144 lines
3.1 KiB
Go
144 lines
3.1 KiB
Go
|
|
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
|
||
|
|
}
|