fix(signaling): make protocol mismatch terminal

This commit is contained in:
AAA committed 2026-08-19 21:11:54 +08:00
1 parent 9dc6d906c3
commit 7621f2766e
3 files changed
+67 -54

No files matched your search

+3 -1
View File
@@ -203,7 +203,9 @@ export class SignalingClient {
this.events.onTerminated(
event.reason === "Session replaced"
? "此页面的会话已被另一个标签页接管"
: "信令会话已终止,请刷新后重试",
: event.code === INVALID_MESSAGE_CLOSE_CODE
? PROTOCOL_REFRESH_MESSAGE
: "信令会话已终止,请刷新后重试",
);
}
});
+6 -6
View File
@@ -503,12 +503,12 @@ export const serverMessageSchema = z.union([
...viewerQualityEvidenceWindowShape,
})
.strict()
.refine(freezeFitsEvidenceWindow, {
message: "Viewer freeze duration exceeds its evidence window",
}),
z
.object({
type: z.literal("host-status"),
.refine(freezeFitsEvidenceWindow, {
message: "Viewer freeze duration exceeds its evidence window",
}),
z
.object({
type: z.literal("host-status"),
online: z.boolean(),
})
.strict(),
+58 -47
View File
@@ -224,57 +224,68 @@ describe("client signaling recovery policy", () => {
viewerPeerIds: [],
iceConfig: { iceServers: [] },
}),
])("terminates once when an old server uses an incompatible protocol", (payload) => {
const sockets: FakeWebSocket[] = [];
class FakeWebSocket extends EventTarget {
static readonly CLOSING = 2;
readyState = 1;
readonly send = vi.fn();
readonly close = vi.fn();
])(
"terminates once when an old server uses an incompatible protocol",
(payload) => {
const sockets: FakeWebSocket[] = [];
class FakeWebSocket extends EventTarget {
static readonly CLOSING = 2;
readyState = 1;
readonly send = vi.fn();
readonly close = vi.fn();
constructor(readonly url: string) {
super();
sockets.push(this);
constructor(readonly url: string) {
super();
sockets.push(this);
}
}
}
vi.stubGlobal("WebSocket", FakeWebSocket);
vi.stubGlobal("window", {
location: new URL("https://share.test/r/123456789012"),
setTimeout,
clearTimeout,
});
const onTerminated = vi.fn();
const signal = new SignalingClient(
{
roomId: "123456789012",
role: "viewer",
clientId: "viewer-client",
},
{
onMessage: () => undefined,
onStatus: () => undefined,
onTerminated,
onAccessRequired: () => undefined,
},
);
vi.stubGlobal("WebSocket", FakeWebSocket);
vi.stubGlobal("window", {
location: new URL("https://share.test/r/123456789012"),
setTimeout,
clearTimeout,
});
const onTerminated = vi.fn();
const signal = new SignalingClient(
{
roomId: "123456789012",
role: "viewer",
clientId: "viewer-client",
},
{
onMessage: () => undefined,
onStatus: () => undefined,
onTerminated,
onAccessRequired: () => undefined,
},
);
signal.start();
sockets[0]!.dispatchEvent(new Event("open"));
expect(JSON.parse(String(sockets[0]!.send.mock.calls[0]![0]))).toMatchObject({
type: "authenticate",
protocol: "screener-v1",
});
const message = new Event("message");
Object.defineProperty(message, "data", { value: payload });
sockets[0]!.dispatchEvent(message);
signal.start();
sockets[0]!.dispatchEvent(new Event("open"));
expect(
JSON.parse(String(sockets[0]!.send.mock.calls[0]![0])),
).toMatchObject({
type: "authenticate",
protocol: "screener-v1",
});
const message = new Event("message");
Object.defineProperty(message, "data", { value: payload });
sockets[0]!.dispatchEvent(message);
const close = new Event("close");
Object.defineProperties(close, {
code: { value: 1008 },
reason: { value: "Invalid message" },
});
sockets[0]!.dispatchEvent(close);
expect(onTerminated).toHaveBeenCalledOnce();
expect(onTerminated).toHaveBeenCalledWith(
"页面版本已更新,请刷新后重试",
);
expect(sockets[0]!.close).toHaveBeenCalledOnce();
expect(sockets).toHaveLength(1);
});
expect(onTerminated).toHaveBeenCalledOnce();
expect(onTerminated).toHaveBeenCalledWith(
"页面版本已更新,请刷新后重试",
);
expect(sockets[0]!.close).toHaveBeenCalledOnce();
expect(sockets).toHaveLength(1);
},
);
it("returns to the access gate after an unauthorized upgrade", async () => {
const sockets: FakeWebSocket[] = [];