@ -1,12 +1,17 @@
package main
import (
"context"
"crypto/tls"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
rdb "git.runcible.io/learning/ratchet/internal/database"
@ -22,17 +27,20 @@ import (
// commit string
// )
func main( ) {
func run( ctx context . Context , w io . Writer , args [ ] string ) error {
// CONFIGURATION
// Parse command line options
addr := flag . String ( "addr" , "0.0.0.0" , "HTTP network address" )
port := flag . String ( "port" , "5001" , "HTTP port" )
logLevel := flag . String ( "logging" , "INFO" , "Logging Level. Valid values [INFO, DEBUG, WARN, ERROR]." )
dbPath := flag . String ( "database" , "./ratchet.db" , "A path to a sqlite3 database" )
certPath := flag . String ( "cert" , "./tls/cert.pem" , "A public cert in .pem format" )
keyPath := flag . String ( "key" , "./tls/key.pem" , "A private key in .pem format" )
flags := flag . NewFlagSet ( args [ 0 ] , flag . ExitOnError )
addr := flags . String ( "addr" , "0.0.0.0" , "HTTP network address" )
port := flags . String ( "port" , "5001" , "HTTP port" )
logLevel := flags . String ( "logging" , "INFO" , "Logging Level. Valid values [INFO, DEBUG, WARN, ERROR]." )
dbPath := flags . String ( "database" , "./ratchet.db" , "A path to a sqlite3 database" )
certPath := flags . String ( "cert" , "./tls/cert.pem" , "A public cert in .pem format" )
keyPath := flags . String ( "key" , "./tls/key.pem" , "A private key in .pem format" )
// must call parse or all values will be the defaults
flag . Parse ( )
if err := flags . Parse ( args [ 1 : ] ) ; err != nil {
return err
}
// DEPENDENCY INJECTION FOR HANDLERS
// Setup Logging
@ -41,17 +49,22 @@ func main() {
db , err := rdb . OpenSqlite3DB ( * dbPath )
if err != nil {
slog . Error ( err . Error ( ) )
os . Exit ( 1 )
return err
}
// Close db connection before exiting main.
defer db . Close ( )
defer func ( ) {
slog . Info ( "Cleaning up database" )
_ , err := db . Exec ( "PRAGMA wal_checkpoint(TRUNCATE)" )
if err != nil {
slog . Error ( fmt . Sprintf ( "Error checkpointing database: %v" , err ) )
}
db . Close ( )
} ( )
//tc, err := server.InitTemplateCache()
tc , err := server . InitFSTemplateCache ( )
if err != nil {
slog . Error ( err . Error ( ) )
os . Exit ( 1 )
return err
}
// SessionManager
@ -126,8 +139,37 @@ func main() {
slog . Info ( fmt . Sprintf ( "Listening on https://%s" , srv . Addr ) )
err = srv . ListenAndServeTLS ( * certPath , * keyPath )
slog . Error ( err . Error ( ) )
os . Exit ( 1 )
go func ( ) {
if err = srv . ListenAndServeTLS ( * certPath , * keyPath ) ; ! errors . Is ( err , http . ErrServerClosed ) {
slog . Error ( err . Error ( ) )
os . Exit ( 1 )
}
slog . Info ( "Stopped serving connections" )
} ( )
// Handle graceful shutdown
sigChan := make ( chan os . Signal , 1 )
signal . Notify ( sigChan , syscall . SIGINT , syscall . SIGTERM )
// Block until signal is recieved
<- sigChan
shutdownCtx , shutdownRelease := context . WithTimeout ( ctx , 10 * time . Second )
defer shutdownRelease ( )
if err := srv . Shutdown ( shutdownCtx ) ; err != nil {
slog . Error ( "Failed to close within context timeout. Forcing server close." )
srv . Close ( )
return err
}
return nil
}
func main ( ) {
ctx := context . Background ( )
if err := run ( ctx , os . Stdout , os . Args ) ; err != nil {
slog . Error ( err . Error ( ) )
os . Exit ( 1 )
}
}