fix stopping
This commit is contained in:
@@ -250,7 +250,7 @@ type WsLifecycleDeps = {
|
||||
cleanupDesktopAudioViewer: (ws: ServerWebSocket<SocketData>) => void;
|
||||
stopConsoleOnTarget: (target: ClientInfo | undefined, sessionId: string) => void;
|
||||
sendDesktopCommand: (target: ClientInfo | undefined, commandType: string, payload: Record<string, unknown>) => void;
|
||||
sendHVNCCommand: (target: ClientInfo, commandType: string, payload: Record<string, unknown>) => void;
|
||||
sendHVNCCommand: (target: ClientInfo | undefined, commandType: string, payload: Record<string, unknown>) => void;
|
||||
notifyConsoleClosed: (clientId: string, reason: string) => void;
|
||||
clearPendingNotificationScreenshots: (clientId: string) => void;
|
||||
clearClientPluginState: (clientId: string) => void;
|
||||
|
||||
@@ -5,8 +5,11 @@ import * as sessionManager from "../sessions/sessionManager";
|
||||
import type { SocketData } from "../sessions/types";
|
||||
import type { ClientInfo } from "../types";
|
||||
import {
|
||||
handleHVNCViewerMessage,
|
||||
handleHVNCViewerOpen,
|
||||
handleRemoteDesktopViewerMessage,
|
||||
handleRemoteDesktopViewerOpen,
|
||||
hvncStreamingState,
|
||||
rdStreamingState,
|
||||
} from "./ws-console-rd-hvnc";
|
||||
|
||||
@@ -70,7 +73,11 @@ afterEach(() => {
|
||||
for (const session of sessionManager.getRdSessionsForClient(clientId)) {
|
||||
sessionManager.deleteRdSession(session.id);
|
||||
}
|
||||
for (const session of sessionManager.getHvncSessionsForClient(clientId)) {
|
||||
sessionManager.deleteHvncSession(session.id);
|
||||
}
|
||||
rdStreamingState.delete(clientId);
|
||||
hvncStreamingState.delete(clientId);
|
||||
clientManager.deleteClient(clientId);
|
||||
}
|
||||
clientIdsToCleanup.clear();
|
||||
@@ -150,3 +157,29 @@ describe("remote desktop viewer control", () => {
|
||||
expect(rdStreamingState.get(clientId)?.isStreaming).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hvnc viewer control", () => {
|
||||
test("forwards hvnc_stop even when server stream state is stale", () => {
|
||||
const clientId = `hvnc-stale-stop-${Date.now().toString(36)}`;
|
||||
const { agentWs } = createClient(clientId);
|
||||
const viewer = createMockWs({ role: "hvnc_viewer", clientId });
|
||||
|
||||
handleHVNCViewerOpen(viewer as any);
|
||||
hvncStreamingState.set(clientId, {
|
||||
isStreaming: false,
|
||||
virtualMode: true,
|
||||
display: 0,
|
||||
quality: 90,
|
||||
codec: "",
|
||||
maxFps: 120,
|
||||
lastFps: 0,
|
||||
});
|
||||
|
||||
handleHVNCViewerMessage(viewer as any, JSON.stringify({ type: "hvnc_stop" }));
|
||||
|
||||
const commands = agentCommands(agentWs);
|
||||
expect(commands.filter((msg) => msg.commandType === "hvnc_stop")).toHaveLength(1);
|
||||
expect(commands.filter((msg) => msg.commandType === "webrtc_stop")).toHaveLength(1);
|
||||
expect(hvncStreamingState.get(clientId)?.isStreaming).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1179,13 +1179,11 @@ export function handleHVNCViewerMessage(ws: ServerWebSocket<SocketData>, raw: st
|
||||
const otherHvncViewers = sessionManager.getHvncSessionsForClient(clientId)
|
||||
.filter(s => s.id !== ws.data.sessionId);
|
||||
if (otherHvncViewers.length === 0) {
|
||||
if (state.isStreaming) {
|
||||
sendHVNCCommand(target, "hvnc_stop", {});
|
||||
sendHVNCCommand(target, "webrtc_stop", { kind: "hvnc" });
|
||||
state.isStreaming = false;
|
||||
hvncStreamingState.set(clientId, state);
|
||||
logger.debug(`[hvnc] stopped streaming for client ${clientId}`);
|
||||
}
|
||||
sendHVNCCommand(target, "hvnc_stop", {});
|
||||
sendHVNCCommand(target, "webrtc_stop", { kind: "hvnc" });
|
||||
state.isStreaming = false;
|
||||
hvncStreamingState.set(clientId, state);
|
||||
logger.debug(`[hvnc] stopped streaming for client ${clientId}`);
|
||||
} else {
|
||||
logger.debug(`[hvnc] ignoring hvnc_stop for client ${clientId} - ${otherHvncViewers.length} other viewer(s) still active`);
|
||||
}
|
||||
@@ -1408,8 +1406,20 @@ export function handleHVNCViewerMessage(ws: ServerWebSocket<SocketData>, raw: st
|
||||
}
|
||||
}
|
||||
|
||||
export function sendHVNCCommand(target: ClientInfo, commandType: string, payload: any) {
|
||||
target.ws.send(encodeMessage({ type: "command", commandType: commandType as any, id: uuidv4(), payload }));
|
||||
export function sendHVNCCommand(target: ClientInfo | undefined, commandType: string, payload: any) {
|
||||
if (!target) {
|
||||
logger.warn(`[hvnc] send command skipped, target missing command=${commandType}`);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
logger.debug(`[hvnc] send command command=${commandType} client=${target.id} payload=${JSON.stringify(payload || {})}`);
|
||||
target.ws.send(encodeMessage({ type: "command", commandType: commandType as any, id: uuidv4(), payload }));
|
||||
metrics.recordCommand(commandType);
|
||||
return true;
|
||||
} catch (err) {
|
||||
logger.error("[hvnc] send command failed", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(globalThis as any).__hvncBroadcast = (clientId: string, bytes: Uint8Array, header?: any): boolean => {
|
||||
|
||||
Reference in New Issue
Block a user