Skip to main content

nd_300/diagnostics/
traffic_counters.rs

1use serde::Serialize;
2use sysinfo::Networks;
3
4use super::shared_cache::SharedCache;
5
6#[derive(Debug, Clone, Serialize)]
7pub struct TrafficCounter {
8    pub interface: String,
9    pub rx_bytes: u64,
10    pub tx_bytes: u64,
11    pub rx_formatted: String,
12    pub tx_formatted: String,
13    pub total_formatted: String,
14}
15
16pub async fn collect_with_cache(cache: &SharedCache) -> Option<Vec<TrafficCounter>> {
17    if let Some(ref networks) = cache.sysinfo_networks {
18        return collect_from_networks(networks);
19    }
20    collect().await
21}
22
23fn collect_from_networks(networks: &Networks) -> Option<Vec<TrafficCounter>> {
24    let mut counters = Vec::new();
25
26    for (name, data) in networks {
27        let rx = data.total_received();
28        let tx = data.total_transmitted();
29
30        if rx == 0 && tx == 0 {
31            continue;
32        }
33
34        counters.push(TrafficCounter {
35            interface: name.clone(),
36            rx_bytes: rx,
37            tx_bytes: tx,
38            rx_formatted: format_bytes(rx),
39            tx_formatted: format_bytes(tx),
40            total_formatted: format_bytes(rx + tx),
41        });
42    }
43
44    if counters.is_empty() {
45        None
46    } else {
47        Some(counters)
48    }
49}
50
51pub async fn collect() -> Option<Vec<TrafficCounter>> {
52    let networks = Networks::new_with_refreshed_list();
53    let mut counters = Vec::new();
54
55    for (name, data) in &networks {
56        let rx = data.total_received();
57        let tx = data.total_transmitted();
58
59        if rx == 0 && tx == 0 {
60            continue;
61        }
62
63        counters.push(TrafficCounter {
64            interface: name.clone(),
65            rx_bytes: rx,
66            tx_bytes: tx,
67            rx_formatted: format_bytes(rx),
68            tx_formatted: format_bytes(tx),
69            total_formatted: format_bytes(rx + tx),
70        });
71    }
72
73    if counters.is_empty() {
74        None
75    } else {
76        Some(counters)
77    }
78}
79
80fn format_bytes(bytes: u64) -> String {
81    const KB: u64 = 1024;
82    const MB: u64 = 1024 * KB;
83    const GB: u64 = 1024 * MB;
84    const TB: u64 = 1024 * GB;
85
86    if bytes >= TB {
87        format!("{:.2} TB", bytes as f64 / TB as f64)
88    } else if bytes >= GB {
89        format!("{:.2} GB", bytes as f64 / GB as f64)
90    } else if bytes >= MB {
91        format!("{:.1} MB", bytes as f64 / MB as f64)
92    } else if bytes >= KB {
93        format!("{:.1} KB", bytes as f64 / KB as f64)
94    } else {
95        format!("{} B", bytes)
96    }
97}