use std::error::Error; use std::result::Result; use std::time::Instant; #[derive(Debug)] pub struct NetworkInfo { pub interfaces: Option>, pub rx_rate: Option, pub tx_rate: Option, } #[derive(Debug)] pub struct NetworkMonitor { prev_rx: u64, prev_tx: u64, last_update: Instant, } impl Default for NetworkMonitor { fn default() -> Self { Self::new() } } impl NetworkMonitor { pub fn new() -> Self { Self { prev_rx: 0, prev_tx: 0, last_update: Instant::now(), } } pub fn update_usage(&mut self) -> Result<(f64, f64), Box> { let (current_rx, current_tx) = get_network_bytes()?; let elapsed = self.last_update.elapsed().as_secs_f64(); self.last_update = Instant::now(); let rx_rate = if current_rx >= self.prev_rx { (current_rx - self.prev_rx) as f64 / elapsed } else { 0.0 }; let tx_rate = if current_tx >= self.prev_tx { (current_tx - self.prev_tx) as f64 / elapsed } else { 0.0 }; self.prev_rx = current_rx; self.prev_tx = current_tx; Ok((rx_rate, tx_rate)) } } pub async fn get_network_info(monitor: &mut NetworkMonitor) -> Result> { let (rx_rate, tx_rate) = monitor.update_usage()?; Ok(NetworkInfo { interfaces: Some(get_network_interfaces()), rx_rate: Some(rx_rate), tx_rate: Some(tx_rate), }) } fn get_network_bytes() -> Result<(u64, u64), Box> { #[cfg(target_os = "windows")] { use std::ptr::null_mut; use winapi::shared::ifmib::MIB_IFTABLE; use winapi::um::iphlpapi::GetIfTable; unsafe { // Erste Abfrage zur Bestimmung der benötigten Puffergröße let mut buffer_size = 0u32; if GetIfTable(null_mut(), &mut buffer_size, 0) != winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER { return Err( anyhow::anyhow!("Failed to get buffer size for network interfaces").into(), ); } // Puffer allozieren let mut buffer = vec![0u8; buffer_size as usize]; let if_table = buffer.as_mut_ptr() as *mut MIB_IFTABLE; // Tatsächliche Daten abrufen if GetIfTable(if_table, &mut buffer_size, 0) != 0 { return Err(anyhow::anyhow!("Failed to get network interface table").into()); } // Daten auswerten let mut rx_total = 0u64; let mut tx_total = 0u64; for i in 0..(*if_table).dwNumEntries { let row = &*((*if_table).table.as_ptr().offset(i as isize)); rx_total += row.dwInOctets as u64; tx_total += row.dwOutOctets as u64; } if rx_total == 0 && tx_total == 0 { Err(anyhow::anyhow!("No network data available").into()) } else { Ok((rx_total, tx_total)) } } } #[cfg(target_os = "linux")] { use std::fs; let mut rx_total = 0u64; let mut tx_total = 0u64; if let Ok(dir) = fs::read_dir("/sys/class/net") { for entry in dir.flatten() { let iface = entry.file_name(); let iface_name = iface.to_string_lossy(); // Ignoriere virtuelle Interfaces if !iface_name.starts_with("lo") && !iface_name.starts_with("virbr") { if let (Ok(rx), Ok(tx)) = ( fs::read_to_string(entry.path().join("statistics/rx_bytes")), fs::read_to_string(entry.path().join("statistics/tx_bytes")), ) { rx_total += rx.trim().parse::().unwrap_or(0); tx_total += tx.trim().parse::().unwrap_or(0); } } } } if rx_total == 0 && tx_total == 0 { return Err(anyhow::anyhow!("No network data available").into()); } else { return Ok((rx_total, tx_total)); } } #[cfg(not(any(target_os = "windows", target_os = "linux")))] Err("No network data available for this OS".into()) } fn get_network_interfaces() -> Vec { #[cfg(target_os = "windows")] { use std::ffi::CStr; use std::ptr::null_mut; use winapi::shared::ifmib::MIB_IFTABLE; use winapi::um::iphlpapi::GetIfTable; unsafe { let mut buffer_size = 0u32; if GetIfTable(null_mut(), &mut buffer_size, 0) != winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER { return vec![]; } let mut buffer = vec![0u8; buffer_size as usize]; let if_table = buffer.as_mut_ptr() as *mut MIB_IFTABLE; if GetIfTable(if_table, &mut buffer_size, 0) != 0 { return vec![]; } (0..(*if_table).dwNumEntries) .map(|i| { let row = &*((*if_table).table.as_ptr().offset(i as isize)); let descr = CStr::from_ptr(row.bDescr.as_ptr() as *const i8) .to_string_lossy() .into_owned(); descr.trim().to_string() }) .collect() } } #[cfg(target_os = "linux")] { use std::fs; let mut interfaces = vec![]; if let Ok(dir) = fs::read_dir("/sys/class/net") { for entry in dir.flatten() { let iface = entry.file_name(); interfaces.push(iface.to_string_lossy().to_string()); } } interfaces } #[cfg(not(any(target_os = "windows", target_os = "linux")))] vec![] }