package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/ez-api/ez-api/internal/api" "github.com/ez-api/ez-api/internal/config" "github.com/ez-api/ez-api/internal/model" "github.com/ez-api/ez-api/internal/service" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "gorm.io/driver/postgres" "gorm.io/gorm" ) func main() { // 1. Load Configuration cfg, err := config.Load() if err != nil { log.Fatalf("Failed to load config: %v", err) } // 2. Initialize Redis Client rdb := redis.NewClient(&redis.Options{ Addr: cfg.Redis.Addr, Password: cfg.Redis.Password, DB: cfg.Redis.DB, }) // Verify Redis connection ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := rdb.Ping(ctx).Err(); err != nil { log.Fatalf("Failed to connect to Redis: %v", err) } log.Println("Connected to Redis successfully") // 3. Initialize GORM (PostgreSQL) db, err := gorm.Open(postgres.Open(cfg.Postgres.DSN), &gorm.Config{}) if err != nil { log.Fatalf("Failed to connect to PostgreSQL: %v", err) } sqlDB, err := db.DB() if err != nil { log.Fatalf("Failed to get generic database object: %v", err) } // Verify DB connection if err := sqlDB.Ping(); err != nil { log.Fatalf("Failed to ping PostgreSQL: %v", err) } log.Println("Connected to PostgreSQL successfully") // Auto Migrate if err := db.AutoMigrate(&model.User{}, &model.Provider{}, &model.Key{}, &model.Model{}); err != nil { log.Fatalf("Failed to auto migrate: %v", err) } // 4. Setup Services and Handlers syncService := service.NewSyncService(rdb) handler := api.NewHandler(db, syncService) // 5. Setup Gin Router r := gin.Default() // Health Check Endpoint r.GET("/health", func(c *gin.Context) { c.String(http.StatusOK, "OK") }) // API Routes r.POST("/keys", handler.CreateKey) srv := &http.Server{ Addr: ":" + cfg.Server.Port, Handler: r, } // 6. Start Server with Graceful Shutdown go func() { log.Printf("Starting ez-api on port %s", cfg.Server.Port) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("Server failed: %v", err) } }() // Wait for interrupt signal quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutting down server...") // Shutdown with timeout ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatalf("Server forced to shutdown: %v", err) } log.Println("Server exited properly") }