package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "git.yigid.dev/fyb/tingz/internal/config" "git.yigid.dev/fyb/tingz/internal/db" "git.yigid.dev/fyb/tingz/internal/deploy" httpserver "git.yigid.dev/fyb/tingz/internal/http" "git.yigid.dev/fyb/tingz/internal/logging" "git.yigid.dev/fyb/tingz/internal/user" ) func main() { if err := run(); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } } func run() error { cfg, err := config.LoadConfig() if err != nil { return fmt.Errorf("failed to load config: %w", err) } logger := logging.New(cfg.LogLevel) logger.Info("deployer service starting", "log_level", cfg.LogLevel) database, err := db.OpenDB(cfg.DBPath) if err != nil { return fmt.Errorf("failed to open database: %w", err) } defer database.Close() if err := db.EnsureSchema(database); err != nil { return fmt.Errorf("failed to ensure schema: %w", err) } userMgr := user.NewManager(database, cfg.DeployRoot, cfg.ReleaseRoot) deployMgr := deploy.NewManager(cfg.DeployRoot, cfg.ReleaseRoot, cfg.ReleasesToKeep, logger) router := httpserver.NewRouter(cfg, userMgr, deployMgr, logger) server := &http.Server{ Addr: "0.0.0.0:8080", Handler: router, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } errChan := make(chan error, 1) go func() { logger.Info("server listening", "addr", server.Addr) if cfg.TLSCert != "" && cfg.TLSKey != "" { errChan <- server.ListenAndServeTLS(cfg.TLSCert, cfg.TLSKey) } else { errChan <- server.ListenAndServe() } }() sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) select { case err := <-errChan: return fmt.Errorf("server error: %w", err) case sig := <-sigChan: logger.Info("received shutdown signal", "signal", sig) } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { return fmt.Errorf("server shutdown failed: %w", err) } logger.Info("server stopped gracefully") return nil }