// Created by: Claude // Date: 2026-01-04 // Purpose: Debug utilities for development // Refs: AGENT.md use crate::mesh::types::Event; use quinn::Connection; use tracing::info; /// Dump event details for debugging pub fn dump_event(event: &Event) { info!("━━━━━━━━━━━━━━━━━━━━━━━━"); info!("Event: {}", event.event_type); info!("ID: {}", event.id); info!("From: {} → To: {}", event.from, event.to); info!("Timestamp: {}", event.timestamp); if let Ok(pretty) = serde_json::to_string_pretty(&event.payload) { info!("Payload:\n{}", pretty); } else { info!("Payload: {:?}", event.payload); } info!("━━━━━━━━━━━━━━━━━━━━━━━━"); } /// Dump QUIC connection statistics pub fn dump_quic_stats(connection: &Connection) { let stats = connection.stats(); info!("━━━ QUIC Connection Stats ━━━"); info!("Remote: {}", connection.remote_address()); info!("RTT: {:?}", stats.path.rtt); info!("Congestion window: {} bytes", stats.path.cwnd); info!("Sent: {} bytes ({} datagrams)", stats.udp_tx.bytes, stats.udp_tx.datagrams); info!("Received: {} bytes ({} datagrams)", stats.udp_rx.bytes, stats.udp_rx.datagrams); info!("Lost packets: {}", stats.path.lost_packets); info!("Lost bytes: {}", stats.path.lost_bytes); info!("━━━━━━━━━━━━━━━━━━━━━━━━━━"); } /// Format bytes in human-readable format pub fn format_bytes(bytes: u64) -> String { const KB: u64 = 1024; const MB: u64 = KB * 1024; const GB: u64 = MB * 1024; if bytes >= GB { format!("{:.2} GB", bytes as f64 / GB as f64) } else if bytes >= MB { format!("{:.2} MB", bytes as f64 / MB as f64) } else if bytes >= KB { format!("{:.2} KB", bytes as f64 / KB as f64) } else { format!("{} B", bytes) } } /// Calculate transfer speed pub fn calculate_speed(bytes: u64, duration_secs: f64) -> String { if duration_secs <= 0.0 { return "N/A".to_string(); } let bytes_per_sec = bytes as f64 / duration_secs; format_bytes(bytes_per_sec as u64) + "/s" } /// Dump session token cache status (for debugging P2P) pub fn dump_session_cache_info(session_id: &str, ttl_remaining_secs: i64) { info!("━━━ Session Token Cache ━━━"); info!("Session ID: {}", session_id); if ttl_remaining_secs > 0 { info!("TTL remaining: {} seconds", ttl_remaining_secs); info!("Status: VALID"); } else { info!("TTL remaining: EXPIRED ({} seconds ago)", ttl_remaining_secs.abs()); info!("Status: EXPIRED"); } info!("━━━━━━━━━━━━━━━━━━━━━━━━━━"); } #[cfg(test)] mod tests { use super::*; #[test] fn test_format_bytes() { assert_eq!(format_bytes(512), "512 B"); assert_eq!(format_bytes(1024), "1.00 KB"); assert_eq!(format_bytes(1536), "1.50 KB"); assert_eq!(format_bytes(1024 * 1024), "1.00 MB"); assert_eq!(format_bytes(1024 * 1024 * 1024), "1.00 GB"); } #[test] fn test_calculate_speed() { assert_eq!(calculate_speed(1024 * 1024, 1.0), "1.00 MB/s"); assert_eq!(calculate_speed(1024, 2.0), "512 B/s"); assert_eq!(calculate_speed(1000, 0.0), "N/A"); } }