package main import ( "log" "net/http" "github.com/gin-gonic/gin" "github.com/nats-io/nats.go" ) // SetupGinServer erstellt und konfiguriert den Gin-Server func SetupGinServer(ec *nats.EncodedConn, port string) *gin.Engine { // Production mode für bessere Performance gin.SetMode(gin.ReleaseMode) r := gin.Default() // Logging Middleware (bereits in gin.Default()) // Custom Logger für bessere Übersicht r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { return "🌐 " + param.TimeStamp.Format("2006-01-02 15:04:05") + " | " + param.Method + " | " + string(rune(param.StatusCode)) + " | " + param.Latency.String() + " | " + param.ClientIP + " | " + param.Path + "\n" })) // Recovery Middleware r.Use(gin.Recovery()) // Cache Control Middleware für statische Assets r.Use(func(c *gin.Context) { path := c.Request.URL.Path // Assets (Bilder, Audio, etc.) - 1 Jahr cachen if len(path) > 7 && path[:8] == "/assets/" { c.Header("Cache-Control", "public, max-age=31536000, immutable") } // WASM und JS Dateien - nur cachen wenn mit ?v= Parameter if (path == "/main.wasm" || path == "/game.js" || path == "/wasm_exec.js") && c.Query("v") != "" { c.Header("Cache-Control", "public, max-age=31536000, immutable") } // CSS und Hintergrundbild - 1 Tag cachen if path == "/style.css" || path == "/background.jpg" { c.Header("Cache-Control", "public, max-age=86400") } // HTML - immer neu laden (enthält BUILD_VERSION für Cache-Busting der JS/WASM) if path == "/" || path == "/index.html" { c.Header("Cache-Control", "no-cache") } c.Next() }) // Health Check Endpoint r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{ "status": "ok", "service": "EscapeFromTeacher", "version": "1.0.0", }) }) // Metrics Endpoint (optional für Kubernetes) r.GET("/metrics", func(c *gin.Context) { mu.RLock() roomCount := len(rooms) playerCount := len(playerSessions) mu.RUnlock() c.JSON(200, gin.H{ "rooms": roomCount, "players": playerCount, }) }) // WebSocket Endpoint r.GET("/ws", func(c *gin.Context) { handleWebSocketGin(c.Writer, c.Request, ec) }) // Static Files - Serve Web Client r.Static("/assets", "./cmd/client/web/assets") r.StaticFile("/", "./cmd/client/web/index.html") r.StaticFile("/index.html", "./cmd/client/web/index.html") r.StaticFile("/game.js", "./cmd/client/web/game.js") r.StaticFile("/style.css", "./cmd/client/web/style.css") r.StaticFile("/wasm_exec.js", "./cmd/client/web/wasm_exec.js") r.StaticFile("/main.wasm", "./cmd/client/web/main.wasm") r.StaticFile("/background.jpg", "./cmd/client/web/background.jpg") // Admin Panel RegisterAdminRoutes(r) // 404 Handler r.NoRoute(func(c *gin.Context) { c.JSON(404, gin.H{ "error": "Route not found", }) }) log.Printf("🚀 Gin-Server konfiguriert auf Port %s", port) log.Printf("📁 Statische Dateien: ./cmd/client/web/") log.Printf("🌐 WebSocket Endpoint: /ws") log.Printf("❤️ Health Check: /health") return r } // handleWebSocketGin verwaltet WebSocket-Verbindungen über Gin func handleWebSocketGin(w http.ResponseWriter, r *http.Request, ec *nats.EncodedConn) { // Verwende die handleWebSocket Funktion aus websocket_gateway.go handleWebSocket(w, r, ec) }