package websocket import ( "api-service/internal/config" ws "api-service/internal/services/websocket" "fmt" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) // WebSocketHandler menangani koneksi WebSocket type WebSocketHandler struct { hub *ws.Hub config config.WebSocketConfig upgrader websocket.Upgrader monitoringManager *ws.MonitoringManager } // NewWebSocketHandler membuat handler WebSocket baru func NewWebSocketHandler(hub *ws.Hub, config config.WebSocketConfig) *WebSocketHandler { return &WebSocketHandler{ hub: hub, config: config, monitoringManager: ws.NewMonitoringManager(hub), upgrader: websocket.Upgrader{ ReadBufferSize: config.ReadBufferSize, WriteBufferSize: config.WriteBufferSize, CheckOrigin: func(r *http.Request) bool { // Dalam production, implementasikan validasi origin yang proper return true }, }, } } // HandleWebSocket menangani upgrade koneksi ke WebSocket func (h *WebSocketHandler) HandleWebSocket(c *gin.Context) { // Ambil parameter dari query atau header clientID := c.Query("client_id") if clientID == "" { clientID = fmt.Sprintf("client_%d", time.Now().UnixNano()) } staticID := c.Query("static_id") userID := c.Query("user_id") room := c.Query("room") ipAddress := c.ClientIP() // Upgrade koneksi HTTP ke WebSocket conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "Failed to upgrade connection", "details": err.Error(), }) return } // Buat klien WebSocket baru client := ws.NewClient(clientID, staticID, userID, room, ipAddress, conn, h.hub, h.config) // Daftarkan klien ke hub h.hub.RegisterChannel() <- client // Jalankan goroutine untuk membaca dan menulis go client.ReadPump() go client.WritePump() } // GetWebSocketStats mengembalikan statistik WebSocket func (h *WebSocketHandler) GetWebSocketStats(c *gin.Context) { stats := h.hub.GetStats() c.JSON(http.StatusOK, stats) } // TestWebSocketConnection endpoint untuk test koneksi WebSocket func (h *WebSocketHandler) TestWebSocketConnection(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "WebSocket service is running", "status": "active", "endpoint": "/api/v1/ws", "parameters": gin.H{ "client_id": "optional, auto-generated if not provided", "static_id": "optional, for persistent client identification", "user_id": "optional, for user identification", "room": "optional, for room-based messaging", }, "example": "ws://meninjar.dev.rssa.id:8070/api/v1/ws?client_id=test_client&room=test_room", "timestamp": time.Now().Unix(), }) } // GetDetailedStats mengembalikan statistik detail WebSocket func (h *WebSocketHandler) GetDetailedStats(c *gin.Context) { detailedStats := h.monitoringManager.GetDetailedStats() c.JSON(http.StatusOK, gin.H{ "admin_stats": detailedStats, "timestamp": time.Now().Unix(), }) } // DisconnectClient memutuskan koneksi klien tertentu func (h *WebSocketHandler) DisconnectClient(c *gin.Context) { clientID := c.Param("clientId") success := h.monitoringManager.DisconnectClient(clientID) c.JSON(http.StatusOK, gin.H{ "status": "force disconnect attempted", "client_id": clientID, "success": success, "timestamp": time.Now().Unix(), }) } // CleanupInactiveClients membersihkan klien tidak aktif func (h *WebSocketHandler) CleanupInactiveClients(c *gin.Context) { var req struct { InactiveMinutes int `json:"inactive_minutes"` Force bool `json:"force"` } if err := c.ShouldBindJSON(&req); err != nil { req.InactiveMinutes = 10 req.Force = false } cleanedCount := h.monitoringManager.CleanupInactiveClients(time.Duration(req.InactiveMinutes) * time.Minute) c.JSON(http.StatusOK, gin.H{ "status": "admin cleanup completed", "cleaned_clients": cleanedCount, "inactive_minutes": req.InactiveMinutes, "force": req.Force, "timestamp": time.Now().Unix(), }) }