package main import ( "context" "embed" "flag" "fmt" "io/fs" "net/http" "os" "os/signal" "syscall" "git.iwork-ai.com/xdc/iqudo-top1/internal/auth" "git.iwork-ai.com/xdc/iqudo-top1/internal/config" "git.iwork-ai.com/xdc/iqudo-top1/internal/database" "git.iwork-ai.com/xdc/iqudo-top1/internal/httpserver" "git.iwork-ai.com/xdc/iqudo-top1/internal/logger" "git.iwork-ai.com/xdc/iqudo-top1/internal/migration" "go.uber.org/zap" ) //go:embed migrations/*.sql var migrationFiles embed.FS //go:embed web/dist/* var frontendFiles embed.FS func main() { environment := flag.String("env", "", "runtime environment: development, test, prod") configDir := flag.String("config-dir", "configs", "configuration directory") flag.Parse() cfg, err := config.Load(config.LoadOptions{Environment: *environment, ConfigDir: *configDir}) if err != nil { fmt.Fprintf(os.Stderr, "load configuration: %v\n", err) os.Exit(1) } log, err := logger.New(cfg.App.Env, cfg.App.Name) if err != nil { fmt.Fprintf(os.Stderr, "create logger: %v\n", err) os.Exit(1) } defer log.Sync() db, err := database.Open(cfg.Database, log) if err != nil { log.Fatal("connect database", zap.Error(err)) } if err := migration.Run(db, migrationFiles); err != nil { log.Fatal("run database migrations", zap.Error(err)) } if err := auth.Seed(db, cfg.Seed); err != nil { log.Fatal("seed administrator", zap.Error(err)) } frontend, err := fs.Sub(frontendFiles, "web/dist") if err != nil { log.Fatal("load embedded frontend", zap.Error(err)) } authService := auth.NewService(db, cfg.Auth) handler := httpserver.New(db, authService, frontend, log, cfg.App.Env) server := &http.Server{Addr: cfg.Server.Address(), Handler: handler, ReadTimeout: cfg.Server.ReadTimeout, WriteTimeout: cfg.Server.WriteTimeout} go func() { log.Info("server started", zap.String("address", cfg.Server.Address())) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal("server stopped unexpectedly", zap.Error(err)) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop ctx, cancel := context.WithTimeout(context.Background(), cfg.Server.ShutdownTimeout) defer cancel() if err := server.Shutdown(ctx); err != nil { log.Error("graceful shutdown failed", zap.Error(err)) } log.Info("server stopped") }