Private
Public Access
1
0

Add Docker, Kubernetes configurations, and CI workflows for deployment. Integrate Gin server for API, WebSocket support, and static file hosting. Refactor WebSocket gateway to use Gin router.
Some checks failed
Dynamic Branch Deploy / build-and-deploy (push) Has been cancelled

This commit is contained in:
Sebastian Unterschütz
2026-01-04 15:14:55 +01:00
parent 2fb19d314f
commit 16f683a360
13 changed files with 872 additions and 13 deletions

88
cmd/server/gin_server.go Normal file
View File

@@ -0,0 +1,88 @@
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())
// 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")
// 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)
}

View File

@@ -172,11 +172,11 @@ func main() {
log.Println("✅ Server bereit. Warte auf Spieler...")
// 9. WEBSOCKET-GATEWAY STARTEN (für Browser-Clients)
go StartWebSocketGateway("8080", ec)
// Block forever
select {}
// 9. GIN-SERVER STARTEN (statische Dateien + WebSocket)
router := SetupGinServer(ec, "8080")
if err := router.Run(":8080"); err != nil {
log.Fatal("❌ Gin-Server Fehler:", err)
}
}
func loadServerAssets(w *game.World) {