feat: add fallback to wg show command for transfer metrics when dump command fails
Add read_transfer_totals_from_show function to parse transfer statistics from wg show output as fallback when wg show dump command fails. Add parse_human_wireguard_bytes helper to convert human-readable byte values (B, KiB, MiB, GiB, TiB) to u64. Update read_transfer_totals to call fallback instead of returning error when dump command fails.
This commit is contained in:
@@ -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::<f64>().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<PathBuf, String> {
|
||||
let candidates = [
|
||||
|
||||
Reference in New Issue
Block a user