@webex/plugin-meetings 3.0.0-beta.257 → 3.0.0-beta.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/reachability/index.js +82 -29
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +1 -1
- package/dist/reachability/request.js.map +1 -1
- package/dist/roap/request.js +5 -13
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +4 -4
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/types/meetings/index.d.ts +11 -1
- package/dist/types/reachability/index.d.ts +30 -5
- package/package.json +20 -20
- package/src/reachability/index.ts +101 -25
- package/src/reachability/request.ts +1 -1
- package/src/roap/request.ts +3 -16
- package/src/roap/turnDiscovery.ts +4 -3
- package/test/unit/spec/meeting/index.js +2 -1
- package/test/unit/spec/reachability/index.ts +163 -7
- package/test/unit/spec/roap/index.ts +1 -1
- package/test/unit/spec/roap/request.ts +1 -0
- package/test/unit/spec/roap/turnDiscovery.ts +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","TurnDiscovery","roapRequest","turnInfo","url","username","password","defer","LoggerProxy","logger","warn","reject","Error","responseTimer","setTimeout","info","promise","roapMessage","headers","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","resolve","meeting","isReconnecting","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","MeetingUtil","getIpVersion","webex","then","mediaConnections","updateMediaConnections","OK","meetings","reachability","isAnyClusterReachable","config","experimental","enableTurnDiscovery","getSkipReason","skipReason","turnDiscoverySkippedReason","turnServerInfo","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","correlationId","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["// @ts-ignore - Types not available for @webex/common\nimport {Defer} from '@webex/common';\n\nimport Metrics from '../metrics';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {ROAP} from '../constants';\n\nimport RoapRequest from './request';\nimport Meeting from '../meeting';\nimport MeetingUtil from '../meeting/util';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\n\n// Roap spec says that seq should start from 1, but TURN discovery works fine with seq=0\n// and this is handy for us, because TURN discovery is always done before the first SDP exchange,\n// so we can do it with seq=0 or not do it at all and then we create the RoapMediaConnection\n// and do the SDP offer with seq=1\nconst TURN_DISCOVERY_SEQ = 0;\n\n/**\n * Handles the process of finding out TURN server information from Linus.\n * This is achieved by sending a TURN_DISCOVERY_REQUEST.\n */\nexport default class TurnDiscovery {\n private roapRequest: RoapRequest;\n\n private defer?: Defer; // used for waiting for the response\n\n private turnInfo: {\n url: string;\n username: string;\n password: string;\n };\n\n private responseTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Constructor\n *\n * @param {RoapRequest} roapRequest\n */\n constructor(roapRequest: RoapRequest) {\n this.roapRequest = roapRequest;\n this.turnInfo = {\n url: '',\n username: '',\n password: '',\n };\n }\n\n /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n private waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress'\n );\n\n return Promise.reject(\n new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()')\n );\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`\n );\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...'\n );\n\n return defer.promise;\n }\n\n /**\n * handles TURN_DISCOVERY_RESPONSE roap message\n *\n * @param {Object} roapMessage\n * @returns {void}\n * @public\n * @memberof Roap\n */\n public handleTurnDiscoveryResponse(roapMessage: object) {\n // @ts-ignore - Fix missing type\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response'\n );\n\n return;\n }\n\n const expectedHeaders = [\n {headerName: 'x-cisco-turn-url', field: 'url'},\n {headerName: 'x-cisco-turn-username', field: 'username'},\n {headerName: 'x-cisco-turn-password', field: 'password'},\n ];\n\n let foundHeaders = 0;\n\n headers?.forEach((receivedHeader) => {\n // check if it matches any of our expected headers\n expectedHeaders.forEach((expectedHeader) => {\n if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {\n this.turnInfo[expectedHeader.field] = receivedHeader.substring(\n expectedHeader.headerName.length + 1\n );\n foundHeaders += 1;\n }\n });\n });\n\n clearTimeout(this.responseTimer);\n this.responseTimer = undefined;\n\n if (foundHeaders !== expectedHeaders.length) {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(\n headers\n )}`\n );\n this.defer.reject(\n new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`)\n );\n } else {\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`\n );\n this.defer.resolve();\n }\n }\n\n /**\n * sends the TURN_DISCOVERY_REQUEST roap request\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean) {\n if (this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress'\n );\n\n return Promise.resolve();\n }\n\n this.defer = new Defer();\n\n const roapMessage = {\n messageType: ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n };\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST'\n );\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n // @ts-ignore - Fix missing type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - Fix missing type\n mediaId: isReconnecting ? '' : meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n // @ts-ignore - because of meeting.webex\n ipVersion: MeetingUtil.getIpVersion(meeting.webex),\n })\n .then(({mediaConnections}) => {\n if (mediaConnections) {\n meeting.updateMediaConnections(mediaConnections);\n }\n });\n }\n\n /**\n * Sends the OK message that server expects to receive\n * after it sends us TURN_DISCOVERY_RESPONSE\n *\n * @param {Meeting} meeting\n * @returns {Promise}\n */\n sendRoapOK(meeting: Meeting) {\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapOK --> sending OK');\n\n return this.roapRequest.sendRoap({\n roapMessage: {\n messageType: ROAP.ROAP_TYPES.OK,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n },\n // @ts-ignore - fix type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - fix type\n mediaId: meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n });\n }\n\n /**\n * Gets the reason why reachability is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped\n */\n private async getSkipReason(meeting: Meeting): Promise<string> {\n // @ts-ignore - fix type\n const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n // @ts-ignore - fix type\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> TURN discovery disabled in config, skipping it'\n );\n\n return 'config';\n }\n\n return '';\n }\n\n /**\n * Checks if TURN discovery is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Boolean} true if TURN discovery is being skipped, false if it is being done\n */\n async isSkipped(meeting) {\n const skipReason = await this.getSkipReason(meeting);\n\n return !!skipReason;\n }\n\n /**\n * Retrieves TURN server information from the backend by doing\n * a roap message exchange:\n * client server\n * | -----TURN_DISCOVERY_REQUEST-----> |\n * | <----TURN_DISCOVERY_RESPONSE----- |\n * | --------------OK----------------> |\n *\n * This TURN discovery roap exchange is always done with seq=0.\n * The RoapMediaConnection SDP exchange always starts with seq=1,\n * so it works fine no matter if TURN discovery is done or not.\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting should be set to true if this is a new\n * media connection just after a reconnection\n * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {\n const turnDiscoverySkippedReason = await this.getSkipReason(meeting);\n\n if (turnDiscoverySkippedReason) {\n return {\n turnServerInfo: undefined,\n turnDiscoverySkippedReason,\n };\n }\n\n return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)\n .then(() => this.waitForTurnDiscoveryResponse())\n .then(() => this.sendRoapOK(meeting))\n .then(() => {\n this.defer = undefined;\n\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');\n\n return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};\n })\n .catch((e) => {\n // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`\n );\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE, {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack,\n });\n\n return {turnServerInfo: undefined, turnDiscoverySkippedReason: undefined};\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","TurnDiscovery","roapRequest","turnInfo","url","username","password","defer","LoggerProxy","logger","warn","reject","Error","responseTimer","setTimeout","info","promise","roapMessage","headers","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","resolve","meeting","isReconnecting","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","MeetingUtil","getIpVersion","webex","then","mediaConnections","updateMediaConnections","OK","meetings","reachability","isAnyPublicClusterReachable","config","experimental","enableTurnDiscovery","getSkipReason","skipReason","turnDiscoverySkippedReason","turnServerInfo","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","correlationId","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["// @ts-ignore - Types not available for @webex/common\nimport {Defer} from '@webex/common';\n\nimport Metrics from '../metrics';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {ROAP} from '../constants';\n\nimport RoapRequest from './request';\nimport Meeting from '../meeting';\nimport MeetingUtil from '../meeting/util';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\n\n// Roap spec says that seq should start from 1, but TURN discovery works fine with seq=0\n// and this is handy for us, because TURN discovery is always done before the first SDP exchange,\n// so we can do it with seq=0 or not do it at all and then we create the RoapMediaConnection\n// and do the SDP offer with seq=1\nconst TURN_DISCOVERY_SEQ = 0;\n\n/**\n * Handles the process of finding out TURN server information from Linus.\n * This is achieved by sending a TURN_DISCOVERY_REQUEST.\n */\nexport default class TurnDiscovery {\n private roapRequest: RoapRequest;\n\n private defer?: Defer; // used for waiting for the response\n\n private turnInfo: {\n url: string;\n username: string;\n password: string;\n };\n\n private responseTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Constructor\n *\n * @param {RoapRequest} roapRequest\n */\n constructor(roapRequest: RoapRequest) {\n this.roapRequest = roapRequest;\n this.turnInfo = {\n url: '',\n username: '',\n password: '',\n };\n }\n\n /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n private waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress'\n );\n\n return Promise.reject(\n new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()')\n );\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`\n );\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...'\n );\n\n return defer.promise;\n }\n\n /**\n * handles TURN_DISCOVERY_RESPONSE roap message\n *\n * @param {Object} roapMessage\n * @returns {void}\n * @public\n * @memberof Roap\n */\n public handleTurnDiscoveryResponse(roapMessage: object) {\n // @ts-ignore - Fix missing type\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response'\n );\n\n return;\n }\n\n const expectedHeaders = [\n {headerName: 'x-cisco-turn-url', field: 'url'},\n {headerName: 'x-cisco-turn-username', field: 'username'},\n {headerName: 'x-cisco-turn-password', field: 'password'},\n ];\n\n let foundHeaders = 0;\n\n headers?.forEach((receivedHeader) => {\n // check if it matches any of our expected headers\n expectedHeaders.forEach((expectedHeader) => {\n if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {\n this.turnInfo[expectedHeader.field] = receivedHeader.substring(\n expectedHeader.headerName.length + 1\n );\n foundHeaders += 1;\n }\n });\n });\n\n clearTimeout(this.responseTimer);\n this.responseTimer = undefined;\n\n if (foundHeaders !== expectedHeaders.length) {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(\n headers\n )}`\n );\n this.defer.reject(\n new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`)\n );\n } else {\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`\n );\n this.defer.resolve();\n }\n }\n\n /**\n * sends the TURN_DISCOVERY_REQUEST roap request\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean) {\n if (this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress'\n );\n\n return Promise.resolve();\n }\n\n this.defer = new Defer();\n\n const roapMessage = {\n messageType: ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n };\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST'\n );\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n // @ts-ignore - Fix missing type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - Fix missing type\n mediaId: isReconnecting ? '' : meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n // @ts-ignore - because of meeting.webex\n ipVersion: MeetingUtil.getIpVersion(meeting.webex),\n })\n .then(({mediaConnections}) => {\n if (mediaConnections) {\n meeting.updateMediaConnections(mediaConnections);\n }\n });\n }\n\n /**\n * Sends the OK message that server expects to receive\n * after it sends us TURN_DISCOVERY_RESPONSE\n *\n * @param {Meeting} meeting\n * @returns {Promise}\n */\n sendRoapOK(meeting: Meeting) {\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapOK --> sending OK');\n\n return this.roapRequest.sendRoap({\n roapMessage: {\n messageType: ROAP.ROAP_TYPES.OK,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n },\n // @ts-ignore - fix type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - fix type\n mediaId: meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n });\n }\n\n /**\n * Gets the reason why reachability is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped\n */\n private async getSkipReason(meeting: Meeting): Promise<string> {\n const isAnyPublicClusterReachable =\n // @ts-ignore - fix type\n await meeting.webex.meetings.reachability.isAnyPublicClusterReachable();\n\n if (isAnyPublicClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n // @ts-ignore - fix type\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> TURN discovery disabled in config, skipping it'\n );\n\n return 'config';\n }\n\n return '';\n }\n\n /**\n * Checks if TURN discovery is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Boolean} true if TURN discovery is being skipped, false if it is being done\n */\n async isSkipped(meeting) {\n const skipReason = await this.getSkipReason(meeting);\n\n return !!skipReason;\n }\n\n /**\n * Retrieves TURN server information from the backend by doing\n * a roap message exchange:\n * client server\n * | -----TURN_DISCOVERY_REQUEST-----> |\n * | <----TURN_DISCOVERY_RESPONSE----- |\n * | --------------OK----------------> |\n *\n * This TURN discovery roap exchange is always done with seq=0.\n * The RoapMediaConnection SDP exchange always starts with seq=1,\n * so it works fine no matter if TURN discovery is done or not.\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting should be set to true if this is a new\n * media connection just after a reconnection\n * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {\n const turnDiscoverySkippedReason = await this.getSkipReason(meeting);\n\n if (turnDiscoverySkippedReason) {\n return {\n turnServerInfo: undefined,\n turnDiscoverySkippedReason,\n };\n }\n\n return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)\n .then(() => this.waitForTurnDiscoveryResponse())\n .then(() => this.sendRoapOK(meeting))\n .then(() => {\n this.defer = undefined;\n\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');\n\n return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};\n })\n .catch((e) => {\n // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`\n );\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE, {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack,\n });\n\n return {turnServerInfo: undefined, turnDiscoverySkippedReason: undefined};\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -244,7 +244,17 @@ export default class Meetings extends WebexPlugin {
|
|
|
244
244
|
* @public
|
|
245
245
|
* @memberof Meetings
|
|
246
246
|
*/
|
|
247
|
-
startReachability(): Promise<
|
|
247
|
+
startReachability(): Promise<{
|
|
248
|
+
[x: string]: {
|
|
249
|
+
udp: import("../reachability").TransportResult;
|
|
250
|
+
tcp: import("../reachability").TransportResult;
|
|
251
|
+
xtls: {
|
|
252
|
+
untested: "true";
|
|
253
|
+
};
|
|
254
|
+
} & {
|
|
255
|
+
isVideoMesh?: boolean;
|
|
256
|
+
};
|
|
257
|
+
}>;
|
|
248
258
|
/**
|
|
249
259
|
* Get geoHint for info for meetings
|
|
250
260
|
* @returns {Promise}
|
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
|
+
export type TransportResult = {
|
|
5
|
+
reachable: 'true' | 'false';
|
|
6
|
+
latencyInMilliseconds?: string;
|
|
7
|
+
clientMediaIPs?: string[];
|
|
8
|
+
untested?: 'true';
|
|
9
|
+
};
|
|
10
|
+
type ReachabilityResult = {
|
|
11
|
+
udp: TransportResult;
|
|
12
|
+
tcp: TransportResult;
|
|
13
|
+
xtls: {
|
|
14
|
+
untested: 'true';
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export type ReachabilityResults = Record<string, ReachabilityResult>;
|
|
18
|
+
type InternalReachabilityResults = Record<string, ReachabilityResult & {
|
|
19
|
+
isVideoMesh?: boolean;
|
|
20
|
+
}>;
|
|
4
21
|
export type ICECandidateResult = {
|
|
5
22
|
clusterId: string;
|
|
23
|
+
isVideoMesh: boolean;
|
|
6
24
|
elapsed?: string | null;
|
|
7
25
|
publicIPs?: string[];
|
|
8
26
|
};
|
|
@@ -28,14 +46,20 @@ export default class Reachability {
|
|
|
28
46
|
* @async
|
|
29
47
|
* @memberof Reachability
|
|
30
48
|
*/
|
|
31
|
-
gatherReachability(): Promise<
|
|
49
|
+
gatherReachability(): Promise<InternalReachabilityResults>;
|
|
50
|
+
/**
|
|
51
|
+
* Reachability results as an object in the format that backend expects
|
|
52
|
+
*
|
|
53
|
+
* @returns {any} reachability results that need to be sent to the backend
|
|
54
|
+
*/
|
|
55
|
+
getReachabilityResults(): Promise<ReachabilityResults | undefined>;
|
|
32
56
|
/**
|
|
33
57
|
* fetches reachability data and checks for cluster reachability
|
|
34
58
|
* @returns {boolean}
|
|
35
59
|
* @public
|
|
36
60
|
* @memberof Reachability
|
|
37
61
|
*/
|
|
38
|
-
|
|
62
|
+
isAnyPublicClusterReachable(): Promise<boolean>;
|
|
39
63
|
/**
|
|
40
64
|
* Generate peerConnection config settings
|
|
41
65
|
* @param {object} cluster
|
|
@@ -99,7 +123,7 @@ export default class Reachability {
|
|
|
99
123
|
* speed.
|
|
100
124
|
* @private
|
|
101
125
|
* @param {RTCPeerConnection} peerConnection
|
|
102
|
-
* @param {
|
|
126
|
+
* @param {boolean} isVideoMesh
|
|
103
127
|
* @returns {Promise}
|
|
104
128
|
*/
|
|
105
129
|
private iceGatheringState;
|
|
@@ -117,11 +141,11 @@ export default class Reachability {
|
|
|
117
141
|
* @protected
|
|
118
142
|
* @memberof Reachability
|
|
119
143
|
*/
|
|
120
|
-
protected
|
|
144
|
+
protected parseIceResultsToInternalReachabilityResults(iceResults: Array<ICECandidateResult>): InternalReachabilityResults;
|
|
121
145
|
/**
|
|
122
146
|
* fetches reachability data
|
|
123
147
|
* @param {object} clusterList
|
|
124
|
-
* @returns {Promise<
|
|
148
|
+
* @returns {Promise<InternalReachabilityResults>} reachability check results
|
|
125
149
|
* @private
|
|
126
150
|
* @memberof Reachability
|
|
127
151
|
*/
|
|
@@ -150,3 +174,4 @@ export default class Reachability {
|
|
|
150
174
|
*/
|
|
151
175
|
private setup;
|
|
152
176
|
}
|
|
177
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/plugin-meetings",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.259",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
|
|
6
6
|
"contributors": [
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@webex/plugin-meetings": "3.0.0-beta.
|
|
36
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
37
|
-
"@webex/test-helper-mocha": "3.0.0-beta.
|
|
38
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
39
|
-
"@webex/test-helper-retry": "3.0.0-beta.
|
|
40
|
-
"@webex/test-helper-test-users": "3.0.0-beta.
|
|
35
|
+
"@webex/plugin-meetings": "3.0.0-beta.259",
|
|
36
|
+
"@webex/test-helper-chai": "3.0.0-beta.259",
|
|
37
|
+
"@webex/test-helper-mocha": "3.0.0-beta.259",
|
|
38
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.259",
|
|
39
|
+
"@webex/test-helper-retry": "3.0.0-beta.259",
|
|
40
|
+
"@webex/test-helper-test-users": "3.0.0-beta.259",
|
|
41
41
|
"chai": "^4.3.4",
|
|
42
42
|
"chai-as-promised": "^7.1.1",
|
|
43
43
|
"jsdom-global": "3.0.2",
|
|
@@ -46,19 +46,19 @@
|
|
|
46
46
|
"typescript": "^4.7.4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@webex/common": "3.0.0-beta.
|
|
50
|
-
"@webex/internal-media-core": "2.0.
|
|
51
|
-
"@webex/internal-plugin-conversation": "3.0.0-beta.
|
|
52
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
53
|
-
"@webex/internal-plugin-llm": "3.0.0-beta.
|
|
54
|
-
"@webex/internal-plugin-mercury": "3.0.0-beta.
|
|
55
|
-
"@webex/internal-plugin-metrics": "3.0.0-beta.
|
|
56
|
-
"@webex/internal-plugin-support": "3.0.0-beta.
|
|
57
|
-
"@webex/internal-plugin-user": "3.0.0-beta.
|
|
58
|
-
"@webex/media-helpers": "3.0.0-beta.
|
|
59
|
-
"@webex/plugin-people": "3.0.0-beta.
|
|
60
|
-
"@webex/plugin-rooms": "3.0.0-beta.
|
|
61
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
49
|
+
"@webex/common": "3.0.0-beta.259",
|
|
50
|
+
"@webex/internal-media-core": "2.0.4",
|
|
51
|
+
"@webex/internal-plugin-conversation": "3.0.0-beta.259",
|
|
52
|
+
"@webex/internal-plugin-device": "3.0.0-beta.259",
|
|
53
|
+
"@webex/internal-plugin-llm": "3.0.0-beta.259",
|
|
54
|
+
"@webex/internal-plugin-mercury": "3.0.0-beta.259",
|
|
55
|
+
"@webex/internal-plugin-metrics": "3.0.0-beta.259",
|
|
56
|
+
"@webex/internal-plugin-support": "3.0.0-beta.259",
|
|
57
|
+
"@webex/internal-plugin-user": "3.0.0-beta.259",
|
|
58
|
+
"@webex/media-helpers": "3.0.0-beta.259",
|
|
59
|
+
"@webex/plugin-people": "3.0.0-beta.259",
|
|
60
|
+
"@webex/plugin-rooms": "3.0.0-beta.259",
|
|
61
|
+
"@webex/webex-core": "3.0.0-beta.259",
|
|
62
62
|
"ampersand-collection": "^2.0.2",
|
|
63
63
|
"bowser": "^2.11.0",
|
|
64
64
|
"btoa": "^1.2.1",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/* eslint-disable class-methods-use-this */
|
|
6
6
|
/* globals window */
|
|
7
|
-
import
|
|
7
|
+
import {uniq, mapValues, pick} from 'lodash';
|
|
8
8
|
|
|
9
9
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
10
10
|
import MeetingUtil from '../meeting/util';
|
|
@@ -16,7 +16,39 @@ import ReachabilityRequest from './request';
|
|
|
16
16
|
const DEFAULT_TIMEOUT = 3000;
|
|
17
17
|
const VIDEO_MESH_TIMEOUT = 1000;
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// result for a specific transport protocol (like udp or tcp)
|
|
20
|
+
export type TransportResult = {
|
|
21
|
+
reachable: 'true' | 'false';
|
|
22
|
+
latencyInMilliseconds?: string;
|
|
23
|
+
clientMediaIPs?: string[];
|
|
24
|
+
untested?: 'true';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// reachability result for a specifc media cluster
|
|
28
|
+
type ReachabilityResult = {
|
|
29
|
+
udp: TransportResult;
|
|
30
|
+
tcp: TransportResult;
|
|
31
|
+
xtls: {
|
|
32
|
+
untested: 'true';
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
// this is the type that is required by the backend when we send them reachability results
|
|
36
|
+
export type ReachabilityResults = Record<string, ReachabilityResult>;
|
|
37
|
+
|
|
38
|
+
// this is the type used by Reachability class internally and stored in local storage
|
|
39
|
+
type InternalReachabilityResults = Record<
|
|
40
|
+
string,
|
|
41
|
+
ReachabilityResult & {
|
|
42
|
+
isVideoMesh?: boolean;
|
|
43
|
+
}
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
export type ICECandidateResult = {
|
|
47
|
+
clusterId: string;
|
|
48
|
+
isVideoMesh: boolean;
|
|
49
|
+
elapsed?: string | null;
|
|
50
|
+
publicIPs?: string[];
|
|
51
|
+
};
|
|
20
52
|
/**
|
|
21
53
|
* @class Reachability
|
|
22
54
|
* @export
|
|
@@ -61,7 +93,7 @@ export default class Reachability {
|
|
|
61
93
|
* @async
|
|
62
94
|
* @memberof Reachability
|
|
63
95
|
*/
|
|
64
|
-
public async gatherReachability() {
|
|
96
|
+
public async gatherReachability(): Promise<InternalReachabilityResults> {
|
|
65
97
|
this.setup();
|
|
66
98
|
|
|
67
99
|
// Remove stored reachability results to ensure no stale data
|
|
@@ -106,13 +138,45 @@ export default class Reachability {
|
|
|
106
138
|
}
|
|
107
139
|
}
|
|
108
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Reachability results as an object in the format that backend expects
|
|
143
|
+
*
|
|
144
|
+
* @returns {any} reachability results that need to be sent to the backend
|
|
145
|
+
*/
|
|
146
|
+
async getReachabilityResults(): Promise<ReachabilityResults | undefined> {
|
|
147
|
+
let results: ReachabilityResults;
|
|
148
|
+
|
|
149
|
+
// these are the only props that backend needs in the reachability results:
|
|
150
|
+
const reachabilityResultsProps: Array<keyof ReachabilityResult> = ['udp', 'tcp', 'xtls'];
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
const resultsJson = await this.webex.boundedStorage.get(
|
|
155
|
+
REACHABILITY.namespace,
|
|
156
|
+
REACHABILITY.localStorageResult
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const internalResults: InternalReachabilityResults = JSON.parse(resultsJson);
|
|
160
|
+
|
|
161
|
+
results = mapValues(internalResults, (result) => pick(result, reachabilityResultsProps));
|
|
162
|
+
} catch (e) {
|
|
163
|
+
// empty storage, that's ok
|
|
164
|
+
LoggerProxy.logger.warn(
|
|
165
|
+
'Roap:request#attachReachabilityData --> Error parsing reachability data: ',
|
|
166
|
+
e
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
172
|
+
|
|
109
173
|
/**
|
|
110
174
|
* fetches reachability data and checks for cluster reachability
|
|
111
175
|
* @returns {boolean}
|
|
112
176
|
* @public
|
|
113
177
|
* @memberof Reachability
|
|
114
178
|
*/
|
|
115
|
-
async
|
|
179
|
+
async isAnyPublicClusterReachable() {
|
|
116
180
|
let reachable = false;
|
|
117
181
|
// @ts-ignore
|
|
118
182
|
const reachabilityData = await this.webex.boundedStorage
|
|
@@ -121,10 +185,12 @@ export default class Reachability {
|
|
|
121
185
|
|
|
122
186
|
if (reachabilityData) {
|
|
123
187
|
try {
|
|
124
|
-
const reachabilityResults = JSON.parse(reachabilityData);
|
|
188
|
+
const reachabilityResults: InternalReachabilityResults = JSON.parse(reachabilityData);
|
|
125
189
|
|
|
126
190
|
reachable = Object.values(reachabilityResults).some(
|
|
127
|
-
(result
|
|
191
|
+
(result) =>
|
|
192
|
+
!result.isVideoMesh &&
|
|
193
|
+
(result.udp?.reachable === 'true' || result.tcp?.reachable === 'true')
|
|
128
194
|
);
|
|
129
195
|
} catch (e) {
|
|
130
196
|
LoggerProxy.logger.error(
|
|
@@ -144,7 +210,7 @@ export default class Reachability {
|
|
|
144
210
|
* @memberof Reachability
|
|
145
211
|
*/
|
|
146
212
|
private buildPeerConnectionConfig(cluster: any) {
|
|
147
|
-
const iceServers =
|
|
213
|
+
const iceServers = uniq(cluster.udp).map((url) => ({
|
|
148
214
|
username: '',
|
|
149
215
|
credential: '',
|
|
150
216
|
urls: [url],
|
|
@@ -205,7 +271,7 @@ export default class Reachability {
|
|
|
205
271
|
* @private
|
|
206
272
|
* @memberof Reachability
|
|
207
273
|
*/
|
|
208
|
-
private getLocalSDPForClusters(clusterList: object) {
|
|
274
|
+
private getLocalSDPForClusters(clusterList: object): Promise<InternalReachabilityResults> {
|
|
209
275
|
let clusters: any[] = [...Object.keys(clusterList)];
|
|
210
276
|
|
|
211
277
|
clusters = clusters.map(async (key) => {
|
|
@@ -218,18 +284,17 @@ export default class Reachability {
|
|
|
218
284
|
peerConnection.begin = Date.now();
|
|
219
285
|
peerConnection.setLocalDescription(description);
|
|
220
286
|
|
|
221
|
-
return this.iceGatheringState(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
});
|
|
287
|
+
return this.iceGatheringState(peerConnection, cluster.isVideoMesh).catch(
|
|
288
|
+
(iceGatheringStateError) => {
|
|
289
|
+
LoggerProxy.logger.log(
|
|
290
|
+
`Reachability:index#getLocalSDPForClusters --> Error in getLocalSDP : ${iceGatheringStateError}`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
);
|
|
229
294
|
});
|
|
230
295
|
|
|
231
296
|
return Promise.all(clusters)
|
|
232
|
-
.then(this.
|
|
297
|
+
.then(this.parseIceResultsToInternalReachabilityResults)
|
|
233
298
|
.then((reachabilityLatencyResults) => {
|
|
234
299
|
this.logUnreachableClusters();
|
|
235
300
|
|
|
@@ -318,12 +383,14 @@ export default class Reachability {
|
|
|
318
383
|
* speed.
|
|
319
384
|
* @private
|
|
320
385
|
* @param {RTCPeerConnection} peerConnection
|
|
321
|
-
* @param {
|
|
386
|
+
* @param {boolean} isVideoMesh
|
|
322
387
|
* @returns {Promise}
|
|
323
388
|
*/
|
|
324
|
-
private iceGatheringState(peerConnection: RTCPeerConnection,
|
|
389
|
+
private iceGatheringState(peerConnection: RTCPeerConnection, isVideoMesh: boolean) {
|
|
325
390
|
const ELAPSED = 'elapsed';
|
|
326
391
|
|
|
392
|
+
const timeout = isVideoMesh ? VIDEO_MESH_TIMEOUT : DEFAULT_TIMEOUT;
|
|
393
|
+
|
|
327
394
|
return new Promise<ICECandidateResult>((resolve) => {
|
|
328
395
|
const peerConnectionProxy = new window.Proxy(peerConnection, {
|
|
329
396
|
// eslint-disable-next-line require-jsdoc
|
|
@@ -339,8 +406,14 @@ export default class Reachability {
|
|
|
339
406
|
set: (target, property, value) => {
|
|
340
407
|
// only intercept elapsed property
|
|
341
408
|
if (property === ELAPSED) {
|
|
342
|
-
|
|
343
|
-
|
|
409
|
+
resolve({
|
|
410
|
+
// @ts-ignore
|
|
411
|
+
clusterId: peerConnection.key,
|
|
412
|
+
isVideoMesh,
|
|
413
|
+
// @ts-ignore
|
|
414
|
+
publicIPs: target.publicIPs,
|
|
415
|
+
elapsed: value,
|
|
416
|
+
});
|
|
344
417
|
|
|
345
418
|
return true;
|
|
346
419
|
}
|
|
@@ -392,10 +465,12 @@ export default class Reachability {
|
|
|
392
465
|
* @protected
|
|
393
466
|
* @memberof Reachability
|
|
394
467
|
*/
|
|
395
|
-
protected
|
|
468
|
+
protected parseIceResultsToInternalReachabilityResults(
|
|
469
|
+
iceResults: Array<ICECandidateResult>
|
|
470
|
+
): InternalReachabilityResults {
|
|
396
471
|
const reachabilityMap = {};
|
|
397
472
|
|
|
398
|
-
iceResults.forEach(({clusterId, elapsed, publicIPs}) => {
|
|
473
|
+
iceResults.forEach(({clusterId, isVideoMesh, elapsed, publicIPs}) => {
|
|
399
474
|
const latencyResult = {};
|
|
400
475
|
|
|
401
476
|
if (!elapsed) {
|
|
@@ -417,6 +492,7 @@ export default class Reachability {
|
|
|
417
492
|
udp: latencyResult,
|
|
418
493
|
tcp: {untested: 'true'},
|
|
419
494
|
xtls: {untested: 'true'},
|
|
495
|
+
isVideoMesh,
|
|
420
496
|
};
|
|
421
497
|
});
|
|
422
498
|
|
|
@@ -426,11 +502,11 @@ export default class Reachability {
|
|
|
426
502
|
/**
|
|
427
503
|
* fetches reachability data
|
|
428
504
|
* @param {object} clusterList
|
|
429
|
-
* @returns {Promise<
|
|
505
|
+
* @returns {Promise<InternalReachabilityResults>} reachability check results
|
|
430
506
|
* @private
|
|
431
507
|
* @memberof Reachability
|
|
432
508
|
*/
|
|
433
|
-
private performReachabilityCheck(clusterList: object) {
|
|
509
|
+
private performReachabilityCheck(clusterList: object): Promise<InternalReachabilityResults> {
|
|
434
510
|
if (!clusterList || !Object.keys(clusterList).length) {
|
|
435
511
|
return Promise.resolve({});
|
|
436
512
|
}
|
|
@@ -49,7 +49,7 @@ class ReachabilityRequest {
|
|
|
49
49
|
const {clusters, joinCookie} = res.body;
|
|
50
50
|
|
|
51
51
|
Object.keys(clusters).forEach((key) => {
|
|
52
|
-
clusters[key].isVideoMesh = res.body.clusterClasses?.hybridMedia?.includes(key);
|
|
52
|
+
clusters[key].isVideoMesh = !!res.body.clusterClasses?.hybridMedia?.includes(key);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
LoggerProxy.logger.log(
|
package/src/roap/request.ts
CHANGED
|
@@ -18,23 +18,10 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
18
18
|
let joinCookie;
|
|
19
19
|
|
|
20
20
|
// @ts-ignore
|
|
21
|
-
const
|
|
22
|
-
.get(REACHABILITY.namespace, REACHABILITY.localStorageResult)
|
|
23
|
-
.catch(() => {});
|
|
24
|
-
|
|
25
|
-
if (reachabilityData) {
|
|
26
|
-
try {
|
|
27
|
-
const reachabilityResult = JSON.parse(reachabilityData);
|
|
21
|
+
const reachabilityResult = await this.webex.meetings.reachability.getReachabilityResults();
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
localSdp.reachability = reachabilityResult;
|
|
32
|
-
}
|
|
33
|
-
} catch (e) {
|
|
34
|
-
LoggerProxy.logger.error(
|
|
35
|
-
`Roap:request#attachReachabilityData --> Error in parsing reachability data: ${e}`
|
|
36
|
-
);
|
|
37
|
-
}
|
|
23
|
+
if (reachabilityResult && Object.keys(reachabilityResult).length) {
|
|
24
|
+
localSdp.reachability = reachabilityResult;
|
|
38
25
|
}
|
|
39
26
|
|
|
40
27
|
// @ts-ignore
|
|
@@ -225,10 +225,11 @@ export default class TurnDiscovery {
|
|
|
225
225
|
* @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped
|
|
226
226
|
*/
|
|
227
227
|
private async getSkipReason(meeting: Meeting): Promise<string> {
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
const isAnyPublicClusterReachable =
|
|
229
|
+
// @ts-ignore - fix type
|
|
230
|
+
await meeting.webex.meetings.reachability.isAnyPublicClusterReachable();
|
|
230
231
|
|
|
231
|
-
if (
|
|
232
|
+
if (isAnyPublicClusterReachable) {
|
|
232
233
|
LoggerProxy.logger.info(
|
|
233
234
|
'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'
|
|
234
235
|
);
|
|
@@ -1722,7 +1722,8 @@ describe('plugin-meetings', () => {
|
|
|
1722
1722
|
meeting.locusInfo.onFullLocus = sinon.stub();
|
|
1723
1723
|
meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
|
|
1724
1724
|
meeting.webex.meetings.reachability = {
|
|
1725
|
-
|
|
1725
|
+
isAnyPublicClusterReachable: sinon.stub().resolves(true),
|
|
1726
|
+
getReachabilityResults: sinon.stub().resolves(undefined),
|
|
1726
1727
|
};
|
|
1727
1728
|
meeting.roap.doTurnDiscovery = sinon
|
|
1728
1729
|
.stub()
|