mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp: fix JSON event clean up
parent
07fcb1a462
commit
082c3a5580
|
|
@ -3,134 +3,7 @@ import { Subject } from "rxjs";
|
||||||
|
|
||||||
import * as stringify from "json-stringify-safe";
|
import * as stringify from "json-stringify-safe";
|
||||||
|
|
||||||
import {
|
import { Event } from "openvidu-browser-v2compatibility";
|
||||||
// Base classes
|
|
||||||
Session,
|
|
||||||
Stream,
|
|
||||||
Connection,
|
|
||||||
StreamManager,
|
|
||||||
Publisher,
|
|
||||||
Subscriber,
|
|
||||||
|
|
||||||
// Base Event
|
|
||||||
Event,
|
|
||||||
|
|
||||||
// Session Events
|
|
||||||
ConnectionEvent,
|
|
||||||
SessionDisconnectedEvent,
|
|
||||||
SignalEvent,
|
|
||||||
StreamEvent,
|
|
||||||
StreamPropertyChangedEvent,
|
|
||||||
ConnectionPropertyChangedEvent, // Missed previously
|
|
||||||
NetworkQualityLevelChangedEvent, // Missed previously
|
|
||||||
SpeechToTextEvent, // Missed previously
|
|
||||||
ExceptionEvent,
|
|
||||||
|
|
||||||
// StreamManager / Publisher / Subscriber Events
|
|
||||||
StreamManagerEvent,
|
|
||||||
VideoElementEvent,
|
|
||||||
PublisherSpeakingEvent,
|
|
||||||
RecordingEvent,
|
|
||||||
FilterEvent, // Missed previously
|
|
||||||
} from "openvidu-browser-v2compatibility";
|
|
||||||
|
|
||||||
const API_ALLOWLIST = new Map<any, string[]>([
|
|
||||||
// ===========================================================================
|
|
||||||
// 1. CORE ENTITIES
|
|
||||||
// ===========================================================================
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Session.html
|
|
||||||
[Session, ["sessionId", "connection", "capabilities", "streamManagers"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Connection.html
|
|
||||||
[Connection, ["connectionId", "creationTime", "data", "record", "role"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Stream.html
|
|
||||||
[
|
|
||||||
Stream,
|
|
||||||
[
|
|
||||||
"streamId",
|
|
||||||
"creationTime",
|
|
||||||
"hasAudio",
|
|
||||||
"hasVideo",
|
|
||||||
"audioActive",
|
|
||||||
"videoActive",
|
|
||||||
"typeOfVideo",
|
|
||||||
"frameRate",
|
|
||||||
"videoDimensions",
|
|
||||||
"connection",
|
|
||||||
"filter",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/StreamManager.html
|
|
||||||
[StreamManager, ["stream", "id", "remote", "videos"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Publisher.html
|
|
||||||
[Publisher, ["stream", "id", "remote", "videos", "accessAllowed"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Subscriber.html
|
|
||||||
[Subscriber, ["stream", "id", "remote", "videos"]],
|
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
// 2. BASE EVENT
|
|
||||||
// ===========================================================================
|
|
||||||
// These are merged into all specific events
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/Event.html
|
|
||||||
[Event, ["type", "cancelable", "target"]],
|
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
// 3. SPECIFIC EVENTS (Alphabetical Order)
|
|
||||||
// ===========================================================================
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/ConnectionEvent.html
|
|
||||||
[ConnectionEvent, ["connection", "reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/ConnectionPropertyChangedEvent.html
|
|
||||||
[
|
|
||||||
ConnectionPropertyChangedEvent,
|
|
||||||
["connection", "changedProperty", "oldValue", "newValue", "reason"],
|
|
||||||
],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/ExceptionEvent.html
|
|
||||||
[ExceptionEvent, ["name", "message", "data"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/FilterEvent.html
|
|
||||||
[FilterEvent, ["filter", "eventType", "data"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/NetworkQualityLevelChangedEvent.html
|
|
||||||
[NetworkQualityLevelChangedEvent, ["connection", "newValue", "oldValue"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/PublisherSpeakingEvent.html
|
|
||||||
[PublisherSpeakingEvent, ["connection", "streamId", "reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/RecordingEvent.html
|
|
||||||
[RecordingEvent, ["id", "name", "reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/SessionDisconnectedEvent.html
|
|
||||||
[SessionDisconnectedEvent, ["reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/SignalEvent.html
|
|
||||||
[SignalEvent, ["type", "data", "from"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/SpeechToTextEvent.html
|
|
||||||
[SpeechToTextEvent, ["connection", "text", "reason", "timestamp", "raw"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/StreamEvent.html
|
|
||||||
[StreamEvent, ["stream", "reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/StreamManagerEvent.html
|
|
||||||
[StreamManagerEvent, ["stream", "reason"]],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/StreamPropertyChangedEvent.html
|
|
||||||
[
|
|
||||||
StreamPropertyChangedEvent,
|
|
||||||
["stream", "changedProperty", "oldValue", "newValue", "reason"],
|
|
||||||
],
|
|
||||||
|
|
||||||
// https://docs.openvidu.io/en/2.32.0/api/openvidu-browser/classes/VideoElementEvent.html
|
|
||||||
[VideoElementEvent, ["element"]],
|
|
||||||
]);
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TestFeedService {
|
export class TestFeedService {
|
||||||
|
|
@ -152,56 +25,139 @@ export class TestFeedService {
|
||||||
return this.cleanEvent(event);
|
return this.cleanEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanEvent(root: any): string {
|
cleanEvent(event: any): string {
|
||||||
const seen = new WeakSet();
|
// 1. GLOBAL BLOCKLIST
|
||||||
|
const globalBlocklist = new Set([
|
||||||
|
"ee",
|
||||||
|
"openvidu",
|
||||||
|
"userHandlerArrowHandler",
|
||||||
|
"handlers",
|
||||||
|
"reliableMessageBuffer",
|
||||||
|
"socket",
|
||||||
|
"loggerOptions",
|
||||||
|
"log",
|
||||||
|
"closingLock",
|
||||||
|
"connectionLock",
|
||||||
|
"offerLock",
|
||||||
|
"remoteOfferLock",
|
||||||
|
"disconnectLock",
|
||||||
|
"dataProcessLock",
|
||||||
|
"taskMutex",
|
||||||
|
"requestQueue",
|
||||||
|
"mutex",
|
||||||
|
"lock",
|
||||||
|
"publisherConnectionPromise",
|
||||||
|
"signalConnectedFuture",
|
||||||
|
"sifTrailer",
|
||||||
|
"enabledCodecs",
|
||||||
|
"supportedCodecs",
|
||||||
|
"enabledPublishCodecs",
|
||||||
|
"enabledPublishVideoCodecs",
|
||||||
|
"videoCaptureDefaults",
|
||||||
|
"audioCaptureDefaults",
|
||||||
|
"publishDefaults",
|
||||||
|
"reconnectPolicy",
|
||||||
|
"permissions",
|
||||||
|
"engine",
|
||||||
|
"client",
|
||||||
|
"signalClient",
|
||||||
|
"pcManager",
|
||||||
|
"ws",
|
||||||
|
"internalEmitter",
|
||||||
|
"publicEmmiter",
|
||||||
|
"codecs",
|
||||||
|
"layers",
|
||||||
|
"encodings",
|
||||||
|
"prevStats",
|
||||||
|
"monitorInterval",
|
||||||
|
"volumeMap",
|
||||||
|
"midToTrackId",
|
||||||
|
"audioContext",
|
||||||
|
"rtcConfig",
|
||||||
|
"options",
|
||||||
|
"connectOptions",
|
||||||
|
]);
|
||||||
|
|
||||||
const getAllowedKeys = (obj: any): string[] | null => {
|
// 2. SCOPED BLOCKLIST (Parent -> Child removal)
|
||||||
for (const [ClassConstructor, keys] of API_ALLOWLIST.entries()) {
|
const scopedBlocklist: Record<string, Set<string>> = {
|
||||||
if (obj instanceof ClassConstructor) {
|
session: new Set(["room", "openvidu"]),
|
||||||
// If instance of specific Event, merge with base Event keys
|
target: new Set(["stream"]),
|
||||||
if (obj instanceof Event && ClassConstructor !== Event) {
|
streamManagers: new Set(["stream"])
|
||||||
return [...(API_ALLOWLIST.get(Event) || []), ...keys];
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const traverse = (current: any): any => {
|
const seen = new WeakSet();
|
||||||
if (current === null || current === undefined) return current;
|
|
||||||
if (typeof current === "bigint") return current.toString();
|
|
||||||
if (typeof current !== "object") return current;
|
|
||||||
|
|
||||||
if (seen.has(current)) return undefined;
|
// 3. RECURSIVE WALKER
|
||||||
seen.add(current);
|
const traverse = (
|
||||||
|
current: any,
|
||||||
if (Array.isArray(current)) {
|
nodeName: string | null,
|
||||||
return current.map(traverse).filter((x) => x !== undefined);
|
parentName: string | null
|
||||||
|
): any => {
|
||||||
|
// JSON.stringify cannot handle BigInt. Convert it to string.
|
||||||
|
if (typeof current === "bigint") {
|
||||||
|
return current.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowedKeys = getAllowedKeys(current);
|
// A. Handle Primitives
|
||||||
const copy: any = {};
|
if (typeof current !== "object" || current === null) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
if (allowedKeys) {
|
// B. Handle Circular References
|
||||||
// Known Class: Filter strictly
|
if (seen.has(current)) {
|
||||||
for (const key of allowedKeys) {
|
return undefined;
|
||||||
if (key in current) {
|
}
|
||||||
const val = traverse(current[key]);
|
seen.add(current);
|
||||||
if (val !== undefined) copy[key] = val;
|
|
||||||
|
// C. Handle Arrays
|
||||||
|
if (Array.isArray(current)) {
|
||||||
|
return current
|
||||||
|
.map((item) => traverse(item, null, nodeName))
|
||||||
|
.filter((item) => item !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
// D. Handle Objects
|
||||||
|
const copy: any = {};
|
||||||
|
const effectiveParent = nodeName || parentName;
|
||||||
|
|
||||||
|
for (const [childKey, childValue] of Object.entries(current)) {
|
||||||
|
// Rule 1: Global Blocklist and Private Properties (start with _)
|
||||||
|
if (globalBlocklist.has(childKey) || childKey.startsWith("_")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule 2: Scoped Blocklist
|
||||||
|
if (
|
||||||
|
effectiveParent &&
|
||||||
|
scopedBlocklist[effectiveParent]?.has(childKey)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule 3: Metadata parsing
|
||||||
|
if (childKey === "metadata" && typeof childValue === "string") {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(childValue);
|
||||||
|
copy[childKey] = {
|
||||||
|
role: parsed.role,
|
||||||
|
clientData: parsed.clientData,
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Plain Object: Copy recursive
|
const cleanedValue = traverse(childValue, childKey, nodeName);
|
||||||
for (const [key, value] of Object.entries(current)) {
|
if (cleanedValue !== undefined) {
|
||||||
const val = traverse(value);
|
copy[childKey] = cleanedValue;
|
||||||
if (val !== undefined) copy[key] = val;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
};
|
};
|
||||||
|
|
||||||
return JSON.stringify(traverse(root));
|
const cleanedObject = traverse(event, "root", null);
|
||||||
|
return JSON.stringify(cleanedObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue