package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) func main() { // Initialiser le logger logger, err := zap.NewProduction() if err != nil { log.Fatalf("Failed to initialize logger: %v", err) } defer logger.Sync() // Initialiser Redis redisClient, err := initRedis("redis://localhost:6379") if err != nil { logger.Error("Failed to initialize Redis", zap.Error(err)) // Continuer sans Redis pour les tests redisClient = nil } // Configurer Gin if os.Getenv("GIN_MODE") == "release" { gin.SetMode(gin.ReleaseMode) } // Créer le router router := gin.New() // Middleware de logging router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { logger.Info("HTTP Request", zap.String("method", param.Method), zap.String("path", param.Path), zap.Int("status", param.StatusCode), zap.Duration("latency", param.Latency), zap.String("client_ip", param.ClientIP), ) return "" })) // Middleware de récupération d'erreurs router.Use(gin.Recovery()) // Middleware CORS router.Use(func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization") c.Header("Access-Control-Max-Age", "86400") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() }) // Routes de test router.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "ok", "timestamp": time.Now(), }) }) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Test endpoint", "redis_connected": redisClient != nil, }) }) // Configuration du serveur port := os.Getenv("PORT") if port == "" { port = "8080" } server := &http.Server{ Addr: ":" + port, Handler: router, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } // Démarrer le serveur en arrière-plan go func() { logger.Info("Starting server", zap.String("port", port)) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { logger.Fatal("Failed to start server", zap.Error(err)) } }() // Attendre un signal d'arrêt quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit logger.Info("Shutting down server...") // Arrêter le serveur gracieusement ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := server.Shutdown(ctx); err != nil { logger.Fatal("Server forced to shutdown", zap.Error(err)) } logger.Info("Server exited") } // initRedis initialise la connexion Redis func initRedis(redisURL string) (*redis.Client, error) { opts, err := redis.ParseURL(redisURL) if err != nil { return nil, err } client := redis.NewClient(opts) // Test de connexion ctx := context.Background() _, err = client.Ping(ctx).Result() if err != nil { return nil, err } return client, nil }