212 lines
6.1 KiB
Go
212 lines
6.1 KiB
Go
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
|
|
}
|