From 932b7cbc33d5c693bfe14700f864dda4f418dcae Mon Sep 17 00:00:00 2001 From: KingKDot Date: Tue, 16 Jun 2026 17:51:41 -0500 Subject: [PATCH] hopefully fix --- Overlord-Client/cmd/agent/session.go | 4 ++-- Overlord-Server/public/assets/remotedesktop.js | 16 ++++++++++++++++ Overlord-Server/public/assets/webcam.js | 18 ++++++++++-------- Overlord-Server/src/server/stale-prune.test.ts | 4 ++-- Overlord-Server/src/server/stale-prune.ts | 1 + .../src/server/ws-console-rd-hvnc.ts | 5 +++++ 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Overlord-Client/cmd/agent/session.go b/Overlord-Client/cmd/agent/session.go index 95eed82..0374ad5 100644 --- a/Overlord-Client/cmd/agent/session.go +++ b/Overlord-Client/cmd/agent/session.go @@ -547,7 +547,7 @@ func runSession(ctx context.Context, cancel context.CancelFunc, conn *websocket. sendCtx, sendCancel := context.WithTimeout(context.Background(), 2*time.Second) defer sendCancel() _ = wire.WriteMsg(sendCtx, conn, di) - conn.Close(websocket.StatusNormalClosure, "bye") + conn.CloseNow() }() identity := config.DeriveIdentity() @@ -747,8 +747,8 @@ func runSession(ctx context.Context, cancel context.CancelFunc, conn *websocket. last := env.LastPong() if !last.IsZero() && time.Since(last) > grace { log.Printf("ping: no pong for %s, forcing reconnect", time.Since(last)) - conn.Close(websocket.StatusGoingAway, "pong timeout") cancel() + conn.CloseNow() return } } diff --git a/Overlord-Server/public/assets/remotedesktop.js b/Overlord-Server/public/assets/remotedesktop.js index 22b205d..2a4c061 100644 --- a/Overlord-Server/public/assets/remotedesktop.js +++ b/Overlord-Server/public/assets/remotedesktop.js @@ -857,6 +857,20 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s setStreamState("connecting", "Connecting"); return; } + if (msg.status === "starting") { + clearOfflineTimer(); + if (desiredStreaming && streamState !== "streaming") { + setStreamState("starting", "Starting stream"); + } + return; + } + if (msg.status === "stopped") { + clearOfflineTimer(); + desiredStreaming = false; + lastFrameAt = 0; + setStreamState("idle", "Stopped"); + return; + } if (msg.status === "online") { clearOfflineTimer(); if (elevationPending) { @@ -1348,10 +1362,12 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s stopBtn.addEventListener("click", function () { if (isRecording()) stopRecording(); desiredStreaming = false; + lastFrameAt = 0; setStreamState("stopping", "Stopping stream"); sendCmd("desktop_stop", {}); disconnectAudio(); stopAllWebrtc(); + setStreamState("idle", "Stopped"); }); if (recordBtn) { recordBtn.addEventListener("click", function () { diff --git a/Overlord-Server/public/assets/webcam.js b/Overlord-Server/public/assets/webcam.js index d1153c4..d6a6cec 100644 --- a/Overlord-Server/public/assets/webcam.js +++ b/Overlord-Server/public/assets/webcam.js @@ -566,7 +566,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s hasRenderedFrame = true; bitmap.close(); updateViewerFps(); - setStreamState("streaming", "Streaming"); + if (desiredStreaming) setStreamState("streaming", "Streaming"); } finally { drawPending = false; } @@ -600,7 +600,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s h264TimestampUs += 66_666; videoDecoder.decode(chunk); updateViewerFps(); - setStreamState("streaming", "Streaming"); + if (desiredStreaming) setStreamState("streaming", "Streaming"); } catch (err) { console.warn("webcam h264 decode failed", err, "payloadBytes=", payload.length); } @@ -698,6 +698,13 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s if (msg.status === "offline") { desiredStreaming = false; setStreamState("offline", msg.reason || "Client offline"); + } else if (msg.status === "starting") { + if (desiredStreaming && streamState !== "streaming") { + setStreamState("starting", "Starting"); + } + } else if (msg.status === "stopped") { + desiredStreaming = false; + setStreamState("idle", "Stopped"); } else if (msg.status === "connecting") { setStreamState("idle", "Ready"); } else if (msg.status === "online") { @@ -790,12 +797,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./shared-ui-s send("webcam_stop"); stopAllWebrtc(); disconnectAudio(); - setStreamState("stopping", "Stopping"); - setTimeout(() => { - if (streamState === "stopping") { - setStreamState("idle", "Stopped"); - } - }, 300); + setStreamState("idle", "Stopped"); }); function stopOnExit() { diff --git a/Overlord-Server/src/server/stale-prune.test.ts b/Overlord-Server/src/server/stale-prune.test.ts index 1e96d80..b831c30 100644 --- a/Overlord-Server/src/server/stale-prune.test.ts +++ b/Overlord-Server/src/server/stale-prune.test.ts @@ -36,7 +36,7 @@ describe("pruneStaleClients", () => { expect(deleted).toEqual([]); }); - test("closes and marks offline stale role=client entries without deleting", () => { + test("closes, marks offline, and deletes stale role=client entries", () => { const clients = new Map(); const staleClient = makeClient("stale-c", Date.now() - 120_000, "client"); clients.set("stale-c", staleClient); @@ -53,7 +53,7 @@ describe("pruneStaleClients", () => { }); expect(offlined).toContain("stale-c"); - expect(deleted).not.toContain("stale-c"); + expect(deleted).toContain("stale-c"); expect((staleClient.ws as any)._calls[0]).toStartWith("close:"); }); diff --git a/Overlord-Server/src/server/stale-prune.ts b/Overlord-Server/src/server/stale-prune.ts index 054e1a7..c93f959 100644 --- a/Overlord-Server/src/server/stale-prune.ts +++ b/Overlord-Server/src/server/stale-prune.ts @@ -20,6 +20,7 @@ export function pruneStaleClients(params: PruneStaleClientsParams): void { if (info.role === "client") { info.ws.close(4000, "stale"); params.setOnlineState(id, false); + params.deleteClient(id); processed += 1; continue; } diff --git a/Overlord-Server/src/server/ws-console-rd-hvnc.ts b/Overlord-Server/src/server/ws-console-rd-hvnc.ts index f844716..2187322 100644 --- a/Overlord-Server/src/server/ws-console-rd-hvnc.ts +++ b/Overlord-Server/src/server/ws-console-rd-hvnc.ts @@ -390,6 +390,7 @@ export function handleRemoteDesktopViewerMessage(ws: ServerWebSocket whepPath: `/api/webrtc/${streamPath}/whep`, }); } + safeSendViewer(ws, { type: "status", status: "starting" }); sendDesktopCommand(target, "desktop_set_fps", { fps: clampDesktopFps(state.maxFps) }); sendDesktopCommand(target, "desktop_start", {}); state.isStreaming = true; @@ -403,6 +404,7 @@ export function handleRemoteDesktopViewerMessage(ws: ServerWebSocket logger.info(`[rd-debug] desktop_start reasserting stale stream client=${clientId} lastFrameAgeMs=${Number.isFinite(lastFrameAgeMs) ? lastFrameAgeMs : -1} state=${JSON.stringify(state)} viewers=${sessionManager.getRdSessionsForClient(clientId).length}`); sendDesktopCommand(target, "desktop_set_fps", { fps: clampDesktopFps(state.maxFps) }); sendDesktopCommand(target, "desktop_start", {}); + safeSendViewer(ws, { type: "status", status: "starting" }); state.isStreaming = true; state.startedAt = Date.now(); rdStreamingState.set(clientId, state); @@ -437,6 +439,7 @@ export function handleRemoteDesktopViewerMessage(ws: ServerWebSocket } else { logger.debug(`[rd] ignoring desktop_stop for client ${clientId} - ${otherViewers.length} other viewer(s) still active`); } + safeSendViewer(ws, { type: "status", status: "stopped" }); break; } case "desktop_record_start": { @@ -994,6 +997,7 @@ export function handleWebcamViewerMessage(ws: ServerWebSocket, raw: whepPath: `/api/webrtc/${streamPath}/whep`, }); } + safeSendViewer(ws, { type: "status", status: "starting" }); sendDesktopCommand(target, "webcam_start", {}); state.isStreaming = true; webcamStreamingState.set(clientId, state); @@ -1019,6 +1023,7 @@ export function handleWebcamViewerMessage(ws: ServerWebSocket, raw: } else { logger.debug(`[webcam] ignoring webcam_stop for client ${clientId} - ${otherWebcamViewers.length} other viewer(s) still active`); } + safeSendViewer(ws, { type: "status", status: "stopped" }); break; } case "webrtc_p2p_offer": {