diff --git a/client/public/version.js b/client/public/version.js index 36a1176..8252c1d 100644 --- a/client/public/version.js +++ b/client/public/version.js @@ -1,5 +1,5 @@ // Maintainer-controlled web client version. // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) -window.CHGRID_WEB_VERSION = "2026.02.22 R166"; +window.CHGRID_WEB_VERSION = "2026.02.22 R167"; // Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid. window.CHGRID_TIME_ZONE = "America/Detroit"; diff --git a/client/src/main.ts b/client/src/main.ts index 07ad8e1..588e039 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -78,7 +78,7 @@ const MIC_CALIBRATION_ACTIVE_RMS_THRESHOLD = 0.003; const MIC_INPUT_GAIN_SCALE_MULTIPLIER = 2; const MIC_INPUT_GAIN_STEP = 0.05; const HEARTBEAT_INTERVAL_MS = 10_000; -const RECONNECT_DELAY_MS = 2_000; +const RECONNECT_DELAY_MS = 5_000; const RECONNECT_MAX_ATTEMPTS = 3; declare global { @@ -515,9 +515,14 @@ function handleSignalingStatus(message: string): void { return; } if (message === 'Disconnected.' && state.running && !reconnectInFlight) { + pushChatMessage('Disconnected from server. Reconnecting...'); void reconnectAfterSocketClose(); return; } + if (message === 'Disconnected.') { + pushChatMessage('Disconnected from server.'); + return; + } pushChatMessage(message); } @@ -1140,7 +1145,7 @@ async function reconnectWithRetry(reason: 'heartbeat' | 'socketClose'): Promise< return; } if (attempt < RECONNECT_MAX_ATTEMPTS) { - pushChatMessage(`Reconnect attempt ${attempt} failed. Retrying...`); + pushChatMessage(`Reconnect attempt ${attempt} failed. Retrying in 5 seconds...`); } } pushChatMessage('Reconnect failed after 3 attempts. Press Connect to retry.'); @@ -1256,7 +1261,9 @@ async function onSignalingMessage(message: IncomingMessage): Promise { if (message.type === 'welcome') { const incomingInstanceId = String(message.serverInfo?.instanceId ?? '').trim() || null; const incomingVersion = String(message.serverInfo?.version ?? '').trim() || 'unknown'; - connectedAnnouncement = `Connected. Version ${incomingVersion}.`; + connectedAnnouncement = reconnectInFlight + ? `Reconnected to server. Version ${incomingVersion}.` + : `Connected to server. Version ${incomingVersion}.`; if ( !reloadScheduledForVersionMismatch && APP_VERSION && @@ -1278,13 +1285,13 @@ async function onSignalingMessage(message: IncomingMessage): Promise { startHeartbeat(); } await onAppMessage(message); - if (connectedAnnouncement) { - pushChatMessage(connectedAnnouncement); - } if (restartAnnouncement) { pushChatMessage(restartAnnouncement); audio.sfxUiConfirm(); } + if (connectedAnnouncement) { + pushChatMessage(connectedAnnouncement); + } } /** Toggles local microphone track mute state. */ diff --git a/docs/protocol-notes.md b/docs/protocol-notes.md index 4620baa..77410e0 100644 --- a/docs/protocol-notes.md +++ b/docs/protocol-notes.md @@ -63,7 +63,8 @@ This is a behavior guide for packet semantics beyond raw schemas. - Heartbeat pings use negative `clientSentAt` ids and are internal (not user-visible ping status). - If websocket close is observed unexpectedly, client starts reconnect flow. - If a heartbeat `pong` is missed for one interval (10 seconds), client also starts reconnect flow. -- Reconnect flow waits 2 seconds and retries up to 3 times before stopping. +- Reconnect flow waits 5 seconds and retries up to 3 times before stopping. - After reconnect, if `welcome.serverInfo.instanceId` changed, client announces `Server restarted.` -- Client emits `Connected. Version .` after each `welcome`. +- Client emits `Connected to server. Version .` on initial `welcome` and + `Reconnected to server. Version .` after reconnect. - If `welcome.serverInfo.version` differs from running client version, client auto-reloads. diff --git a/docs/runtime-flow.md b/docs/runtime-flow.md index b7e449a..22ed750 100644 --- a/docs/runtime-flow.md +++ b/docs/runtime-flow.md @@ -50,7 +50,7 @@ Core incoming message effects: - If websocket closes unexpectedly, client starts reconnect flow immediately. - While running, client also sends heartbeat `ping` every 10 seconds (fallback for silent half-open cases). - If one heartbeat `pong` is missed (10-second interval), client starts reconnect flow. -- Reconnect flow waits 2 seconds and retries up to 3 times. +- Reconnect flow waits 5 seconds and retries up to 3 times. - If reconnect lands on a different `welcome.serverInfo.instanceId`, client announces server restart. - Connect/reconnect status message is emitted from `welcome` and includes server version.