From 5f567b43203a4396318d1ee8c142715e42967591 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Fri, 22 May 2026 08:52:46 +0200 Subject: [PATCH] fix(client): report runtime errors on disconnect The Windows client sends a best-effort disconnect control message after the runtime loop exits. That message previously always said `client shutting down`, even when the loop ended because TAP I/O, relay event handling, or relay-route verification failed. Preserve the returned error, but include its chain in the disconnect message so the relay log records why the client left during manual MVP testing. Clean exits still report the original shutdown text. Test Plan: - cargo fmt --check - cargo test -p lanparty-client-win - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check - git diff --cached --check Refs: MVP Windows client diagnostics --- crates/lanparty-client-win/src/main.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/lanparty-client-win/src/main.rs b/crates/lanparty-client-win/src/main.rs index 744e936..970f55b 100644 --- a/crates/lanparty-client-win/src/main.rs +++ b/crates/lanparty-client-win/src/main.rs @@ -212,13 +212,21 @@ async fn main() -> Result<()> { let _ = config.tap_instance_id; #[cfg(not(windows))] let run_result = run_client(&session).await; - session.shutdown("client shutting down").await; + let shutdown_message = client_shutdown_message(&run_result); + session.shutdown(&shutdown_message).await; #[cfg(windows)] drop(relay_route_pin); run_result } +fn client_shutdown_message(run_result: &Result<()>) -> String { + match run_result { + Ok(()) => "client shutting down".to_owned(), + Err(error) => format!("client shutting down after error: {error:#}"), + } +} + #[cfg(windows)] fn ensure_supported_platform() -> Result<()> { Ok(()) @@ -1274,6 +1282,20 @@ mod tests { assert!(error.to_string().contains("does not match tunnel identity")); } + #[test] + fn reports_runtime_errors_in_shutdown_message() { + assert_eq!( + client_shutdown_message(&Ok(())), + "client shutting down".to_owned() + ); + + let error = anyhow::anyhow!("route pin changed").context("bridge stopped"); + assert_eq!( + client_shutdown_message(&Err(error)), + "client shutting down after error: bridge stopped: route pin changed".to_owned() + ); + } + #[test] fn formats_client_diagnostics_status_line() { let diagnostics = ClientDiagnostics::new(