1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
mod network_stat;

use std::{
    collections::HashSet,
    hash::{Hash, Hasher},
    io::ErrorKind,
    thread::sleep,
    time::Duration,
};

pub use network_stat::*;

use crate::scanner_rust::{generic_array::typenum::U1024, ScannerAscii, ScannerError};

#[derive(Default, Debug, Clone, Eq)]
pub struct Network {
    pub interface: String,
    pub stat:      NetworkStat,
}

impl Hash for Network {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.interface.hash(state)
    }
}

impl PartialEq for Network {
    #[inline]
    fn eq(&self, other: &Network) -> bool {
        self.interface.eq(&other.interface)
    }
}

/// Get network information by reading the `/proc/net/dev` file.
///
/// ```rust
/// use mprober_lib::network;
///
/// let networks = network::get_networks().unwrap();
///
/// println!("{networks:#?}");
/// ```
pub fn get_networks() -> Result<Vec<Network>, ScannerError> {
    let mut sc: ScannerAscii<_, U1024> = ScannerAscii::scan_path2("/proc/net/dev")?;

    for _ in 0..2 {
        sc.drop_next_line()?.ok_or(ErrorKind::UnexpectedEof)?;
    }

    let mut networks = Vec::with_capacity(1);

    while let Some(interface) = sc.next_until_raw(":")? {
        let interface = unsafe { String::from_utf8_unchecked(interface) };

        let receive_bytes = sc.next_u64()?.ok_or(ErrorKind::UnexpectedEof)?;

        for _ in 0..7 {
            sc.drop_next()?.ok_or(ErrorKind::UnexpectedEof)?;
        }

        let transmit_bytes = sc.next_u64()?.ok_or(ErrorKind::UnexpectedEof)?;

        let stat = NetworkStat {
            receive_bytes,
            transmit_bytes,
        };

        let network = Network {
            interface,
            stat,
        };

        networks.push(network);

        sc.drop_next_line()?.ok_or(ErrorKind::UnexpectedEof)?;
    }

    Ok(networks)
}

/// Get network information by reading the `/proc/net/dev` file and measure the speed within a specific time interval.
///
/// ```rust
/// use std::time::Duration;
///
/// use mprober_lib::network;
///
/// let networks_with_speed =
///     network::get_networks_with_speed(Duration::from_millis(100)).unwrap();
///
/// for (network, network_speed) in networks_with_speed {
///     println!("{}: ", network.interface);
///     println!("    Receive: {:.1} B/s", network_speed.receive);
///     println!("    Transmit: {:.1} B/s", network_speed.transmit);
/// }
/// ```
pub fn get_networks_with_speed(
    interval: Duration,
) -> Result<Vec<(Network, NetworkSpeed)>, ScannerError> {
    let pre_networks = get_networks()?;

    let pre_networks_length = pre_networks.len();

    let mut pre_networks_hashset = HashSet::with_capacity(pre_networks_length);

    for pre_network in pre_networks {
        pre_networks_hashset.insert(pre_network);
    }

    sleep(interval);

    let networks = get_networks()?;

    let mut networks_with_speed = Vec::with_capacity(networks.len().min(pre_networks_length));

    for network in networks {
        if let Some(pre_network) = pre_networks_hashset.get(&network) {
            let network_speed = pre_network.stat.compute_speed(&network.stat, interval);

            networks_with_speed.push((network, network_speed));
        }
    }

    Ok(networks_with_speed)
}