Files
websocket-qris/internal/handlers/websocket/websocket.go
2025-10-24 12:33:10 +00:00

137 lines
4.0 KiB
Go

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(),
})
}