feat: add fallback tunnel status check and improve Windows service command calls

Add fallback to tunnel_status when metrics query fails in current_metrics function, returning zero bytes with actual tunnel state. Update waitForTunnelStatus in frontend to use tunnel_status instead of tunnel_metrics for status polling and refresh metrics separately on success. Change CloseRequested window event handler to call app_handle().exit(0) instead of no-op. Replace "sc" with "sc.exe" in all Windows service command
This commit is contained in:
2026-03-18 09:53:46 +01:00
parent eff143d5b3
commit 3d70655cfa
3 changed files with 40 additions and 20 deletions

View File

@@ -403,11 +403,21 @@ fn current_metrics(app: &AppHandle) -> Result<TunnelMetrics, String> {
let session = session.as_ref().ok_or_else(|| "No active session is available".to_string())?; let session = session.as_ref().ok_or_else(|| "No active session is available".to_string())?;
session.profile_path.clone() session.profile_path.clone()
}; };
tunnel_manager::metrics(app, std::path::Path::new(&profile_path)).map(|metrics| TunnelMetrics { match tunnel_manager::metrics(app, std::path::Path::new(&profile_path)) {
active: metrics.active, Ok(metrics) => Ok(TunnelMetrics {
rx_bytes: metrics.rx_bytes, active: metrics.active,
tx_bytes: metrics.tx_bytes, rx_bytes: metrics.rx_bytes,
}) tx_bytes: metrics.tx_bytes,
}),
Err(_) => {
let active = tunnel_manager::is_active(app, std::path::Path::new(&profile_path))?;
Ok(TunnelMetrics {
active,
rx_bytes: 0,
tx_bytes: 0,
})
}
}
} }
async fn sync_current_session(app: &AppHandle) -> Result<SessionState, String> { async fn sync_current_session(app: &AppHandle) -> Result<SessionState, String> {
@@ -658,7 +668,9 @@ pub fn run() {
Ok(()) Ok(())
}) })
.on_window_event(|window, event| match event { .on_window_event(|window, event| match event {
WindowEvent::CloseRequested { .. } => {} WindowEvent::CloseRequested { .. } => {
window.app_handle().exit(0);
}
WindowEvent::Resized(_) => { WindowEvent::Resized(_) => {
if window.is_minimized().unwrap_or(false) { if window.is_minimized().unwrap_or(false) {
hide_main_window(window); hide_main_window(window);

View File

@@ -88,7 +88,14 @@ export function App() {
setMetrics(value); setMetrics(value);
setConnected(value.active); setConnected(value.active);
} catch { } catch {
setMetrics({ active: false, rxBytes: 0, txBytes: 0 }); try {
const active = await invoke<boolean>("tunnel_status");
setConnected(active);
setMetrics((current) => ({ ...current, active }));
} catch {
setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
setConnected(false);
}
} }
} }
@@ -122,15 +129,16 @@ export function App() {
async function waitForTunnelStatus(expected: boolean) { async function waitForTunnelStatus(expected: boolean) {
for (let attempt = 0; attempt < 8; attempt += 1) { for (let attempt = 0; attempt < 8; attempt += 1) {
try { try {
const value = await invoke<TunnelMetrics>("tunnel_metrics"); const active = await invoke<boolean>("tunnel_status");
setMetrics(value); setConnected(active);
setConnected(value.active); if (active === expected) {
if (value.active === expected) { await refreshTunnelMetrics();
return value.active; return active;
} }
} catch { } catch {
if (!expected) { if (!expected) {
setMetrics({ active: false, rxBytes: 0, txBytes: 0 }); setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
setConnected(false);
return false; return false;
} }
} }
@@ -138,11 +146,11 @@ export function App() {
await new Promise((resolve) => window.setTimeout(resolve, 500)); await new Promise((resolve) => window.setTimeout(resolve, 500));
} }
return invoke<TunnelMetrics>("tunnel_metrics") return invoke<boolean>("tunnel_status")
.then((value) => { .then(async (active) => {
setMetrics(value); setConnected(active);
setConnected(value.active); await refreshTunnelMetrics();
return value.active; return active;
}) })
.catch(() => false); .catch(() => false);
} }

View File

@@ -479,7 +479,7 @@ fn connect_to_service() -> Result<TcpStream, String> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn start_windows_service() -> Result<(), String> { fn start_windows_service() -> Result<(), String> {
let status = Command::new("sc") let status = Command::new("sc.exe")
.arg("start") .arg("start")
.arg(SERVICE_NAME) .arg(SERVICE_NAME)
.creation_flags(CREATE_NO_WINDOW) .creation_flags(CREATE_NO_WINDOW)
@@ -610,7 +610,7 @@ fn tunnel_service_is_active(profile: &Path) -> Result<bool, String> {
{ {
let tunnel_name = tunnel_name(profile)?; let tunnel_name = tunnel_name(profile)?;
let service_name = format!("WireGuardTunnel${}", tunnel_name); let service_name = format!("WireGuardTunnel${}", tunnel_name);
let output = Command::new("sc") let output = Command::new("sc.exe")
.arg("query") .arg("query")
.arg(&service_name) .arg(&service_name)
.creation_flags(CREATE_NO_WINDOW) .creation_flags(CREATE_NO_WINDOW)
@@ -659,7 +659,7 @@ fn describe_windows_tunnel_state(profile: &Path) -> String {
Err(err) => return err, Err(err) => return err,
}; };
let service_name = format!("WireGuardTunnel${}", tunnel_name); let service_name = format!("WireGuardTunnel${}", tunnel_name);
let output = Command::new("sc") let output = Command::new("sc.exe")
.arg("query") .arg("query")
.arg(&service_name) .arg(&service_name)
.creation_flags(CREATE_NO_WINDOW) .creation_flags(CREATE_NO_WINDOW)