commit 83357007b021e2da29e69dcb2dd4e05cad87e1fc Author: ddidderr Date: Wed Dec 4 18:24:02 2024 +0100 initial commit (ugly but works): linkspeed diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a9430af --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "linkspeed" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..039ba63 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "linkspeed" +version = "0.1.0" +edition = "2024" +rust-version = "1.85" + +[dependencies] diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b010586 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,85 @@ +use std::{ + env, + fs::File, + io::{self, Read, Seek, SeekFrom}, + thread::sleep, + time::{Duration, Instant}, +}; + +struct LinkSpeed { + rx: File, + tx: File, + rx_bytes: u64, + tx_bytes: u64, + time: Instant, +} + +impl LinkSpeed { + pub fn new(dev: String) -> io::Result { + let rx_bytes_file = File::open(format!("/sys/class/net/{dev}/statistics/rx_bytes"))?; + let tx_bytes_file = File::open(format!("/sys/class/net/{dev}/statistics/tx_bytes"))?; + + Ok(Self { + rx: rx_bytes_file, + tx: tx_bytes_file, + rx_bytes: 0, + tx_bytes: 0, + time: Instant::now(), + }) + } + + fn read_bytes(file: &mut File) -> io::Result { + file.seek(SeekFrom::Start(0))?; + let mut buf = String::new(); + file.read_to_string(&mut buf)?; + Ok(buf.trim().parse().unwrap_or(0)) + } + + fn update(&mut self) -> io::Result<(u64, u64)> { + let rx_bytes = Self::read_bytes(&mut self.rx)?; + let tx_bytes = Self::read_bytes(&mut self.tx)?; + + let mut rx_diff = rx_bytes - self.rx_bytes; + let mut tx_diff = tx_bytes - self.tx_bytes; + + if self.rx_bytes == 0 { + self.rx_bytes = rx_bytes; + rx_diff = 0; + } + + if self.tx_bytes == 0 { + self.tx_bytes = tx_bytes; + tx_diff = 0; + } + + self.rx_bytes = rx_bytes; + self.tx_bytes = tx_bytes; + + Ok((rx_diff, tx_diff)) + } + + pub fn get_measurement(&mut self) -> (f64, f64) { + let elapsed = self.time.elapsed().as_secs_f64(); + let (rx, tx) = self.update().unwrap(); + let rx_speed = rx as f64 / elapsed; + let tx_speed = tx as f64 / elapsed; + self.time = Instant::now(); + (rx_speed, tx_speed) + } +} + +fn main() { + let netdev_name = env::args().nth(1).expect("No network device provided"); + + let mut link_speed = LinkSpeed::new(netdev_name).expect("Failed to create LinkSpeed object"); + + loop { + let (rx_speed, tx_speed) = link_speed.get_measurement(); + println!( + "RX: {:.0} MBit/s, TX: {:.0} MBit/s", + rx_speed / 1024.0 / 1024.0 * 8.0, + tx_speed / 1024.0 / 1024.0 * 8.0 + ); + sleep(Duration::from_millis(1000)); + } +}