import { sleep } from "../helpers/testutils.js"; /** @type {MockPrivateSignalingManager | MockPublicSignalingManager} */ let manager; export function reset(isPrivate) { manager = isPrivate ? new MockPrivateSignalingManager() : new MockPublicSignalingManager(); } export class MockSignaling extends EventTarget { constructor(interval = 1000) { super(); this.interval = interval; } async start() { await manager.add(this); } async stop() { await manager.remove(this); } async createConnection(connectionId) { await manager.openConnection(this, connectionId); } async deleteConnection(connectionId) { await manager.closeConnection(this, connectionId); } async sendOffer(connectionId, sdp) { const data = { 'sdp': sdp, 'connectionId': connectionId }; await manager.offer(this, data); } async sendAnswer(connectionId, sdp) { const data = { 'sdp': sdp, 'connectionId': connectionId }; await manager.answer(this, data); } async sendCandidate(connectionId, candidate, sdpMLineIndex, sdpMid) { const data = { 'candidate': candidate, 'sdpMLineIndex': sdpMLineIndex, 'sdpMid': sdpMid, 'connectionId': connectionId }; await manager.candidate(this, data); } } class MockPublicSignalingManager { constructor() { this.list = new Set(); this.delay = async () => await sleep(10); } async add(signaling) { await this.delay(); this.list.add(signaling); signaling.dispatchEvent(new Event("start")); } async remove(signaling) { await this.delay(); this.list.delete(signaling); signaling.dispatchEvent(new Event("end")); } async openConnection(signaling, connectionId) { await this.delay(); const data = { connectionId: connectionId, polite: true }; signaling.dispatchEvent(new CustomEvent("connect", { detail: data })); } async closeConnection(signaling, connectionId) { await this.delay(); const data = { connectionId: connectionId }; for (const element of this.list) { element.dispatchEvent(new CustomEvent("disconnect", { detail: data })); } } async offer(owner, data) { await this.delay(); data.polite = false; for (const signaling of this.list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("offer", { detail: data })); } } } async answer(owner, data) { await this.delay(); for (const signaling of this.list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("answer", { detail: data })); } } } async candidate(owner, data) { await this.delay(); for (const signaling of this.list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("candidate", { detail: data })); } } } } class MockPrivateSignalingManager { constructor() { // structure Map> connectionIds this.connectionIds = new Map(); this.delay = async () => await sleep(10); } async add(signaling) { await this.delay(); signaling.dispatchEvent(new Event("start")); } async remove(signaling) { await this.delay(); signaling.dispatchEvent(new Event("end")); } async openConnection(signaling, connectionId) { await this.delay(); const peerExists = this.connectionIds.has(connectionId); if (!peerExists) { this.connectionIds.set(connectionId, new Set()); } const list = this.connectionIds.get(connectionId); list.add(signaling); const data = { connectionId: connectionId, polite: peerExists }; signaling.dispatchEvent(new CustomEvent("connect", { detail: data })); } async closeConnection(signaling, connectionId) { await this.delay(); const peerExists = this.connectionIds.has(connectionId); const list = this.connectionIds.get(connectionId); if (!peerExists || !list.has(signaling)) { console.error(`${connectionId} This connection id is not used.`); } const data = { connectionId: connectionId }; for (const element of list) { element.dispatchEvent(new CustomEvent("disconnect", { detail: data })); } list.delete(signaling); if (list.size == 0) { this.connectionIds.delete(connectionId); } } findList(owner, connectionId) { if (!this.connectionIds.has(connectionId)) { return null; } const list = new Set(this.connectionIds.get(connectionId)); list.delete(owner); if (list.Count == 0) { return null; } return list; } async offer(owner, data) { await this.delay(); const list = this.findList(owner, data.connectionId); if (list == null) { console.warn(`${data.connectionId} This connection id is not ready other session.`); return; } data.polite = true; for (const signaling of list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("offer", { detail: data })); } } } async answer(owner, data) { await this.delay(); const list = this.findList(owner, data.connectionId); if (list == null) { console.warn(`${data.connectionId} This connection id is not ready other session.`); return; } for (const signaling of list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("answer", { detail: data })); } } } async candidate(owner, data) { await this.delay(); const list = this.findList(owner, data.connectionId); if (list == null) { console.warn(`${data.connectionId} This connection id is not ready other session.`); return; } for (const signaling of list) { if (signaling != owner) { signaling.dispatchEvent(new CustomEvent("candidate", { detail: data })); } } } }