From 6310864b0be3caf7d0474b38f85df71c5a7272dd Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Sat, 28 Mar 2026 15:15:47 +0400 Subject: [PATCH] fix: client sends Hangup before disconnect, relay handles timeouts gracefully Client: sends SignalMessage::Hangup(Normal) before closing in all modes (send-tone, file mode, silence mode) so the relay knows the session ended. Relay: downgrades "timed out" / "reset" / "closed" recv errors from ERROR to INFO since these are normal disconnect scenarios. Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/wzp-client/src/cli.rs | 13 ++++++++++--- crates/wzp-relay/src/room.rs | 7 ++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/wzp-client/src/cli.rs b/crates/wzp-client/src/cli.rs index 85d5d26..6ab3451 100644 --- a/crates/wzp-client/src/cli.rs +++ b/crates/wzp-client/src/cli.rs @@ -359,6 +359,10 @@ async fn run_silence(transport: Arc) -> anyhow::R } info!(total_source, total_repair, total_bytes, "done — closing"); + let hangup = wzp_proto::SignalMessage::Hangup { + reason: wzp_proto::HangupReason::Normal, + }; + transport.send_signal(&hangup).await.ok(); transport.close().await?; Ok(()) } @@ -505,14 +509,17 @@ async fn run_file_mode( // Wait for send to finish (or ctrl+c in recv) let _ = send_handle.await; - // If send finished but recv is still going, give it a moment then stop + // Send Hangup signal so the relay knows we're done + let hangup = wzp_proto::SignalMessage::Hangup { + reason: wzp_proto::HangupReason::Normal, + }; + transport.send_signal(&hangup).await.ok(); + let all_pcm = if record_file.is_some() { - // Wait a bit for remaining packets after sender finishes tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; transport.close().await?; recv_handle.await.unwrap_or_default() } else { - // No recording — just close and exit transport.close().await?; recv_handle.abort(); Vec::new() diff --git a/crates/wzp-relay/src/room.rs b/crates/wzp-relay/src/room.rs index d80997b..6a2e08c 100644 --- a/crates/wzp-relay/src/room.rs +++ b/crates/wzp-relay/src/room.rs @@ -281,7 +281,12 @@ async fn run_participant_plain( break; } Err(e) => { - error!(%addr, participant = participant_id, "recv error: {e}"); + let msg = e.to_string(); + if msg.contains("timed out") || msg.contains("reset") || msg.contains("closed") { + info!(%addr, participant = participant_id, "connection closed: {e}"); + } else { + error!(%addr, participant = participant_id, "recv error: {e}"); + } break; } };