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
// Copyright ⓒ 2019-2020 Lewis Belcher
// Licensed under the MIT license (see LICENSE or <http://opensource.org/licenses/MIT>).
// All files in the project carrying such notice may not be copied, modified, or
// distributed except according to those terms

use crate::blocks::{Block, Configure, Message, Sender};
use crate::utils;
use serde::Deserialize;
use std::thread;

#[derive(Deserialize)]
pub struct Network {
	#[serde(default = "default_name")]
	name: String,
	#[serde(default = "default_period")]
	period: f32,
	device: String,
	rx_file: Option<String>,
	tx_file: Option<String>,
}

fn default_name() -> String {
	"network".to_string()
}

fn default_period() -> f32 {
	1.0
}

fn get_network_file(device: &str, direction: &str) -> String {
	format!("/sys/class/net/{}/statistics/{}_bytes", device, direction)
}

impl Configure for Network {
	fn post_deserialise(mut instance: Self) -> Self
	where
		Self: Sized,
	{
		instance.rx_file = Some(get_network_file(&instance.device, "rx"));
		instance.tx_file = Some(get_network_file(&instance.device, "tx"));
		instance
	}

	fn get_name(&self) -> String {
		self.name.clone()
	}
}

impl Sender for Network {
	fn add_sender(&self, channel: crossbeam_channel::Sender<Message>) {
		let name = self.get_name();
		let rx_file = utils::monitor_file(self.rx_file.as_ref().unwrap().clone(), self.period);
		let mut tx_file = utils::monitor_file(self.tx_file.as_ref().unwrap().clone(), self.period);
		let coef = 1.0 / (self.period * 1024.0); // Report in kB
		let mut rx = Speed::new(coef);
		let mut tx = Speed::new(coef);
		let mut first = true;
		let mut block = Block::new(name.clone(), true);

		thread::spawn(move || {
			for rx_ in rx_file {
				rx.push(utils::str_to_f32(&rx_).unwrap());
				tx.push(utils::str_to_f32(&tx_file.read()).unwrap());

				if first {
					first = false;
				} else {
					block.full_text = Some(format!(
						"<span foreground='#ccffcc'>\u{f0ab} {:.1}</span> <span foreground='#ffcccc'>\u{f0aa} {:.1}</span>",
						rx.calc_speed(),
						tx.calc_speed()
					));
					channel.send((name.clone(), block.to_string())).unwrap();
				}
			}
		});
	}
}

struct Speed {
	curr: f32,
	prev: f32,
	coef: f32,
}

impl Speed {
	fn new(coef: f32) -> Speed {
		Speed {
			curr: 0.0,
			prev: 0.0,
			coef,
		}
	}

	fn push(&mut self, new: f32) {
		self.prev = self.curr;
		self.curr = new;
	}

	fn calc_speed(&self) -> f32 {
		(self.curr - self.prev) * self.coef
	}
}