@webex/plugin-meetings 2.33.2 → 2.34.0
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/meeting/index.js +13 -3
- package/dist/meeting/index.js.map +1 -1
- package/dist/roap/turnDiscovery.js +16 -4
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/package.json +17 -17
- package/src/meeting/index.js +15 -3
- package/src/roap/turnDiscovery.ts +4 -4
- package/test/unit/spec/meeting/index.js +56 -4
- package/test/unit/spec/roap/turnDiscovery.ts +36 -20
|
@@ -240,13 +240,19 @@ var TurnDiscovery = /*#__PURE__*/function () {
|
|
|
240
240
|
if (isAnyClusterReachable) {
|
|
241
241
|
_loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');
|
|
242
242
|
|
|
243
|
-
return _promise.default.resolve(
|
|
243
|
+
return _promise.default.resolve({
|
|
244
|
+
turnServerInfo: undefined,
|
|
245
|
+
turnDiscoverySkippedReason: 'reachability'
|
|
246
|
+
});
|
|
244
247
|
}
|
|
245
248
|
|
|
246
249
|
if (!meeting.config.experimental.enableTurnDiscovery) {
|
|
247
250
|
_loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');
|
|
248
251
|
|
|
249
|
-
return _promise.default.resolve(
|
|
252
|
+
return _promise.default.resolve({
|
|
253
|
+
turnServerInfo: undefined,
|
|
254
|
+
turnDiscoverySkippedReason: 'config'
|
|
255
|
+
});
|
|
250
256
|
}
|
|
251
257
|
|
|
252
258
|
return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting).then(function () {
|
|
@@ -258,7 +264,10 @@ var TurnDiscovery = /*#__PURE__*/function () {
|
|
|
258
264
|
|
|
259
265
|
_loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
|
|
260
266
|
|
|
261
|
-
return
|
|
267
|
+
return {
|
|
268
|
+
turnServerInfo: _this2.turnInfo,
|
|
269
|
+
turnDiscoverySkippedReason: undefined
|
|
270
|
+
};
|
|
262
271
|
}).catch(function (e) {
|
|
263
272
|
// we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
|
|
264
273
|
_loggerProxy.default.logger.info("Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ".concat(e));
|
|
@@ -270,7 +279,10 @@ var TurnDiscovery = /*#__PURE__*/function () {
|
|
|
270
279
|
stack: e.stack
|
|
271
280
|
});
|
|
272
281
|
|
|
273
|
-
return _promise.default.resolve(
|
|
282
|
+
return _promise.default.resolve({
|
|
283
|
+
turnServerInfo: undefined,
|
|
284
|
+
turnDiscoverySkippedReason: undefined
|
|
285
|
+
});
|
|
274
286
|
});
|
|
275
287
|
}
|
|
276
288
|
}]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TURN_DISCOVERY_TIMEOUT","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","seq","roapSeq","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","sendRoap","correlationId","locusSelfUrl","selfUrl","mediaId","audioMuted","isAudioMuted","videoMuted","isVideoMuted","meetingId","id","then","mediaConnections","setRoapSeq","updateMediaConnections","OK","isAnyClusterReachable","webex","meetings","reachability","config","experimental","enableTurnDiscovery","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["import {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';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\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 /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress');\n\n return Promise.reject(new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()'));\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(`Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`);\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...');\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 handleTurnDiscoveryResponse(roapMessage) {\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response');\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(expectedHeader.headerName.length + 1);\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(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(headers)}`);\n this.defer.reject(new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`));\n }\n else {\n LoggerProxy.logger.info(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`);\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, isReconnecting) {\n const seq = meeting.roapSeq + 1;\n\n if (this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress');\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,\n };\n\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n correlationId: meeting.correlationId,\n locusSelfUrl: meeting.selfUrl,\n mediaId: isReconnecting ? '' : meeting.mediaId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n })\n .then(({mediaConnections}) => {\n meeting.setRoapSeq(seq);\n\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) {\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: meeting.roapSeq\n },\n locusSelfUrl: meeting.selfUrl,\n mediaId: meeting.mediaId,\n correlationId: meeting.correlationId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n });\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 * @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 doTurnDiscovery(meeting, isReconnecting) {\n const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');\n return Promise.resolve(undefined);\n }\n\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');\n\n return Promise.resolve(undefined);\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 this.turnInfo;\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(`Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`);\n\n Metrics.sendBehavioralMetric(\n BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE,\n {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack\n }\n );\n\n return Promise.resolve(undefined);\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;;AAEA;;AACA;;AACA;;AACA;;AAIA,IAAMA,sBAAsB,GAAG,EAA/B,C,CAAmC;;AAEnC;AACA;AACA;AACA;;IACqBC,a;EAGI;;EAUvB;AACF;AACA;AACA;AACA;EACE,uBAAYC,WAAZ,EAAsC;IAAA;IAAA;IAAA;IAAA;IAAA;IACpC,KAAKA,WAAL,GAAmBA,WAAnB;IACA,KAAKC,QAAL,GAAgB;MACdC,GAAG,EAAE,EADS;MAEdC,QAAQ,EAAE,EAFI;MAGdC,QAAQ,EAAE;IAHI,CAAhB;EAKD;EAGD;AACF;AACA;AACA;AACA;AACA;AACA;;;;;WACE,wCAA+B;MAC7B,IAAI,CAAC,KAAKC,KAAV,EAAiB;QACfC,oBAAA,CAAYC,MAAZ,CAAmBC,IAAnB,CAAwB,uFAAxB;;QAEA,OAAO,iBAAQC,MAAR,CAAe,IAAIC,KAAJ,CAAU,6EAAV,CAAf,CAAP;MACD;;MAED,IAAOL,KAAP,GAAgB,IAAhB,CAAOA,KAAP;MAEA,KAAKM,aAAL,GAAqBC,UAAU,CAAC,YAAM;QACpCN,oBAAA,CAAYC,MAAZ,CAAmBC,IAAnB,mGAAmHV,sBAAnH;;QAEAO,KAAK,CAACI,MAAN,CAAa,IAAIC,KAAJ,CAAU,+CAAV,CAAb;MACD,CAJ8B,EAI5BZ,sBAAsB,GAAG,IAJG,CAA/B;;MAMAQ,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,4FAAxB;;MAEA,OAAOR,KAAK,CAACS,OAAb;IACD;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;;;;WACE,qCAA4BC,WAA5B,EAAyC;MAAA;;MACvC,IAAOC,OAAP,GAAkBD,WAAlB,CAAOC,OAAP;;MAEA,IAAI,CAAC,KAAKX,KAAV,EAAiB;QACfC,oBAAA,CAAYC,MAAZ,CAAmBC,IAAnB,CAAwB,uFAAxB;;QAEA;MACD;;MAED,IAAMS,eAAe,GAAG,CACtB;QAACC,UAAU,EAAE,kBAAb;QAAiCC,KAAK,EAAE;MAAxC,CADsB,EAEtB;QAACD,UAAU,EAAE,uBAAb;QAAsCC,KAAK,EAAE;MAA7C,CAFsB,EAGtB;QAACD,UAAU,EAAE,uBAAb;QAAsCC,KAAK,EAAE;MAA7C,CAHsB,CAAxB;MAMA,IAAIC,YAAY,GAAG,CAAnB;MAEAJ,OAAO,SAAP,IAAAA,OAAO,WAAP,YAAAA,OAAO,CAAEK,OAAT,CAAiB,UAACC,cAAD,EAAoB;QACnC;QACAL,eAAe,CAACI,OAAhB,CAAwB,UAACE,cAAD,EAAoB;UAC1C,IAAID,cAAc,CAACE,UAAf,WAA6BD,cAAc,CAACL,UAA5C,OAAJ,EAAgE;YAC9D,KAAI,CAACjB,QAAL,CAAcsB,cAAc,CAACJ,KAA7B,IAAsCG,cAAc,CAACG,SAAf,CAAyBF,cAAc,CAACL,UAAf,CAA0BQ,MAA1B,GAAmC,CAA5D,CAAtC;YACAN,YAAY,IAAI,CAAhB;UACD;QACF,CALD;MAMD,CARD;MAUAO,YAAY,CAAC,KAAKhB,aAAN,CAAZ;MACA,KAAKA,aAAL,GAAqBiB,SAArB;;MAEA,IAAIR,YAAY,KAAKH,eAAe,CAACS,MAArC,EAA6C;QAC3CpB,oBAAA,CAAYC,MAAZ,CAAmBC,IAAnB,8FAA8G,wBAAeQ,OAAf,CAA9G;;QACA,KAAKX,KAAL,CAAWI,MAAX,CAAkB,IAAIC,KAAJ,yDAA2D,wBAAeM,OAAf,CAA3D,EAAlB;MACD,CAHD,MAIK;QACHV,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,6FAA6G,KAAKZ,QAAL,CAAcC,GAA3H;;QACA,KAAKG,KAAL,CAAWwB,OAAX;MACD;IACF;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;WACE,sCAA6BC,OAA7B,EAAsCC,cAAtC,EAAsD;MACpD,IAAMC,GAAG,GAAGF,OAAO,CAACG,OAAR,GAAkB,CAA9B;;MAEA,IAAI,KAAK5B,KAAT,EAAgB;QACdC,oBAAA,CAAYC,MAAZ,CAAmBC,IAAnB,CAAwB,yEAAxB;;QAEA,OAAO,iBAAQqB,OAAR,EAAP;MACD;;MAED,KAAKxB,KAAL,GAAa,IAAI6B,aAAJ,EAAb;MAEA,IAAMnB,WAAW,GAAG;QAClBoB,WAAW,EAAEC,gBAAA,CAAKC,UAAL,CAAgBC,sBADX;QAElBC,OAAO,EAAEH,gBAAA,CAAKI,YAFI;QAGlBR,GAAG,EAAHA;MAHkB,CAApB;;MAMA1B,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,oFAAxB;;MAEA,OAAO,KAAKb,WAAL,CACJyC,QADI,CACK;QACR1B,WAAW,EAAXA,WADQ;QAER2B,aAAa,EAAEZ,OAAO,CAACY,aAFf;QAGRC,YAAY,EAAEb,OAAO,CAACc,OAHd;QAIRC,OAAO,EAAEd,cAAc,GAAG,EAAH,GAAQD,OAAO,CAACe,OAJ/B;QAKRC,UAAU,EAAEhB,OAAO,CAACiB,YAAR,EALJ;QAMRC,UAAU,EAAElB,OAAO,CAACmB,YAAR,EANJ;QAORC,SAAS,EAAEpB,OAAO,CAACqB;MAPX,CADL,EAUJC,IAVI,CAUC,gBAAwB;QAAA,IAAtBC,gBAAsB,QAAtBA,gBAAsB;QAC5BvB,OAAO,CAACwB,UAAR,CAAmBtB,GAAnB;;QAEA,IAAIqB,gBAAJ,EAAsB;UACpBvB,OAAO,CAACyB,sBAAR,CAA+BF,gBAA/B;QACD;MACF,CAhBI,CAAP;IAiBD;IAED;AACF;AACA;AACA;AACA;AACA;AACA;;;;WACE,oBAAWvB,OAAX,EAAoB;MAClBxB,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,8CAAxB;;MAEA,OAAO,KAAKb,WAAL,CAAiByC,QAAjB,CAA0B;QAC/B1B,WAAW,EAAE;UACXoB,WAAW,EAAEC,gBAAA,CAAKC,UAAL,CAAgBmB,EADlB;UAEXjB,OAAO,EAAEH,gBAAA,CAAKI,YAFH;UAGXR,GAAG,EAAEF,OAAO,CAACG;QAHF,CADkB;QAM/BU,YAAY,EAAEb,OAAO,CAACc,OANS;QAO/BC,OAAO,EAAEf,OAAO,CAACe,OAPc;QAQ/BH,aAAa,EAAEZ,OAAO,CAACY,aARQ;QAS/BI,UAAU,EAAEhB,OAAO,CAACiB,YAAR,EATmB;QAU/BC,UAAU,EAAElB,OAAO,CAACmB,YAAR,EAVmB;QAW/BC,SAAS,EAAEpB,OAAO,CAACqB;MAXY,CAA1B,CAAP;IAaD;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;WACE,yBAAgBrB,OAAhB,EAAyBC,cAAzB,EAAyC;MAAA;;MACvC,IAAM0B,qBAAqB,GAAG3B,OAAO,CAAC4B,KAAR,CAAcC,QAAd,CAAuBC,YAAvB,CAAoCH,qBAApC,EAA9B;;MAEA,IAAIA,qBAAJ,EAA2B;QACzBnD,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,6FAAxB;;QACA,OAAO,iBAAQgB,OAAR,CAAgBD,SAAhB,CAAP;MACD;;MAED,IAAI,CAACE,OAAO,CAAC+B,MAAR,CAAeC,YAAf,CAA4BC,mBAAjC,EAAsD;QACpDzD,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,uFAAxB;;QAEA,OAAO,iBAAQgB,OAAR,CAAgBD,SAAhB,CAAP;MACD;;MAED,OAAO,KAAKoC,4BAAL,CAAkClC,OAAlC,EAA2CC,cAA3C,EACJqB,IADI,CACC;QAAA,OAAM,MAAI,CAACa,4BAAL,EAAN;MAAA,CADD,EAEJb,IAFI,CAEC;QAAA,OAAM,MAAI,CAACc,UAAL,CAAgBpC,OAAhB,CAAN;MAAA,CAFD,EAGJsB,IAHI,CAGC,YAAM;QACV,MAAI,CAAC/C,KAAL,GAAauB,SAAb;;QAEAtB,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,CAAwB,iEAAxB;;QAEA,OAAO,MAAI,CAACZ,QAAZ;MACD,CATI,EAUJkE,KAVI,CAUE,UAACC,CAAD,EAAO;QACZ;QACA9D,oBAAA,CAAYC,MAAZ,CAAmBM,IAAnB,kGAAkHuD,CAAlH;;QAEAC,gBAAA,CAAQC,oBAAR,CACEC,kBAAA,CAAmBC,sBADrB,EAEE;UACEC,cAAc,EAAE3C,OAAO,CAACY,aAD1B;UAEEgC,QAAQ,EAAE5C,OAAO,CAAC6C,QAAR,CAAiBC,KAAjB,CAAuB,GAAvB,EAA4BC,GAA5B,EAFZ;UAGEC,MAAM,EAAEV,CAAC,CAACW,OAHZ;UAIEC,KAAK,EAAEZ,CAAC,CAACY;QAJX,CAFF;;QAUA,OAAO,iBAAQnD,OAAR,CAAgBD,SAAhB,CAAP;MACD,CAzBI,CAAP;IA0BD"}
|
|
1
|
+
{"version":3,"names":["TURN_DISCOVERY_TIMEOUT","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","seq","roapSeq","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","sendRoap","correlationId","locusSelfUrl","selfUrl","mediaId","audioMuted","isAudioMuted","videoMuted","isVideoMuted","meetingId","id","then","mediaConnections","setRoapSeq","updateMediaConnections","OK","isAnyClusterReachable","webex","meetings","reachability","turnServerInfo","turnDiscoverySkippedReason","config","experimental","enableTurnDiscovery","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["import {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';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\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 /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress');\n\n return Promise.reject(new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()'));\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(`Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`);\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...');\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 handleTurnDiscoveryResponse(roapMessage) {\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response');\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(expectedHeader.headerName.length + 1);\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(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(headers)}`);\n this.defer.reject(new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`));\n }\n else {\n LoggerProxy.logger.info(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`);\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, isReconnecting) {\n const seq = meeting.roapSeq + 1;\n\n if (this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress');\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,\n };\n\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n correlationId: meeting.correlationId,\n locusSelfUrl: meeting.selfUrl,\n mediaId: isReconnecting ? '' : meeting.mediaId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n })\n .then(({mediaConnections}) => {\n meeting.setRoapSeq(seq);\n\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) {\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: meeting.roapSeq\n },\n locusSelfUrl: meeting.selfUrl,\n mediaId: meeting.mediaId,\n correlationId: meeting.correlationId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n });\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 * @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 doTurnDiscovery(meeting, isReconnecting) {\n const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'reachability'});\n }\n\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');\n\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});\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(`Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`);\n\n Metrics.sendBehavioralMetric(\n BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE,\n {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack\n }\n );\n\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});\n });\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/plugin-meetings",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.34.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
|
|
6
6
|
"contributors": [
|
|
@@ -24,30 +24,30 @@
|
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@webex/plugin-meetings": "2.
|
|
28
|
-
"@webex/test-helper-chai": "2.
|
|
29
|
-
"@webex/test-helper-mocha": "2.
|
|
30
|
-
"@webex/test-helper-mock-webex": "2.
|
|
31
|
-
"@webex/test-helper-retry": "2.
|
|
32
|
-
"@webex/test-helper-test-users": "2.
|
|
27
|
+
"@webex/plugin-meetings": "2.34.0",
|
|
28
|
+
"@webex/test-helper-chai": "2.34.0",
|
|
29
|
+
"@webex/test-helper-mocha": "2.34.0",
|
|
30
|
+
"@webex/test-helper-mock-webex": "2.34.0",
|
|
31
|
+
"@webex/test-helper-retry": "2.34.0",
|
|
32
|
+
"@webex/test-helper-test-users": "2.34.0",
|
|
33
33
|
"chai": "^4.3.4",
|
|
34
34
|
"chai-as-promised": "^7.1.1",
|
|
35
35
|
"jsdom-global": "3.0.2",
|
|
36
36
|
"sinon": "^9.2.4"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@webex/common": "2.
|
|
39
|
+
"@webex/common": "2.34.0",
|
|
40
40
|
"@webex/internal-media-core": "^0.0.7-beta",
|
|
41
|
-
"@webex/internal-plugin-conversation": "2.
|
|
42
|
-
"@webex/internal-plugin-device": "2.
|
|
43
|
-
"@webex/internal-plugin-mercury": "2.
|
|
44
|
-
"@webex/internal-plugin-metrics": "2.
|
|
45
|
-
"@webex/internal-plugin-support": "2.
|
|
46
|
-
"@webex/internal-plugin-user": "2.
|
|
47
|
-
"@webex/plugin-people": "2.
|
|
48
|
-
"@webex/plugin-rooms": "2.
|
|
41
|
+
"@webex/internal-plugin-conversation": "2.34.0",
|
|
42
|
+
"@webex/internal-plugin-device": "2.34.0",
|
|
43
|
+
"@webex/internal-plugin-mercury": "2.34.0",
|
|
44
|
+
"@webex/internal-plugin-metrics": "2.34.0",
|
|
45
|
+
"@webex/internal-plugin-support": "2.34.0",
|
|
46
|
+
"@webex/internal-plugin-user": "2.34.0",
|
|
47
|
+
"@webex/plugin-people": "2.34.0",
|
|
48
|
+
"@webex/plugin-rooms": "2.34.0",
|
|
49
49
|
"@webex/ts-sdp": "^1.0.1",
|
|
50
|
-
"@webex/webex-core": "2.
|
|
50
|
+
"@webex/webex-core": "2.34.0",
|
|
51
51
|
"bowser": "^2.11.0",
|
|
52
52
|
"btoa": "^1.2.1",
|
|
53
53
|
"dotenv": "^4.0.0",
|
package/src/meeting/index.js
CHANGED
|
@@ -4184,6 +4184,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4184
4184
|
addMedia(options = {}) {
|
|
4185
4185
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
4186
4186
|
|
|
4187
|
+
let turnDiscoverySkippedReason;
|
|
4188
|
+
let turnServerUsed = false;
|
|
4189
|
+
|
|
4187
4190
|
if (this.meetingState !== FULL_STATE.ACTIVE) {
|
|
4188
4191
|
return Promise.reject(new MeetingNotActiveError());
|
|
4189
4192
|
}
|
|
@@ -4225,7 +4228,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4225
4228
|
|
|
4226
4229
|
return MeetingUtil.validateOptions(options)
|
|
4227
4230
|
.then(() => this.roap.doTurnDiscovery(this, false))
|
|
4228
|
-
.then((
|
|
4231
|
+
.then((turnDiscoveryObject) => {
|
|
4232
|
+
({turnDiscoverySkippedReason} = turnDiscoveryObject);
|
|
4233
|
+
turnServerUsed = !turnDiscoverySkippedReason;
|
|
4234
|
+
|
|
4235
|
+
const {turnServerInfo} = turnDiscoveryObject;
|
|
4236
|
+
|
|
4229
4237
|
this.mediaProperties.setMediaPeerConnection(MediaUtil.createPeerConnection(turnServerInfo));
|
|
4230
4238
|
this.setMercuryListener();
|
|
4231
4239
|
PeerConnectionManager.setPeerConnectionEvents(this);
|
|
@@ -4266,7 +4274,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4266
4274
|
correlation_id: this.correlationId,
|
|
4267
4275
|
locus_id: this.locusUrl.split('/').pop(),
|
|
4268
4276
|
reason: error.message,
|
|
4269
|
-
stack: error.stack
|
|
4277
|
+
stack: error.stack,
|
|
4278
|
+
turnDiscoverySkippedReason,
|
|
4279
|
+
turnServerUsed
|
|
4270
4280
|
}
|
|
4271
4281
|
);
|
|
4272
4282
|
|
|
@@ -4376,7 +4386,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4376
4386
|
locus_id: this.locusUrl.split('/').pop(),
|
|
4377
4387
|
reason: error.message,
|
|
4378
4388
|
stack: error.stack,
|
|
4379
|
-
code: error.code
|
|
4389
|
+
code: error.code,
|
|
4390
|
+
turnDiscoverySkippedReason,
|
|
4391
|
+
turnServerUsed
|
|
4380
4392
|
}
|
|
4381
4393
|
);
|
|
4382
4394
|
|
|
@@ -206,13 +206,13 @@ export default class TurnDiscovery {
|
|
|
206
206
|
|
|
207
207
|
if (isAnyClusterReachable) {
|
|
208
208
|
LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');
|
|
209
|
-
return Promise.resolve(undefined);
|
|
209
|
+
return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'reachability'});
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
if (!meeting.config.experimental.enableTurnDiscovery) {
|
|
213
213
|
LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');
|
|
214
214
|
|
|
215
|
-
return Promise.resolve(undefined);
|
|
215
|
+
return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)
|
|
@@ -223,7 +223,7 @@ export default class TurnDiscovery {
|
|
|
223
223
|
|
|
224
224
|
LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
|
|
225
225
|
|
|
226
|
-
return this.turnInfo;
|
|
226
|
+
return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};
|
|
227
227
|
})
|
|
228
228
|
.catch((e) => {
|
|
229
229
|
// we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
|
|
@@ -239,7 +239,7 @@ export default class TurnDiscovery {
|
|
|
239
239
|
}
|
|
240
240
|
);
|
|
241
241
|
|
|
242
|
-
return Promise.resolve(undefined);
|
|
242
|
+
return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
|
|
243
243
|
});
|
|
244
244
|
}
|
|
245
245
|
}
|
|
@@ -920,7 +920,7 @@ describe('plugin-meetings', () => {
|
|
|
920
920
|
meeting.mediaProperties.peerConnection.connectionState = CONSTANTS.CONNECTION_STATE.CONNECTED;
|
|
921
921
|
resolve();
|
|
922
922
|
}));
|
|
923
|
-
meeting.roap.doTurnDiscovery = sinon.stub().resolves();
|
|
923
|
+
meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: {}, turnDiscoverySkippedReason: undefined});
|
|
924
924
|
PeerConnectionManager.setContentSlides = sinon.stub().returns(true);
|
|
925
925
|
});
|
|
926
926
|
|
|
@@ -961,6 +961,39 @@ describe('plugin-meetings', () => {
|
|
|
961
961
|
await meeting.addMedia().catch((err) => {
|
|
962
962
|
assert.exists(err);
|
|
963
963
|
assert.isNull(meeting.statsAnalyzer);
|
|
964
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
965
|
+
assert.calledWith(
|
|
966
|
+
Metrics.sendBehavioralMetric,
|
|
967
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
|
968
|
+
correlation_id: meeting.correlationId,
|
|
969
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
970
|
+
reason: err.message,
|
|
971
|
+
stack: err.stack,
|
|
972
|
+
code: err.code,
|
|
973
|
+
turnDiscoverySkippedReason: undefined,
|
|
974
|
+
turnServerUsed: true
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
});
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
it('checks metrics called with skipped reason config', async () => {
|
|
981
|
+
meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});
|
|
982
|
+
meeting.meetingState = 'ACTIVE';
|
|
983
|
+
await meeting.addMedia().catch((err) => {
|
|
984
|
+
assert.exists(err);
|
|
985
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
986
|
+
assert.calledWith(
|
|
987
|
+
Metrics.sendBehavioralMetric,
|
|
988
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
|
989
|
+
correlation_id: meeting.correlationId,
|
|
990
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
991
|
+
reason: err.message,
|
|
992
|
+
stack: err.stack,
|
|
993
|
+
turnDiscoverySkippedReason: 'config',
|
|
994
|
+
turnServerUsed: false
|
|
995
|
+
}
|
|
996
|
+
);
|
|
964
997
|
});
|
|
965
998
|
});
|
|
966
999
|
|
|
@@ -970,6 +1003,18 @@ describe('plugin-meetings', () => {
|
|
|
970
1003
|
await meeting.addMedia().catch((err) => {
|
|
971
1004
|
assert.exists(err);
|
|
972
1005
|
assert.isNull(meeting.mediaProperties.peerConnection);
|
|
1006
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
1007
|
+
assert.calledWith(
|
|
1008
|
+
Metrics.sendBehavioralMetric,
|
|
1009
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
|
1010
|
+
correlation_id: meeting.correlationId,
|
|
1011
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
1012
|
+
reason: err.message,
|
|
1013
|
+
stack: err.stack,
|
|
1014
|
+
turnDiscoverySkippedReason: undefined,
|
|
1015
|
+
turnServerUsed: true
|
|
1016
|
+
}
|
|
1017
|
+
);
|
|
973
1018
|
});
|
|
974
1019
|
});
|
|
975
1020
|
|
|
@@ -1035,6 +1080,8 @@ describe('plugin-meetings', () => {
|
|
|
1035
1080
|
});
|
|
1036
1081
|
|
|
1037
1082
|
it('should attach the media and return promise', async () => {
|
|
1083
|
+
meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
|
|
1084
|
+
|
|
1038
1085
|
meeting.meetingState = 'ACTIVE';
|
|
1039
1086
|
MediaUtil.createPeerConnection.resetHistory();
|
|
1040
1087
|
const media = meeting.addMedia({
|
|
@@ -1065,10 +1112,14 @@ describe('plugin-meetings', () => {
|
|
|
1065
1112
|
meeting.meetingState = 'ACTIVE';
|
|
1066
1113
|
MediaUtil.createPeerConnection.resetHistory();
|
|
1067
1114
|
|
|
1115
|
+
|
|
1068
1116
|
meeting.roap.doTurnDiscovery = sinon.stub().resolves({
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1117
|
+
turnServerInfo: {
|
|
1118
|
+
url: FAKE_TURN_URL,
|
|
1119
|
+
username: FAKE_TURN_USER,
|
|
1120
|
+
password: FAKE_TURN_PASSWORD
|
|
1121
|
+
},
|
|
1122
|
+
turnServerSkippedReason: undefined
|
|
1072
1123
|
});
|
|
1073
1124
|
const media = meeting.addMedia({
|
|
1074
1125
|
mediaSettings: {}
|
|
@@ -1087,6 +1138,7 @@ describe('plugin-meetings', () => {
|
|
|
1087
1138
|
});
|
|
1088
1139
|
|
|
1089
1140
|
it('should attach the media and return promise', async () => {
|
|
1141
|
+
meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
|
|
1090
1142
|
meeting.meetingState = 'ACTIVE';
|
|
1091
1143
|
meeting.mediaProperties.peerConnection.connectionState = 'DISCONNECTED';
|
|
1092
1144
|
const media = meeting.addMedia({
|
|
@@ -117,14 +117,15 @@ describe('TurnDiscovery', () => {
|
|
|
117
117
|
// check that we've sent OK
|
|
118
118
|
await checkRoapMessageSent('OK', 0);
|
|
119
119
|
|
|
120
|
-
const
|
|
120
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await result;
|
|
121
121
|
|
|
122
|
-
assert.deepEqual(
|
|
122
|
+
assert.deepEqual(turnServerInfo, {
|
|
123
123
|
url: FAKE_TURN_URL,
|
|
124
124
|
username: FAKE_TURN_USERNAME,
|
|
125
125
|
password: FAKE_TURN_PASSWORD
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
128
129
|
});
|
|
129
130
|
|
|
130
131
|
it('sends TURN_DISCOVERY_REQUEST with empty mediaId when isReconnecting is true', async () => {
|
|
@@ -152,13 +153,14 @@ describe('TurnDiscovery', () => {
|
|
|
152
153
|
// check that we've sent OK
|
|
153
154
|
await checkRoapMessageSent('OK', 0);
|
|
154
155
|
|
|
155
|
-
const
|
|
156
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await result;
|
|
156
157
|
|
|
157
|
-
assert.deepEqual(
|
|
158
|
+
assert.deepEqual(turnServerInfo, {
|
|
158
159
|
url: FAKE_TURN_URL,
|
|
159
160
|
username: FAKE_TURN_USERNAME,
|
|
160
161
|
password: FAKE_TURN_PASSWORD
|
|
161
162
|
});
|
|
163
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
162
164
|
});
|
|
163
165
|
|
|
164
166
|
it('ignores any extra, unexpected headers in the response', async () => {
|
|
@@ -187,13 +189,13 @@ describe('TurnDiscovery', () => {
|
|
|
187
189
|
// check that we've sent OK and still parsed the headers we care about
|
|
188
190
|
await checkRoapMessageSent('OK', 0);
|
|
189
191
|
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
assert.deepEqual(turnInfo, {
|
|
192
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await result;
|
|
193
|
+
assert.deepEqual(turnServerInfo, {
|
|
193
194
|
url: FAKE_TURN_URL,
|
|
194
195
|
username: FAKE_TURN_USERNAME,
|
|
195
196
|
password: FAKE_TURN_PASSWORD
|
|
196
197
|
});
|
|
198
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
197
199
|
});
|
|
198
200
|
|
|
199
201
|
it('resolves with undefined if turn discovery feature is disabled in config', async () => {
|
|
@@ -203,7 +205,10 @@ describe('TurnDiscovery', () => {
|
|
|
203
205
|
|
|
204
206
|
const result = await new TurnDiscovery(mockRoapRequest).doTurnDiscovery(testMeeting);
|
|
205
207
|
|
|
206
|
-
|
|
208
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = result;
|
|
209
|
+
|
|
210
|
+
assert.isUndefined(turnServerInfo);
|
|
211
|
+
assert.equal(turnDiscoverySkippedReason, 'config');
|
|
207
212
|
assert.notCalled(mockRoapRequest.sendRoap);
|
|
208
213
|
assert.notCalled(Metrics.sendBehavioralMetric);
|
|
209
214
|
|
|
@@ -218,7 +223,10 @@ describe('TurnDiscovery', () => {
|
|
|
218
223
|
|
|
219
224
|
const result = await td.doTurnDiscovery(testMeeting, false);
|
|
220
225
|
|
|
221
|
-
|
|
226
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = result;
|
|
227
|
+
|
|
228
|
+
assert.isUndefined(turnServerInfo);
|
|
229
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
222
230
|
checkFailureMetricsSent();
|
|
223
231
|
});
|
|
224
232
|
|
|
@@ -227,7 +235,10 @@ describe('TurnDiscovery', () => {
|
|
|
227
235
|
testMeeting.webex.meetings.reachability.isAnyClusterReachable = () => true;
|
|
228
236
|
const result = await new TurnDiscovery(mockRoapRequest).doTurnDiscovery(testMeeting);
|
|
229
237
|
|
|
230
|
-
|
|
238
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = result;
|
|
239
|
+
|
|
240
|
+
assert.isUndefined(turnServerInfo);
|
|
241
|
+
assert.equal(turnDiscoverySkippedReason, 'reachability');
|
|
231
242
|
assert.notCalled(mockRoapRequest.sendRoap);
|
|
232
243
|
assert.notCalled(Metrics.sendBehavioralMetric);
|
|
233
244
|
testMeeting.webex.meetings.reachability.isAnyClusterReachable = prev;
|
|
@@ -242,9 +253,10 @@ describe('TurnDiscovery', () => {
|
|
|
242
253
|
await clock.tickAsync(10 * 1000);
|
|
243
254
|
await testUtils.flushPromises();
|
|
244
255
|
|
|
245
|
-
const
|
|
256
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await promise;
|
|
246
257
|
|
|
247
|
-
assert.isUndefined(
|
|
258
|
+
assert.isUndefined(turnServerInfo);
|
|
259
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
248
260
|
checkFailureMetricsSent();
|
|
249
261
|
});
|
|
250
262
|
|
|
@@ -260,9 +272,10 @@ describe('TurnDiscovery', () => {
|
|
|
260
272
|
]
|
|
261
273
|
});
|
|
262
274
|
await testUtils.flushPromises();
|
|
263
|
-
const
|
|
275
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
|
|
264
276
|
|
|
265
|
-
assert.isUndefined(
|
|
277
|
+
assert.isUndefined(turnServerInfo);
|
|
278
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
266
279
|
checkFailureMetricsSent();
|
|
267
280
|
});
|
|
268
281
|
|
|
@@ -274,9 +287,10 @@ describe('TurnDiscovery', () => {
|
|
|
274
287
|
td.handleTurnDiscoveryResponse({});
|
|
275
288
|
|
|
276
289
|
await testUtils.flushPromises();
|
|
277
|
-
const
|
|
290
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
|
|
278
291
|
|
|
279
|
-
assert.isUndefined(
|
|
292
|
+
assert.isUndefined(turnServerInfo);
|
|
293
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
280
294
|
checkFailureMetricsSent();
|
|
281
295
|
});
|
|
282
296
|
|
|
@@ -288,9 +302,10 @@ describe('TurnDiscovery', () => {
|
|
|
288
302
|
td.handleTurnDiscoveryResponse({headers: []});
|
|
289
303
|
|
|
290
304
|
await testUtils.flushPromises();
|
|
291
|
-
const
|
|
305
|
+
const {turnServerInfo, turnDiscoverySkippedReason}= await turnDiscoveryPromise;
|
|
292
306
|
|
|
293
|
-
assert.isUndefined(
|
|
307
|
+
assert.isUndefined(turnServerInfo);
|
|
308
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
294
309
|
checkFailureMetricsSent();
|
|
295
310
|
});
|
|
296
311
|
|
|
@@ -321,9 +336,10 @@ describe('TurnDiscovery', () => {
|
|
|
321
336
|
// check that we've sent OK
|
|
322
337
|
await checkRoapMessageSent('OK', 0);
|
|
323
338
|
|
|
324
|
-
const
|
|
339
|
+
const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
|
|
325
340
|
|
|
326
|
-
assert.isUndefined(
|
|
341
|
+
assert.isUndefined(turnServerInfo);
|
|
342
|
+
assert.isUndefined(turnDiscoverySkippedReason);
|
|
327
343
|
checkFailureMetricsSent();
|
|
328
344
|
});
|
|
329
345
|
});
|