package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/rs/zerolog/log" "github.com/treytartt/mycrib-api/internal/config" "github.com/treytartt/mycrib-api/internal/database" "github.com/treytartt/mycrib-api/internal/router" "github.com/treytartt/mycrib-api/internal/services" "github.com/treytartt/mycrib-api/pkg/utils" ) func main() { // Load configuration cfg, err := config.Load() if err != nil { fmt.Printf("Failed to load configuration: %v\n", err) os.Exit(1) } // Initialize logger utils.InitLogger(cfg.Server.Debug) log.Info(). Bool("debug", cfg.Server.Debug). Int("port", cfg.Server.Port). Msg("Starting MyCrib API server") // Connect to database db, err := database.Connect(&cfg.Database, cfg.Server.Debug) if err != nil { log.Fatal().Err(err).Msg("Failed to connect to database") } defer database.Close() // Run database migrations if err := database.Migrate(); err != nil { log.Fatal().Err(err).Msg("Failed to run database migrations") } // Connect to Redis cache, err := services.NewCacheService(&cfg.Redis) if err != nil { log.Fatal().Err(err).Msg("Failed to connect to Redis") } defer cache.Close() // Initialize email service var emailService *services.EmailService if cfg.Email.Host != "" && cfg.Email.User != "" { emailService = services.NewEmailService(&cfg.Email) log.Info(). Str("host", cfg.Email.Host). Msg("Email service initialized") } else { log.Warn().Msg("Email service not configured - emails will not be sent") } // Setup router with dependencies deps := &router.Dependencies{ DB: db, Cache: cache, Config: cfg, EmailService: emailService, } r := router.SetupRouter(deps) // Create HTTP server srv := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.Server.Port), Handler: r, ReadTimeout: 30 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, } // Start server in goroutine go func() { log.Info(). Str("addr", srv.Addr). Msg("HTTP server listening") if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal().Err(err).Msg("Failed to start HTTP server") } }() // Wait for interrupt signal for graceful shutdown quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Info().Msg("Shutting down server...") // Graceful shutdown with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal().Err(err).Msg("Server forced to shutdown") } log.Info().Msg("Server exited") }