package stats import ( "sync" "time" ) // ComponentStats represents statistics for a specific component type ComponentStats struct { Component string `json:"component"` Timestamp time.Time `json:"timestamp"` Queries int64 `json:"queries"` Errors int64 `json:"errors"` ResponseTime float64 `json:"response_time_ms"` Connections int64 `json:"connections"` BytesServed int64 `json:"bytes_served"` Metadata map[string]interface{} `json:"metadata"` } // DHTStats represents DHT-specific statistics type DHTStats struct { QueriesSent int64 `json:"queries_sent"` QueriesReceived int64 `json:"queries_received"` NodesInTable int `json:"nodes_in_routing_table"` StoredPeers int `json:"stored_peers"` AnnouncesSent int64 `json:"announces_sent"` PeersSeen int64 `json:"peers_seen"` LastAnnounce time.Time `json:"last_announce"` ErrorRate float64 `json:"error_rate"` } // TrackerStats represents tracker-specific statistics type TrackerStats struct { ActiveTorrents int `json:"active_torrents"` TotalPeers int `json:"total_peers"` AnnouncesPerMin float64 `json:"announces_per_minute"` ScrapeRequests int64 `json:"scrape_requests"` AverageSwarmSize float64 `json:"average_swarm_size"` LastActivity time.Time `json:"last_activity"` } // GatewayStats represents gateway-specific statistics type GatewayStats struct { UploadsPerHour float64 `json:"uploads_per_hour"` DownloadsPerHour float64 `json:"downloads_per_hour"` BandwidthUsed int64 `json:"bandwidth_used_bytes"` ActiveUploads int `json:"active_uploads"` ActiveDownloads int `json:"active_downloads"` CacheHitRate float64 `json:"cache_hit_rate"` AverageFileSize int64 `json:"average_file_size"` } // WebSocketStats represents WebSocket tracker statistics type WebSocketStats struct { ActiveConnections int `json:"active_connections"` WebRTCPeers int `json:"webrtc_peers"` MessagesPerSec float64 `json:"messages_per_second"` ConnectionErrors int64 `json:"connection_errors"` PeerExchanges int64 `json:"peer_exchanges"` AverageLatency float64 `json:"average_latency_ms"` } // SystemStats represents overall system performance type SystemStats struct { CPUUsage float64 `json:"cpu_usage_percent"` MemoryUsage int64 `json:"memory_usage_bytes"` GoroutineCount int `json:"goroutine_count"` ResponseTime float64 `json:"avg_response_time_ms"` RequestsPerSec float64 `json:"requests_per_second"` } // BandwidthStats represents bandwidth usage tracking type BandwidthStats struct { TorrentHash string `json:"torrent_hash"` BytesServed int64 `json:"bytes_served"` BytesFromPeers int64 `json:"bytes_from_peers"` P2POffloadPercent float64 `json:"p2p_offload_percent"` PeerCount int `json:"peer_count"` Timestamp time.Time `json:"timestamp"` } // TimeSeriesPoint represents a single point in time-series data type TimeSeriesPoint struct { Timestamp time.Time `json:"timestamp"` Value float64 `json:"value"` Component string `json:"component"` Metric string `json:"metric"` } // StatsCollector manages collection and aggregation of statistics type StatsCollector struct { mutex sync.RWMutex dhtStats *DHTStats trackerStats *TrackerStats gatewayStats *GatewayStats wsStats *WebSocketStats systemStats *SystemStats bandwidthMap map[string]*BandwidthStats // Rate tracking requestCounts map[string]int64 errorCounts map[string]int64 lastReset time.Time // Performance tracking responseTimes map[string][]float64 activeConns int64 } // NewStatsCollector creates a new statistics collector func NewStatsCollector() *StatsCollector { return &StatsCollector{ dhtStats: &DHTStats{}, trackerStats: &TrackerStats{}, gatewayStats: &GatewayStats{}, wsStats: &WebSocketStats{}, systemStats: &SystemStats{}, bandwidthMap: make(map[string]*BandwidthStats), requestCounts: make(map[string]int64), errorCounts: make(map[string]int64), responseTimes: make(map[string][]float64), lastReset: time.Now(), } } // RecordRequest increments request count for a component func (sc *StatsCollector) RecordRequest(component string) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.requestCounts[component]++ } // RecordError increments error count for a component func (sc *StatsCollector) RecordError(component string) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.errorCounts[component]++ } // RecordResponseTime records response time for a component func (sc *StatsCollector) RecordResponseTime(component string, duration time.Duration) { sc.mutex.Lock() defer sc.mutex.Unlock() ms := float64(duration.Nanoseconds()) / 1e6 if sc.responseTimes[component] == nil { sc.responseTimes[component] = make([]float64, 0, 100) } sc.responseTimes[component] = append(sc.responseTimes[component], ms) // Keep only last 100 measurements if len(sc.responseTimes[component]) > 100 { sc.responseTimes[component] = sc.responseTimes[component][1:] } } // RecordBandwidth records bandwidth usage for a torrent func (sc *StatsCollector) RecordBandwidth(torrentHash string, bytesServed, bytesFromPeers int64, peerCount int) { sc.mutex.Lock() defer sc.mutex.Unlock() var p2pOffload float64 if bytesServed > 0 { p2pOffload = float64(bytesFromPeers) / float64(bytesServed) * 100 } sc.bandwidthMap[torrentHash] = &BandwidthStats{ TorrentHash: torrentHash, BytesServed: bytesServed, BytesFromPeers: bytesFromPeers, P2POffloadPercent: p2pOffload, PeerCount: peerCount, Timestamp: time.Now(), } } // GetAverageResponseTime calculates average response time for a component func (sc *StatsCollector) GetAverageResponseTime(component string) float64 { sc.mutex.RLock() defer sc.mutex.RUnlock() times := sc.responseTimes[component] if len(times) == 0 { return 0 } var sum float64 for _, t := range times { sum += t } return sum / float64(len(times)) } // GetRequestRate calculates requests per second for a component func (sc *StatsCollector) GetRequestRate(component string) float64 { sc.mutex.RLock() defer sc.mutex.RUnlock() duration := time.Since(sc.lastReset).Seconds() if duration == 0 { return 0 } return float64(sc.requestCounts[component]) / duration } // GetErrorRate calculates error rate percentage for a component func (sc *StatsCollector) GetErrorRate(component string) float64 { sc.mutex.RLock() defer sc.mutex.RUnlock() requests := sc.requestCounts[component] if requests == 0 { return 0 } return float64(sc.errorCounts[component]) / float64(requests) * 100 } // ResetCounters resets rate-based counters (called periodically) func (sc *StatsCollector) ResetCounters() { sc.mutex.Lock() defer sc.mutex.Unlock() // Reset counters but keep running totals for rates sc.requestCounts = make(map[string]int64) sc.errorCounts = make(map[string]int64) sc.lastReset = time.Now() } // UpdateDHTStats updates DHT statistics func (sc *StatsCollector) UpdateDHTStats(stats *DHTStats) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.dhtStats = stats } // UpdateTrackerStats updates tracker statistics func (sc *StatsCollector) UpdateTrackerStats(stats *TrackerStats) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.trackerStats = stats } // UpdateGatewayStats updates gateway statistics func (sc *StatsCollector) UpdateGatewayStats(stats *GatewayStats) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.gatewayStats = stats } // UpdateWebSocketStats updates WebSocket statistics func (sc *StatsCollector) UpdateWebSocketStats(stats *WebSocketStats) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.wsStats = stats } // UpdateSystemStats updates system statistics func (sc *StatsCollector) UpdateSystemStats(stats *SystemStats) { sc.mutex.Lock() defer sc.mutex.Unlock() sc.systemStats = stats } // GetSnapshot returns a complete snapshot of current statistics func (sc *StatsCollector) GetSnapshot() map[string]interface{} { sc.mutex.RLock() defer sc.mutex.RUnlock() return map[string]interface{}{ "timestamp": time.Now().Format(time.RFC3339), "dht": sc.dhtStats, "tracker": sc.trackerStats, "gateway": sc.gatewayStats, "websocket": sc.wsStats, "system": sc.systemStats, "bandwidth": sc.bandwidthMap, } }