package main import ( "context" "flag" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" "zeromesh/internal/config" "zeromesh/internal/controller" "zeromesh/internal/database" "zeromesh/internal/router" ) func main() { cfgPath := flag.String("config", "config.yaml", "config file path") flag.Parse() cfg, err := config.Load(*cfgPath) if err != nil { slog.Error("load config", "err", err) os.Exit(1) } logLevel := new(slog.LevelVar) switch cfg.Logging.Level { case "debug": logLevel.Set(slog.LevelDebug) case "warn": logLevel.Set(slog.LevelWarn) case "error": logLevel.Set(slog.LevelError) default: logLevel.Set(slog.LevelInfo) } opts := &slog.HandlerOptions{Level: logLevel} var handler slog.Handler if cfg.Logging.Format == "json" { handler = slog.NewJSONHandler(os.Stderr, opts) } else { handler = slog.NewTextHandler(os.Stderr, opts) } logger := slog.New(handler) slog.SetDefault(logger) db, err := database.Init(&cfg.Database) if err != nil { slog.Error("init database", "err", err) os.Exit(1) } ctr, err := controller.New(cfg, db, logger) if err != nil { slog.Error("init controller", "err", err) os.Exit(1) } if err := ctr.Start(); err != nil { slog.Error("start controller", "err", err) os.Exit(1) } gin.SetMode(gin.ReleaseMode) r := router.Setup(cfg, db) srv := &http.Server{ Addr: cfg.Server.Addr(), Handler: r, } go func() { slog.Info("http server listening", "addr", srv.Addr) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { slog.Error("http serve", "err", err) } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit slog.Info("shutting down...") ctr.Stop() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { slog.Error("server shutdown", "err", err) } }