summaryrefslogtreecommitdiffstats
path: root/src/app/data_harvester/network.rs
blob: 650a68e3d07ec24848af1bd0c440ba514db6d55e (plain)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use std::time::Instant;

#[derive(Default, Clone, Debug)]
/// All units in bits.
pub struct NetworkHarvest {
    pub rx: u64,
    pub tx: u64,
    pub total_rx: u64,
    pub total_tx: u64,
}

impl NetworkHarvest {
    pub fn first_run_cleanup(&mut self) {
        self.rx = 0;
        self.tx = 0;
    }
}

/// Separate Windows implementation required due to https://github.com/heim-rs/heim/issues/26.
#[cfg(target_os = "windows")]
pub async fn get_network_data(
    sys: &sysinfo::System, prev_net_access_time: Instant, prev_net_rx: &mut u64,
    prev_net_tx: &mut u64, curr_time: Instant, actually_get: bool,
    filter: &Option<crate::app::Filter>,
) -> crate::utils::error::Result<Option<NetworkHarvest>> {
    use sysinfo::{NetworkExt, SystemExt};

    if !actually_get {
        return Ok(None);
    }

    let mut total_rx: u64 = 0;
    let mut total_tx: u64 = 0;

    let networks = sys.get_networks();
    for (name, network) in networks {
        let to_keep = if let Some(filter) = filter {
            let mut ret = filter.is_list_ignored;
            for r in &filter.list {
                if r.is_match(&name) {
                    ret = !filter.is_list_ignored;
                    break;
                }
            }
            ret
        } else {
            true
        };

        if to_keep {
            total_rx += network.get_total_received() * 8;
            total_tx += network.get_total_transmitted() * 8;
        }
    }

    let elapsed_time = curr_time.duration_since(prev_net_access_time).as_secs_f64();

    let (rx, tx) = if elapsed_time == 0.0 {
        (0, 0)
    } else {
        (
            ((total_rx.saturating_sub(*prev_net_rx)) as f64 / elapsed_time) as u64,
            ((total_tx.saturating_sub(*prev_net_tx)) as f64 / elapsed_time) as u64,
        )
    };

    *prev_net_rx = total_rx;
    *prev_net_tx = total_tx;
    Ok(Some(NetworkHarvest {
        rx,
        tx,
        total_rx,
        total_tx,
    }))
}

// FIXME: Eventually make it so that this thing also takes individual usage into account, so we can allow for showing per-interface!
#[cfg(not(target_os = "windows"))]
pub async fn get_network_data(
    prev_net_access_time: Instant, prev_net_rx: &mut u64, prev_net_tx: &mut u64,
    curr_time: Instant, actually_get: bool, filter: &Option<crate::app::Filter>,
) -> crate::utils::error::Result<Option<NetworkHarvest>> {
    use futures::StreamExt;

    if !actually_get {
        return Ok(None);
    }

    let io_data = heim::net::io_counters().await?;
    futures::pin_mut!(io_data);
    let mut total_rx: u64 = 0;
    let mut total_tx: u64 = 0;

    while let Some(io) = io_data.next().await {
        if let Ok(io) = io {
            let to_keep = if let Some(filter) = filter {
                if filter.is_list_ignored {
                    let mut ret = true;
                    for r in &filter.list {
                        if r.is_match(&io.interface()) {
                            ret = false;
                            break;
                        }
                    }
                    ret
                } else {
                    true
                }
            } else {
                true
            };

            if to_keep {
                // TODO: Use bytes as the default instead, perhaps?
                // Since you might have to do a double conversion (bytes -> bits -> bytes) in some cases;
                // but if you stick to bytes, then in the bytes, case, you do no conversion, and in the bits case,
                // you only do one conversion...
                total_rx += io.bytes_recv().get::<heim::units::information::bit>();
                total_tx += io.bytes_sent().get::<heim::units::information::bit>();
            }
        }
    }

    let elapsed_time = curr_time.duration_since(prev_net_access_time).as_secs_f64();

    let (rx, tx) = if elapsed_time == 0.0 {
        (0, 0)
    } else {
        (
            ((total_rx.saturating_sub(*prev_net_rx)) as f64 / elapsed_time) as u64,
            ((total_tx.saturating_sub(*prev_net_tx)) as f64 / elapsed_time) as u64,
        )
    };

    *prev_net_rx = total_rx;
    *prev_net_tx = total_tx;
    Ok(Some(NetworkHarvest {
        rx,
        tx,
        total_rx,
        total_tx,
    }))
}