package main import ( "context" "fmt" "io/fs" "log" "net/http" "os/signal" "syscall" "time" hwlab "git.georgsen.dk/hwlab" "git.georgsen.dk/hwlab/internal/api" "git.georgsen.dk/hwlab/internal/config" "git.georgsen.dk/hwlab/internal/queue" ) func main() { cfg, err := config.Load() if err != nil { log.Fatalf("config: %v", err) } staticFS, err := fs.Sub(hwlab.StaticFiles, "web/dist") if err != nil { log.Fatalf("embed: %v", err) } // Context for graceful shutdown ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() // Start write-ahead queue worker (non-fatal if DragonFlyDB unavailable) waq, err := queue.NewWAQ(cfg.DragonflyURL) if err != nil { log.Printf("WARNING: WAQ unavailable (%v) — NetBox operations will not be queued during downtime", err) } else { retryInterval := time.Duration(cfg.WAQRetryIntervalSeconds) * time.Second go waq.RunWorker(ctx, queue.NoOpHandler, cfg.WAQMaxAttempts, retryInterval) defer waq.Close() log.Printf("WAQ worker started") } router := api.NewRouter(staticFS) addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) log.Printf("HWLab starting on %s", addr) srv := &http.Server{Addr: addr, Handler: router} go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server: %v", err) } }() // Wait for shutdown signal <-ctx.Done() log.Println("Shutting down...") shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("server shutdown: %v", err) } log.Println("Shutdown complete") }