rs_blocks/blocks/
network.rs

1// Copyright ⓒ 2019-2021 Lewis Belcher
2// Licensed under the MIT license (see LICENSE or <http://opensource.org/licenses/MIT>).
3// All files in the project carrying such notice may not be copied, modified, or
4// distributed except according to those terms
5
6//! # Network block
7//!
8//! Use this block to get network monitoring in the status bar.
9//!
10//! Typical configuration:
11//!
12//! ```toml
13//! [network]
14//! path_to_rx = "/sys/class/net/wlan0/statistics/rx_bytes"
15//! path_to_tx = "/sys/class/net/wlan0/statistics/tx_bytes"
16//! ```
17//!
18//! ## Configuration options
19//!
20//! - `name`: Name of the block (must be unique)
21//! - `period`: Default update period in seconds (extra updates may occur on
22//!    event changes etc)
23//! - `alpha`: Weight for the exponential moving average of value updates
24//! - `path_to_rx`: Path to the file to monitor for network receiving traffic
25//!    (usually something like `/sys/class/net/<DEVICE>/statistics/rx_bytes`
26//!    where `<DEVICE>` is the network device to monitor)
27//! - `path_to_tx`: Path to the file to monitor for network transmission traffic
28//!    (usually something like `/sys/class/net/<DEVICE>/statistics/tx_bytes`
29//!    where `<DEVICE>` is the network device to monitor)
30
31use crate::blocks::{Block, Configure, Message, Sender, ValidatedPath};
32use crate::utils;
33use serde::Deserialize;
34use std::thread;
35
36#[derive(Configure, Deserialize)]
37pub struct Network {
38	#[serde(default = "default_name")]
39	name: String,
40	#[serde(default = "default_period")]
41	period: f32,
42	path_to_rx: ValidatedPath,
43	path_to_tx: ValidatedPath,
44}
45
46fn default_name() -> String {
47	"network".to_string()
48}
49
50fn default_period() -> f32 {
51	1.0
52}
53
54impl Sender for Network {
55	fn add_sender(&self, channel: crossbeam_channel::Sender<Message>) -> anyhow::Result<()> {
56		let name = self.get_name();
57		let rx_file = utils::monitor_file(self.path_to_rx.0.clone(), self.period);
58		let mut tx_file = utils::monitor_file(self.path_to_tx.0.clone(), self.period);
59		let coef = 1.0 / (self.period * 1024.0); // Report in kB
60		let mut rx = Speed::new(coef);
61		let mut tx = Speed::new(coef);
62		let mut first = true;
63		let mut block = Block::new(name.clone(), true);
64
65		thread::spawn(move || {
66			for rx_ in rx_file {
67				rx.push(utils::str_to_f32(&rx_).unwrap());
68				tx.push(utils::str_to_f32(&tx_file.read()).unwrap());
69
70				if first {
71					first = false;
72				} else {
73					block.full_text = Some(format!(
74						"<span foreground='#ccffcc'>\u{f0ab} {:.1}</span> <span foreground='#ffcccc'>\u{f0aa} {:.1}</span>",
75						rx.calc_speed(),
76						tx.calc_speed()
77					));
78					channel.send((name.clone(), block.to_string())).unwrap();
79				}
80			}
81		});
82
83		Ok(())
84	}
85}
86
87struct Speed {
88	curr: f32,
89	prev: f32,
90	coef: f32,
91}
92
93impl Speed {
94	fn new(coef: f32) -> Speed {
95		Speed {
96			curr: 0.0,
97			prev: 0.0,
98			coef,
99		}
100	}
101
102	fn push(&mut self, new: f32) {
103		self.prev = self.curr;
104		self.curr = new;
105	}
106
107	fn calc_speed(&self) -> f32 {
108		(self.curr - self.prev) * self.coef
109	}
110}