fix(ui): keep route diagnostic labels stable (#318)

This commit is contained in:
AAA authored and GitHub committed 2026-08-28 22:53:27 +08:00
1 parent 27421f458c
commit b129b3dbc0
4 files changed
+160 -14

No files matched your search

+3 -14
View File
@@ -88,8 +88,6 @@ interface RoomRuntime {
pump?: Promise<void>;
deadlineTimer?: NodeJS.Timeout;
sfuRefreshesInFlight: Set<string>;
debugOrdinalByPeerId: Map<string, number>;
nextDebugOrdinal: number;
}
interface PreparedCandidate {
@@ -201,7 +199,6 @@ export class HybridMediaRouter {
room.advertisedCapacityByViewer.get(input.peerId) ?? 0,
);
}
this.debugPeer(input.roomId, input.peerId);
if (room.controller) {
this.releaseResources(
room.controller.upsertParticipant({
@@ -932,7 +929,6 @@ export class HybridMediaRouter {
removeViewer(roomId: string, peerId: string): void {
const room = this.rooms.get(roomId);
room?.advertisedCapacityByViewer.delete(peerId);
room?.debugOrdinalByPeerId.delete(peerId);
this.options.deleteConnectionId(roomId, peerId);
if (room?.controller?.confirmDeparture(peerId, this.now())) {
this.requestPump(roomId);
@@ -965,8 +961,6 @@ export class HybridMediaRouter {
advertisedCapacityByViewer: new Map(),
requested: false,
sfuRefreshesInFlight: new Set(),
debugOrdinalByPeerId: new Map(),
nextDebugOrdinal: 1,
};
this.rooms.set(roomId, room);
}
@@ -1952,14 +1946,9 @@ export class HybridMediaRouter {
private debugPeer(roomId: string, peerId: string): string {
const room = this.rooms.get(roomId);
if (peerId === room?.hostPeerId) return "host";
if (!room) return "viewer-unknown";
let ordinal = room.debugOrdinalByPeerId.get(peerId);
if (ordinal === undefined) {
ordinal = room.nextDebugOrdinal;
room.nextDebugOrdinal += 1;
room.debugOrdinalByPeerId.set(peerId, ordinal);
}
return `viewer-${ordinal}`;
return (
room?.controller?.diagnosticParticipantLabel(peerId) ?? "viewer-unknown"
);
}
private debugTuple(roomId: string, tuple: CandidateTuple): string {
+4
View File
@@ -375,6 +375,10 @@ export class RoomRouteController<Resource = unknown> {
});
}
diagnosticParticipantLabel(peerId: string): string {
return this.debugPeer(peerId);
}
snapshot(): RouteSnapshot<Resource> {
return {
revision: this.revision,
+118
View File
@@ -234,6 +234,124 @@ async function establishSfuRoom(
}
describe("HybridMediaRouter v9 runtime", () => {
it("keeps the controller diagnostic label until a departed relay is pruned", async () => {
const { store, sent, router } = harness(2);
try {
const room = await store.createRoom();
const host = connectHost(store, room);
complete(router, host);
const parent = connectViewer(store, room, "diagnostic-label-parent");
complete(router, parent);
const parentPrepare = await vi.waitFor(() => {
const prepared = preparedFor(sent, parent.sessionId);
expect(prepared).toBeDefined();
return prepared!;
});
router.handleRouteReady(parent, {
type: "route-ready",
revision: parentPrepare.revision,
phase: "prepare",
});
router.setViewerRelayCapacity(parent, 1);
const temporaryRoot = connectViewer(
store,
room,
"diagnostic-label-temporary-root",
);
complete(router, temporaryRoot);
const temporaryPrepare = await vi.waitFor(() => {
const prepared = preparedFor(sent, temporaryRoot.sessionId);
expect(prepared?.assignment.upstream).toEqual({
kind: "peer",
peerId: host.peerId,
});
return prepared!;
});
router.handleRouteReady(temporaryRoot, {
type: "route-ready",
revision: temporaryPrepare.revision,
phase: "prepare",
});
const child = connectViewer(store, room, "diagnostic-label-child");
complete(router, child);
const childPrepare = await vi.waitFor(() => {
const prepared = preparedFor(sent, child.sessionId);
expect(prepared?.assignment.upstream).toEqual({
kind: "peer",
peerId: parent.peerId,
});
return prepared!;
});
router.handleRouteReady(child, {
type: "route-ready",
revision: childPrepare.revision,
phase: "prepare",
});
store.disconnectParticipant(
room.roomId,
temporaryRoot.peerId,
temporaryRoot.sessionId,
);
router.disconnectParticipant(
room.roomId,
temporaryRoot.peerId,
temporaryRoot.sessionId,
);
router.removeViewer(room.roomId, temporaryRoot.peerId);
await vi.waitFor(() =>
expect(
router.resolveActiveViewerMediaEdge(
room.roomId,
temporaryRoot.peerId,
),
).toBeUndefined(),
);
const internal = router as unknown as {
debugPeer(roomId: string, peerId: string): string;
};
const label = internal.debugPeer(room.roomId, parent.peerId);
store.disconnectParticipant(
room.roomId,
parent.peerId,
parent.sessionId,
);
router.disconnectParticipant(
room.roomId,
parent.peerId,
parent.sessionId,
);
router.removeViewer(room.roomId, parent.peerId);
expect(internal.debugPeer(room.roomId, parent.peerId)).toBe(label);
const recovery = await vi.waitFor(() => {
const prepared = preparedFor(sent, child.sessionId);
expect(prepared?.revision).toBeGreaterThan(childPrepare.revision);
expect(prepared?.assignment.upstream).toEqual({
kind: "peer",
peerId: host.peerId,
});
return prepared!;
});
router.handleRouteReady(child, {
type: "route-ready",
revision: recovery.revision,
phase: "prepare",
});
await vi.waitFor(() =>
expect(internal.debugPeer(room.roomId, parent.peerId)).toBe(
"viewer-unknown",
),
);
} finally {
await router.close();
}
});
it("maps an exact Host active failure to its committed direct edge", async () => {
const { store, sent, router } = harness(2);
try {
+35
View File
@@ -353,6 +353,41 @@ function qualityMetrics(
}
describe("RoomRouteController", () => {
it("keeps one diagnostic label until a departed relay is finally pruned", () => {
const routes = controller(2);
addViewer(routes, A, 1);
addViewer(routes, B, 0);
routes.hydrateEdge(A, peerEdge(HOST, "a_from_host"));
routes.hydrateEdge(B, peerEdge(A, "b_from_a"));
const label = routes.diagnosticParticipantLabel(A);
expect(label).toMatch(/^viewer-\d+$/);
routes.upsertParticipant({
peerId: A,
role: "viewer",
sessionId: "a_replacement_session",
effectiveDownstreamCapacity: 1,
});
expect(routes.diagnosticParticipantLabel(A)).toBe(label);
expect(routes.disconnectSession(A, "a_replacement_session")).toBe(true);
expect(routes.diagnosticParticipantLabel(A)).toBe(label);
expect(routes.confirmDeparture(A, 0)).toBe(true);
expect(routes.diagnosticParticipantLabel(A)).toBe(label);
const repair = routes.reconcile(1).operation!;
expect(repair).toMatchObject({
childPeerId: B,
reason: "parent-departed",
});
commitCurrent(routes, 2, "b_from_host");
const pruned = routes.reconcile(4);
expect(pruned.removedPeerIds).toContain(A);
expect(routes.diagnosticParticipantLabel(A)).toBe("viewer-unknown");
addViewer(routes, C, 0);
expect(routes.diagnosticParticipantLabel(C)).not.toBe(label);
});
it("keeps isolated limitation windows diagnostic", () => {
const routes = controller(2, { qualityConvergenceEnabled: true });
addViewer(routes, A, 2);