package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/benya/temporserv/internal/config" "github.com/benya/temporserv/internal/db" "github.com/benya/temporserv/internal/httpapi" "github.com/benya/temporserv/internal/scanner" ) func main() { cfg := config.Load() ctx := context.Background() database, err := db.Open(ctx, cfg) if err != nil { log.Fatalf("database bootstrap failed: %v", err) } defer database.Close() if err := db.Migrate(ctx, database); err != nil { log.Fatalf("database migrations failed: %v", err) } if err := db.Seed(ctx, database, cfg); err != nil { log.Fatalf("database seed failed: %v", err) } scanService := scanner.NewService(database, cfg.MediaRoot, cfg.ArtworkCacheDir) if scanService.HasMediaFiles() { if result, err := scanService.Scan(ctx); err != nil { log.Printf("startup scan failed: %v", err) } else { log.Printf("startup scan completed: artists=%d albums=%d tracks=%d", result.Artists, result.Albums, result.Tracks) } } handler := httpapi.NewRouter(cfg, database, scanService) server := &http.Server{ Addr: cfg.Address(), Handler: handler, ReadHeaderTimeout: 10 * time.Second, } go func() { log.Printf("temporserv listening on %s", cfg.Address()) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server failed: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { log.Printf("shutdown error: %v", err) } }