diff --git a/desktop-client/tunnel-helper/src/main.rs b/desktop-client/tunnel-helper/src/main.rs index 87ce51a..8a8d84b 100644 --- a/desktop-client/tunnel-helper/src/main.rs +++ b/desktop-client/tunnel-helper/src/main.rs @@ -712,7 +712,7 @@ fn read_transfer_totals(profile: &Path) -> Result<(u64, u64), String> { .map_err(|err| format!("Unable to query tunnel transfer counters: {err}"))?; if !output.status.success() { - return Err("Unable to read WireGuard transfer counters.".into()); + return read_transfer_totals_from_show(tunnel_name); } let stdout = String::from_utf8_lossy(&output.stdout); @@ -732,6 +732,66 @@ fn read_transfer_totals(profile: &Path) -> Result<(u64, u64), String> { Ok((rx_bytes, tx_bytes)) } +fn read_transfer_totals_from_show(tunnel_name: &str) -> Result<(u64, u64), String> { + let mut command = Command::new(find_wg_cli()?); + command.arg("show").arg(tunnel_name); + #[cfg(target_os = "windows")] + command.creation_flags(CREATE_NO_WINDOW); + + let output = command + .output() + .map_err(|err| format!("Unable to query tunnel transfer text: {err}"))?; + + if !output.status.success() { + return Err("Unable to read WireGuard transfer counters.".into()); + } + + let stdout = String::from_utf8_lossy(&output.stdout); + let mut rx_bytes = 0_u64; + let mut tx_bytes = 0_u64; + + for line in stdout.lines() { + let trimmed = line.trim(); + if let Some(rest) = trimmed.strip_prefix("transfer:") { + let parts: Vec<&str> = rest.split(',').collect(); + if let Some(received) = parts.first() { + rx_bytes = rx_bytes.saturating_add(parse_human_wireguard_bytes(received)); + } + if let Some(sent) = parts.get(1) { + tx_bytes = tx_bytes.saturating_add(parse_human_wireguard_bytes(sent)); + } + } + } + + Ok((rx_bytes, tx_bytes)) +} + +fn parse_human_wireguard_bytes(value: &str) -> u64 { + let cleaned = value + .replace("received", "") + .replace("sent", "") + .trim() + .to_string(); + let mut parts = cleaned.split_whitespace(); + let amount = parts + .next() + .map(|raw| raw.replace(',', ".")) + .and_then(|raw| raw.parse::().ok()) + .unwrap_or(0.0); + let unit = parts.next().unwrap_or("B"); + + let multiplier = match unit { + "B" => 1.0, + "KiB" => 1024.0, + "MiB" => 1024.0 * 1024.0, + "GiB" => 1024.0 * 1024.0 * 1024.0, + "TiB" => 1024.0 * 1024.0 * 1024.0 * 1024.0, + _ => 1.0, + }; + + (amount * multiplier) as u64 +} + #[cfg(target_os = "windows")] fn find_wg_cli() -> Result { let candidates = [