server with basic hot reload

This commit is contained in:
2025-11-30 10:09:53 +02:00
parent f1ed3c977a
commit 44e92bcfef
14 changed files with 700 additions and 18 deletions

View File

@@ -14,4 +14,4 @@ var rootCmd = &cobra.Command{
func Execute() error {
return rootCmd.Execute()
}
}

View File

@@ -1,36 +1,149 @@
package cmd
import (
"fmt"
"log/slog"
"net"
"net/http"
"time"
application "git.oblat.lv/alex/triggerssmith/internal/app"
"git.oblat.lv/alex/triggerssmith/internal/config"
"github.com/spf13/cobra"
)
var opts = struct {
ConfigPath *string
Debug *bool
Debug *bool
}{}
// simple middleware for request logging
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
slog.Info("HTTP request",
slog.String("method", r.Method),
slog.String("path", r.URL.Path),
slog.String("remote", r.RemoteAddr),
)
next.ServeHTTP(w, r)
slog.Debug("HTTP request finished",
slog.String("method", r.Method),
slog.String("path", r.URL.Path),
slog.Duration("latency", time.Since(start)),
)
})
}
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Start the server",
Run: func(cmd *cobra.Command, args []string) {
// defer func() {
// if r := recover(); r != nil {
// slog.Error("Application panicked", slog.Any("error", r))
// }
// }()
// configure logger
if *opts.Debug {
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelDebug})))
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelDebug, AddSource: true})))
} else {
slog.SetDefault(slog.New(slog.NewTextHandler(cmd.OutOrStdout(), &slog.HandlerOptions{Level: slog.LevelInfo})))
}
slog.Debug("Starting server")
// load config
slog.Debug("Reading configuration", slog.String("path", *opts.ConfigPath))
config, err := config.LoadConfig(*opts.ConfigPath)
cfg, err := config.LoadConfig(*opts.ConfigPath)
if err != nil {
slog.Error("Failed to load configuration", slog.String("path", *opts.ConfigPath), slog.String("error", err.Error()))
return
}
slog.Debug("Configuration loaded", slog.Any("config", config))
slog.Info("Server started", slog.Int("port", config.Server.Port), slog.String("address", config.Server.Addr))
slog.Debug("Configuration loaded", slog.Any("config", cfg))
// init app
app, err := application.NewApp()
if err != application.ErrNilPointerWarn && err != nil {
slog.Error("Failed to create app instance", slog.String("error", err.Error()))
return
}
app.LoadConfiguration(cfg)
/*
// setup handlers
mux := http.NewServeMux()
// static files
staticPath := cfg.Server.StaticFilesPath
slog.Debug("Setting up static file server", slog.String("path", staticPath))
fs := http.FileServer(http.Dir(staticPath))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
handler := loggingMiddleware(mux)
*/
// start server
/*addr := fmt.Sprintf("%s:%d", cfg.Server.Addr, cfg.Server.Port)
slog.Debug("Binding listener", slog.String("address", addr))
ln, err := net.Listen("tcp", addr)
if err != nil {
slog.Error("Failed to start listener", slog.String("address", addr), slog.String("error", err.Error()))
return
}
srv := &http.Server{
Addr: addr,
Handler: handler,
}
slog.Info("Server started", slog.String("address", addr))
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
slog.Error("HTTP server stopped with error", slog.String("error", err.Error()))
}*/
server := app.Server()
mux := http.NewServeMux()
// static files
staticPath := cfg.Server.StaticFilesPath
slog.Debug("Setting up static file server", slog.String("path", staticPath))
fs := http.FileServer(http.Dir(staticPath))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
handler := loggingMiddleware(mux)
server.SetHandler(handler)
server.Init()
var addr = net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))
slog.Debug("Binding listener", slog.String("address", addr))
err = server.Start(addr)
if err != nil {
slog.Error("Failed to start server", slog.String("error", err.Error()))
return
} else {
slog.Info("Server started", slog.String("address", net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))))
}
for true {
fmt.Scanln()
if err := config.ReloadConfig(cfg); err != nil {
slog.Error("Failed to reload configuration", slog.String("error", err.Error()))
} else {
slog.Info("Configuration reloaded", slog.Any("config", cfg))
var addr = net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))
err = server.Reload(addr)
if err != nil {
slog.Error("Failed to restart server with new configuration", slog.String("error", err.Error()))
} else {
slog.Info("Server restarted with new configuration", slog.String("address", net.JoinHostPort(cfg.Server.Addr, fmt.Sprintf("%d", cfg.Server.Port))))
}
}
}
},
}