package websocket import ( "fmt" "time" ) // DetailedStats menyimpan statistik detail WebSocket type DetailedStats struct { ConnectedClients int `json:"connected_clients"` UniqueIPs int `json:"unique_ips"` StaticClients int `json:"static_clients"` ActiveRooms int `json:"active_rooms"` IPDistribution map[string]int `json:"ip_distribution"` RoomDistribution map[string]int `json:"room_distribution"` MessageQueueSize int `json:"message_queue_size"` QueueWorkers int `json:"queue_workers"` Uptime time.Duration `json:"uptime_seconds"` Timestamp int64 `json:"timestamp"` } // ClientInfo menyimpan informasi klien type ClientInfo struct { ID string `json:"id"` StaticID string `json:"static_id"` IPAddress string `json:"ip_address"` UserID string `json:"user_id"` Room string `json:"room"` ConnectedAt time.Time `json:"connected_at"` LastPing time.Time `json:"last_ping"` LastPong time.Time `json:"last_pong"` IsActive bool `json:"is_active"` } // MonitoringData menyimpan data monitoring lengkap type MonitoringData struct { Stats DetailedStats `json:"stats"` RecentActivity []ActivityLog `json:"recent_activity"` SystemHealth map[string]interface{} `json:"system_health"` Performance PerformanceMetrics `json:"performance"` } // PerformanceMetrics menyimpan metrik performa type PerformanceMetrics struct { MessagesPerSecond float64 `json:"messages_per_second"` AverageLatency float64 `json:"average_latency_ms"` ErrorRate float64 `json:"error_rate_percent"` MemoryUsage int64 `json:"memory_usage_bytes"` } // MonitoringManager mengelola monitoring WebSocket type MonitoringManager struct { hub *Hub } // NewMonitoringManager membuat manajer monitoring baru func NewMonitoringManager(hub *Hub) *MonitoringManager { return &MonitoringManager{hub: hub} } // GetDetailedStats mengembalikan statistik detail func (m *MonitoringManager) GetDetailedStats() DetailedStats { m.hub.mu.RLock() defer m.hub.mu.RUnlock() // Hitung distribusi IP ipDistribution := make(map[string]int) for ip, clients := range m.hub.clientsByIP { ipDistribution[ip] = len(clients) } // Hitung distribusi ruangan roomDistribution := make(map[string]int) for room, clients := range m.hub.rooms { roomDistribution[room] = len(clients) } return DetailedStats{ ConnectedClients: len(m.hub.clients), UniqueIPs: len(m.hub.clientsByIP), StaticClients: len(m.hub.clientsByStatic), ActiveRooms: len(m.hub.rooms), IPDistribution: ipDistribution, RoomDistribution: roomDistribution, MessageQueueSize: len(m.hub.messageQueue), QueueWorkers: m.hub.config.QueueWorkers, Uptime: time.Since(m.hub.startTime), Timestamp: time.Now().Unix(), } } // GetAllClients mengembalikan semua klien yang terhubung func (m *MonitoringManager) GetAllClients() []ClientInfo { m.hub.mu.RLock() defer m.hub.mu.RUnlock() var clients []ClientInfo for client := range m.hub.clients { clientInfo := ClientInfo{ ID: client.ID, StaticID: client.StaticID, IPAddress: client.IPAddress, UserID: client.UserID, Room: client.Room, ConnectedAt: client.connectedAt, LastPing: client.lastPing, LastPong: client.lastPong, IsActive: client.isClientActive(), } clients = append(clients, clientInfo) } return clients } // GetMonitoringData mengembalikan data monitoring lengkap func (m *MonitoringManager) GetMonitoringData() MonitoringData { stats := m.GetDetailedStats() m.hub.activityMu.RLock() recentActivity := make([]ActivityLog, 0) // Dapatkan 100 aktivitas terakhir start := len(m.hub.activityLog) - 100 if start < 0 { start = 0 } for i := start; i < len(m.hub.activityLog); i++ { recentActivity = append(recentActivity, m.hub.activityLog[i]) } m.hub.activityMu.RUnlock() // Dapatkan kesehatan sistem dari layanan database systemHealth := make(map[string]interface{}) if m.hub.dbService != nil { systemHealth["databases"] = m.hub.dbService.Health() systemHealth["available_dbs"] = m.hub.dbService.ListDBs() } systemHealth["websocket_status"] = "healthy" systemHealth["uptime_seconds"] = time.Since(m.hub.startTime).Seconds() // Hitung metrik performa uptime := time.Since(m.hub.startTime) var messagesPerSecond float64 var errorRate float64 if uptime.Seconds() > 0 { messagesPerSecond = float64(m.hub.messageCount) / uptime.Seconds() } if m.hub.messageCount > 0 { errorRate = (float64(m.hub.errorCount) / float64(m.hub.messageCount)) * 100 } performance := PerformanceMetrics{ MessagesPerSecond: messagesPerSecond, AverageLatency: 2.5, // Nilai mock - implementasi pelacakan latensi aktual ErrorRate: errorRate, MemoryUsage: 0, // Nilai mock - implementasi pelacakan memori aktual } return MonitoringData{ Stats: stats, RecentActivity: recentActivity, SystemHealth: systemHealth, Performance: performance, } } // CleanupInactiveClients membersihkan klien tidak aktif func (m *MonitoringManager) CleanupInactiveClients(inactiveTimeout time.Duration) int { m.hub.mu.RLock() var inactiveClients []*Client cutoff := time.Now().Add(-inactiveTimeout) for client := range m.hub.clients { if client.lastPing.Before(cutoff) { inactiveClients = append(inactiveClients, client) } } m.hub.mu.RUnlock() // Putuskan koneksi klien tidak aktif for _, client := range inactiveClients { m.hub.logActivity("cleanup_disconnect", client.ID, fmt.Sprintf("Inactive for %v", time.Since(client.lastPing))) client.cancel() client.Conn.Close() } return len(inactiveClients) } // DisconnectClient memutuskan koneksi klien tertentu func (m *MonitoringManager) DisconnectClient(clientID string) bool { m.hub.mu.RLock() client, exists := m.hub.clientsByID[clientID] m.hub.mu.RUnlock() if !exists { return false } // Log aktivitas m.hub.logActivity("force_disconnect", clientID, "Client disconnected by admin") // Batalkan context dan tutup koneksi client.cancel() client.Conn.Close() return true }