feat: add fallback to wg show transfer parsing when dump command fails on Windows
Add read_windows_metrics_from_show function that parses human-readable transfer output from wg show command when wg show dump fails. Add parse_human_wireguard_bytes helper to convert human-readable byte values (B, KiB, MiB, GiB, TiB) to u64. Update direct_windows_metrics to fall back to transfer parsing instead of returning zero metrics when dump command fails.
This commit is contained in:
@@ -136,11 +136,7 @@ fn direct_windows_metrics(profile_path: &Path) -> Result<TunnelMetrics, String>
|
|||||||
.map_err(|err| format!("Unable to query WireGuard counters: {err}"))?;
|
.map_err(|err| format!("Unable to query WireGuard counters: {err}"))?;
|
||||||
|
|
||||||
if !wg_output.status.success() {
|
if !wg_output.status.success() {
|
||||||
return Ok(TunnelMetrics {
|
return read_windows_metrics_from_show(tunnel_name);
|
||||||
active: true,
|
|
||||||
rx_bytes: 0,
|
|
||||||
tx_bytes: 0,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let stdout = String::from_utf8_lossy(&wg_output.stdout);
|
let stdout = String::from_utf8_lossy(&wg_output.stdout);
|
||||||
@@ -163,6 +159,77 @@ fn direct_windows_metrics(profile_path: &Path) -> Result<TunnelMetrics, String>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn read_windows_metrics_from_show(tunnel_name: &str) -> Result<TunnelMetrics, String> {
|
||||||
|
let wg = find_windows_wg()?;
|
||||||
|
let mut command = Command::new(wg);
|
||||||
|
command
|
||||||
|
.arg("show")
|
||||||
|
.arg(tunnel_name)
|
||||||
|
.creation_flags(CREATE_NO_WINDOW);
|
||||||
|
let output = command
|
||||||
|
.output()
|
||||||
|
.map_err(|err| format!("Unable to query WireGuard transfer text: {err}"))?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Ok(TunnelMetrics {
|
||||||
|
active: true,
|
||||||
|
rx_bytes: 0,
|
||||||
|
tx_bytes: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = parse_human_wireguard_bytes(received);
|
||||||
|
}
|
||||||
|
if let Some(sent) = parts.get(1) {
|
||||||
|
tx_bytes = parse_human_wireguard_bytes(sent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(TunnelMetrics {
|
||||||
|
active: true,
|
||||||
|
rx_bytes,
|
||||||
|
tx_bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
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")]
|
#[cfg(target_os = "windows")]
|
||||||
fn find_windows_wg() -> Result<PathBuf, String> {
|
fn find_windows_wg() -> Result<PathBuf, String> {
|
||||||
let candidates = [
|
let candidates = [
|
||||||
|
|||||||
Reference in New Issue
Block a user