@webex/plugin-meetings 3.0.0-beta.367 → 3.0.0-beta.368

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.
@@ -209,7 +209,7 @@ var Breakout = _webexCore.WebexPlugin.extend({
209
209
  sessionId: this.sessionId
210
210
  });
211
211
  },
212
- version: "3.0.0-beta.367"
212
+ version: "3.0.0-beta.368"
213
213
  });
214
214
  var _default = Breakout;
215
215
  exports.default = _default;
@@ -1041,7 +1041,7 @@ var Breakouts = _webexCore.WebexPlugin.extend({
1041
1041
  this.trigger(_constants.BREAKOUTS.EVENTS.ASK_RETURN_TO_MAIN);
1042
1042
  }
1043
1043
  },
1044
- version: "3.0.0-beta.367"
1044
+ version: "3.0.0-beta.368"
1045
1045
  });
1046
1046
  var _default = Breakouts;
1047
1047
  exports.default = _default;
@@ -359,7 +359,7 @@ var SimultaneousInterpretation = _webexCore.WebexPlugin.extend({
359
359
  throw error;
360
360
  });
361
361
  },
362
- version: "3.0.0-beta.367"
362
+ version: "3.0.0-beta.368"
363
363
  });
364
364
  var _default = SimultaneousInterpretation;
365
365
  exports.default = _default;
@@ -18,7 +18,7 @@ var SILanguage = _webexCore.WebexPlugin.extend({
18
18
  languageCode: 'number',
19
19
  languageName: 'string'
20
20
  },
21
- version: "3.0.0-beta.367"
21
+ version: "3.0.0-beta.368"
22
22
  });
23
23
  var _default = SILanguage;
24
24
  exports.default = _default;
@@ -66,41 +66,35 @@ var Reachability = /*#__PURE__*/function () {
66
66
  return _regenerator.default.wrap(function _callee$(_context) {
67
67
  while (1) switch (_context.prev = _context.next) {
68
68
  case 0:
69
- _context.next = 2;
70
- return this.webex.boundedStorage.del(this.namespace, _constants.REACHABILITY.localStorageResult);
71
- case 2:
72
- _context.next = 4;
73
- return this.webex.boundedStorage.del(this.namespace, _constants.REACHABILITY.localStorageJoinCookie);
74
- case 4:
75
- _context.prev = 4;
76
- _context.next = 7;
69
+ _context.prev = 0;
70
+ _context.next = 3;
77
71
  return this.reachabilityRequest.getClusters(_util.default.getIpVersion(this.webex));
78
- case 7:
72
+ case 3:
79
73
  _yield$this$reachabil = _context.sent;
80
74
  clusters = _yield$this$reachabil.clusters;
81
75
  joinCookie = _yield$this$reachabil.joinCookie;
82
- _context.next = 12;
76
+ _context.next = 8;
83
77
  return this.performReachabilityChecks(clusters);
84
- case 12:
78
+ case 8:
85
79
  results = _context.sent;
86
- _context.next = 15;
80
+ _context.next = 11;
87
81
  return this.webex.boundedStorage.put(this.namespace, _constants.REACHABILITY.localStorageResult, (0, _stringify.default)(results));
88
- case 15:
89
- _context.next = 17;
82
+ case 11:
83
+ _context.next = 13;
90
84
  return this.webex.boundedStorage.put(this.namespace, _constants.REACHABILITY.localStorageJoinCookie, (0, _stringify.default)(joinCookie));
91
- case 17:
85
+ case 13:
92
86
  _loggerProxy.default.logger.log('Reachability:index#gatherReachability --> Reachability checks completed');
93
87
  return _context.abrupt("return", results);
94
- case 21:
95
- _context.prev = 21;
96
- _context.t0 = _context["catch"](4);
88
+ case 17:
89
+ _context.prev = 17;
90
+ _context.t0 = _context["catch"](0);
97
91
  _loggerProxy.default.logger.error("Reachability:index#gatherReachability --> Error:", _context.t0);
98
92
  return _context.abrupt("return", {});
99
- case 25:
93
+ case 21:
100
94
  case "end":
101
95
  return _context.stop();
102
96
  }
103
- }, _callee, this, [[4, 21]]);
97
+ }, _callee, this, [[0, 17]]);
104
98
  }));
105
99
  function gatherReachability() {
106
100
  return _gatherReachability.apply(this, arguments);
@@ -1 +1 @@
1
- {"version":3,"names":["Reachability","webex","REACHABILITY","namespace","reachabilityRequest","ReachabilityRequest","clusterReachability","boundedStorage","del","localStorageResult","localStorageJoinCookie","getClusters","MeetingUtil","getIpVersion","clusters","joinCookie","performReachabilityChecks","results","put","LoggerProxy","logger","log","error","stats","reachability_public_udp_success","reachability_public_udp_failed","reachability_public_tcp_success","reachability_public_tcp_failed","reachability_vmn_udp_success","reachability_vmn_udp_failed","reachability_vmn_tcp_success","reachability_vmn_tcp_failed","updateStats","clusterType","result","udp","outcome","tcp","get","resultsJson","JSON","parse","forEach","isVideoMesh","warn","transportResult","output","key","value","reachable","untested","latencyInMilliseconds","toString","allClusterResults","clusterResult","mapTransportResultToBackendDataFormat","xtls","catch","reachabilityData","reachabilityResults","some","e","unreachableList","getResult","push","name","protocol","list","getUnreachableClusters","clusterList","length","resolve","config","meetings","experimental","enableTcpReachability","clusterReachabilityChecks","map","cluster","includeTcpReachability","ClusterReachability","start","then","all","logUnreachableClusters"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-disable class-methods-use-this */\nimport {mapValues} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport MeetingUtil from '../meeting/util';\n\nimport {REACHABILITY} from '../constants';\n\nimport ReachabilityRequest, {ClusterList} from './request';\nimport {\n ClusterReachability,\n ClusterReachabilityResult,\n TransportResult,\n} from './clusterReachability';\n\nexport type ReachabilityMetrics = {\n reachability_public_udp_success: number;\n reachability_public_udp_failed: number;\n reachability_public_tcp_success: number;\n reachability_public_tcp_failed: number;\n reachability_vmn_udp_success: number;\n reachability_vmn_udp_failed: number;\n reachability_vmn_tcp_success: number;\n reachability_vmn_tcp_failed: number;\n};\n\n/**\n * This is the type that matches what backend expects us to send to them. It is a bit weird, because\n * it uses strings instead of booleans and numbers, but that's what they require.\n */\nexport type TransportResultForBackend = {\n reachable?: 'true' | 'false';\n latencyInMilliseconds?: string;\n clientMediaIPs?: string[];\n untested?: 'true';\n};\n\nexport type ReachabilityResultForBackend = {\n udp: TransportResultForBackend;\n tcp: TransportResultForBackend;\n xtls: TransportResultForBackend;\n};\n\n// this is the type that is required by the backend when we send them reachability results\nexport type ReachabilityResultsForBackend = Record<string, ReachabilityResultForBackend>;\n\n// this is the type used by Reachability class internally and stored in local storage\nexport type ReachabilityResults = Record<\n string,\n ClusterReachabilityResult & {\n isVideoMesh?: boolean;\n }\n>;\n\n/**\n * @class Reachability\n * @export\n */\nexport default class Reachability {\n namespace = REACHABILITY.namespace;\n webex: object;\n reachabilityRequest: ReachabilityRequest;\n clusterReachability: {\n [key: string]: ClusterReachability;\n };\n\n /**\n * Creates an instance of Reachability.\n * @param {object} webex\n * @memberof Reachability\n */\n constructor(webex: object) {\n this.webex = webex;\n\n /**\n * internal request object for the server\n * @instance\n * @type {Array}\n * @private\n * @memberof Reachability\n */\n this.reachabilityRequest = new ReachabilityRequest(this.webex);\n\n this.clusterReachability = {};\n }\n\n /**\n * Gets a list of media clusters from the backend and performs reachability checks on all the clusters\n * @returns {Promise<ReachabilityResults>} reachability results\n * @public\n * @memberof Reachability\n */\n public async gatherReachability(): Promise<ReachabilityResults> {\n // Remove stored reachability results to ensure no stale data\n // @ts-ignore\n await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageResult);\n // @ts-ignore\n await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageJoinCookie);\n\n // Fetch clusters and measure latency\n try {\n const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(\n MeetingUtil.getIpVersion(this.webex)\n );\n\n // Perform Reachability Check\n const results = await this.performReachabilityChecks(clusters);\n\n // @ts-ignore\n await this.webex.boundedStorage.put(\n this.namespace,\n REACHABILITY.localStorageResult,\n JSON.stringify(results)\n );\n // @ts-ignore\n await this.webex.boundedStorage.put(\n this.namespace,\n REACHABILITY.localStorageJoinCookie,\n JSON.stringify(joinCookie)\n );\n\n LoggerProxy.logger.log(\n 'Reachability:index#gatherReachability --> Reachability checks completed'\n );\n\n return results;\n } catch (error) {\n LoggerProxy.logger.error(`Reachability:index#gatherReachability --> Error:`, error);\n\n return {};\n }\n }\n\n /**\n * Returns statistics about last reachability results. The returned value is an object\n * with a flat list of properties so that it can be easily sent with metrics\n *\n * @returns {Promise} Promise with metrics values, it never rejects/throws.\n */\n async getReachabilityMetrics(): Promise<ReachabilityMetrics> {\n const stats: ReachabilityMetrics = {\n reachability_public_udp_success: 0,\n reachability_public_udp_failed: 0,\n reachability_public_tcp_success: 0,\n reachability_public_tcp_failed: 0,\n reachability_vmn_udp_success: 0,\n reachability_vmn_udp_failed: 0,\n reachability_vmn_tcp_success: 0,\n reachability_vmn_tcp_failed: 0,\n };\n\n const updateStats = (clusterType: 'public' | 'vmn', result: ClusterReachabilityResult) => {\n if (result.udp && result.udp.result !== 'untested') {\n const outcome = result.udp.result === 'reachable' ? 'success' : 'failed';\n stats[`reachability_${clusterType}_udp_${outcome}`] += 1;\n }\n if (result.tcp && result.tcp.result !== 'untested') {\n const outcome = result.tcp.result === 'reachable' ? 'success' : 'failed';\n stats[`reachability_${clusterType}_tcp_${outcome}`] += 1;\n }\n };\n\n try {\n // @ts-ignore\n const resultsJson = await this.webex.boundedStorage.get(\n REACHABILITY.namespace,\n REACHABILITY.localStorageResult\n );\n\n const results: ReachabilityResults = JSON.parse(resultsJson);\n\n Object.values(results).forEach((result) => {\n updateStats(result.isVideoMesh ? 'vmn' : 'public', result);\n });\n } catch (e) {\n // empty storage, that's ok\n LoggerProxy.logger.warn(\n 'Roap:request#getReachabilityMetrics --> Error parsing reachability data: ',\n e\n );\n }\n\n return stats;\n }\n\n /**\n * Maps our internal transport result to the format that backend expects\n * @param {TransportResult} transportResult\n * @returns {TransportResultForBackend}\n */\n private mapTransportResultToBackendDataFormat(\n transportResult: TransportResult\n ): TransportResultForBackend {\n const output: TransportResultForBackend = {};\n\n for (const [key, value] of Object.entries(transportResult)) {\n switch (key) {\n case 'result':\n switch (value) {\n case 'reachable':\n output.reachable = 'true';\n break;\n case 'unreachable':\n output.reachable = 'false';\n break;\n case 'untested':\n output.untested = 'true';\n break;\n }\n break;\n case 'latencyInMilliseconds':\n output.latencyInMilliseconds = value.toString();\n break;\n default:\n output[key] = value;\n }\n }\n\n return output;\n }\n\n /**\n * Reachability results as an object in the format that backend expects\n *\n * @returns {any} reachability results that need to be sent to the backend\n */\n async getReachabilityResults(): Promise<ReachabilityResultsForBackend | undefined> {\n let results: ReachabilityResultsForBackend;\n\n try {\n // @ts-ignore\n const resultsJson = await this.webex.boundedStorage.get(\n REACHABILITY.namespace,\n REACHABILITY.localStorageResult\n );\n\n const allClusterResults: ReachabilityResults = JSON.parse(resultsJson);\n\n results = mapValues(allClusterResults, (clusterResult) => ({\n udp: this.mapTransportResultToBackendDataFormat(clusterResult.udp || {result: 'untested'}),\n tcp: this.mapTransportResultToBackendDataFormat(clusterResult.tcp || {result: 'untested'}),\n xtls: this.mapTransportResultToBackendDataFormat(\n clusterResult.xtls || {result: 'untested'}\n ),\n }));\n } catch (e) {\n // empty storage, that's ok\n LoggerProxy.logger.warn(\n 'Roap:request#attachReachabilityData --> Error parsing reachability data: ',\n e\n );\n }\n\n return results;\n }\n\n /**\n * fetches reachability data and checks for cluster reachability\n * @returns {boolean}\n * @public\n * @memberof Reachability\n */\n async isAnyPublicClusterReachable() {\n let reachable = false;\n // @ts-ignore\n const reachabilityData = await this.webex.boundedStorage\n .get(this.namespace, REACHABILITY.localStorageResult)\n .catch(() => {});\n\n if (reachabilityData) {\n try {\n const reachabilityResults: ReachabilityResults = JSON.parse(reachabilityData);\n\n reachable = Object.values(reachabilityResults).some(\n (result) =>\n !result.isVideoMesh &&\n (result.udp?.result === 'reachable' || result.tcp?.result === 'reachable')\n );\n } catch (e) {\n LoggerProxy.logger.error(\n `Roap:request#attachReachabilityData --> Error in parsing reachability data: ${e}`\n );\n }\n }\n\n return reachable;\n }\n\n /**\n * Get list of all unreachable clusters\n * @returns {array} Unreachable clusters\n * @private\n * @memberof Reachability\n */\n private getUnreachableClusters(): Array<{name: string; protocol: string}> {\n const unreachableList = [];\n\n Object.entries(this.clusterReachability).forEach(([key, clusterReachability]) => {\n const result = clusterReachability.getResult();\n\n if (result.udp.result === 'unreachable') {\n unreachableList.push({name: key, protocol: 'udp'});\n }\n if (result.tcp.result === 'unreachable') {\n unreachableList.push({name: key, protocol: 'tcp'});\n }\n });\n\n return unreachableList;\n }\n\n /**\n * Make a log of unreachable clusters.\n * @returns {undefined}\n * @private\n * @memberof Reachability\n */\n private logUnreachableClusters() {\n const list = this.getUnreachableClusters();\n\n list.forEach(({name, protocol}) => {\n LoggerProxy.logger.log(\n `Reachability:index#logUnreachableClusters --> failed to reach ${name} over ${protocol}`\n );\n });\n }\n\n /**\n * Performs reachability checks for all clusters\n * @param {ClusterList} clusterList\n * @returns {Promise<ReachabilityResults>} reachability check results\n */\n private async performReachabilityChecks(clusterList: ClusterList): Promise<ReachabilityResults> {\n const results: ReachabilityResults = {};\n\n if (!clusterList || !Object.keys(clusterList).length) {\n return Promise.resolve(results);\n }\n\n LoggerProxy.logger.log(\n `Reachability:index#performReachabilityChecks --> doing UDP${\n // @ts-ignore\n this.webex.config.meetings.experimental.enableTcpReachability ? ' and TCP' : ''\n } reachability checks`\n );\n\n const clusterReachabilityChecks = Object.keys(clusterList).map((key) => {\n const cluster = clusterList[key];\n\n // Linus doesn't support TCP reachability checks on video mesh nodes\n const includeTcpReachability =\n // @ts-ignore\n this.webex.config.meetings.experimental.enableTcpReachability && !cluster.isVideoMesh;\n\n if (!includeTcpReachability) {\n cluster.tcp = [];\n }\n\n this.clusterReachability[key] = new ClusterReachability(key, cluster);\n\n return this.clusterReachability[key].start().then((result) => {\n results[key] = result;\n results[key].isVideoMesh = cluster.isVideoMesh;\n });\n });\n\n await Promise.all(clusterReachabilityChecks);\n\n this.logUnreachableClusters();\n\n return results;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["Reachability","webex","REACHABILITY","namespace","reachabilityRequest","ReachabilityRequest","clusterReachability","getClusters","MeetingUtil","getIpVersion","clusters","joinCookie","performReachabilityChecks","results","boundedStorage","put","localStorageResult","localStorageJoinCookie","LoggerProxy","logger","log","error","stats","reachability_public_udp_success","reachability_public_udp_failed","reachability_public_tcp_success","reachability_public_tcp_failed","reachability_vmn_udp_success","reachability_vmn_udp_failed","reachability_vmn_tcp_success","reachability_vmn_tcp_failed","updateStats","clusterType","result","udp","outcome","tcp","get","resultsJson","JSON","parse","forEach","isVideoMesh","warn","transportResult","output","key","value","reachable","untested","latencyInMilliseconds","toString","allClusterResults","clusterResult","mapTransportResultToBackendDataFormat","xtls","catch","reachabilityData","reachabilityResults","some","e","unreachableList","getResult","push","name","protocol","list","getUnreachableClusters","clusterList","length","resolve","config","meetings","experimental","enableTcpReachability","clusterReachabilityChecks","map","cluster","includeTcpReachability","ClusterReachability","start","then","all","logUnreachableClusters"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-disable class-methods-use-this */\nimport {mapValues} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport MeetingUtil from '../meeting/util';\n\nimport {REACHABILITY} from '../constants';\n\nimport ReachabilityRequest, {ClusterList} from './request';\nimport {\n ClusterReachability,\n ClusterReachabilityResult,\n TransportResult,\n} from './clusterReachability';\n\nexport type ReachabilityMetrics = {\n reachability_public_udp_success: number;\n reachability_public_udp_failed: number;\n reachability_public_tcp_success: number;\n reachability_public_tcp_failed: number;\n reachability_vmn_udp_success: number;\n reachability_vmn_udp_failed: number;\n reachability_vmn_tcp_success: number;\n reachability_vmn_tcp_failed: number;\n};\n\n/**\n * This is the type that matches what backend expects us to send to them. It is a bit weird, because\n * it uses strings instead of booleans and numbers, but that's what they require.\n */\nexport type TransportResultForBackend = {\n reachable?: 'true' | 'false';\n latencyInMilliseconds?: string;\n clientMediaIPs?: string[];\n untested?: 'true';\n};\n\nexport type ReachabilityResultForBackend = {\n udp: TransportResultForBackend;\n tcp: TransportResultForBackend;\n xtls: TransportResultForBackend;\n};\n\n// this is the type that is required by the backend when we send them reachability results\nexport type ReachabilityResultsForBackend = Record<string, ReachabilityResultForBackend>;\n\n// this is the type used by Reachability class internally and stored in local storage\nexport type ReachabilityResults = Record<\n string,\n ClusterReachabilityResult & {\n isVideoMesh?: boolean;\n }\n>;\n\n/**\n * @class Reachability\n * @export\n */\nexport default class Reachability {\n namespace = REACHABILITY.namespace;\n webex: object;\n reachabilityRequest: ReachabilityRequest;\n clusterReachability: {\n [key: string]: ClusterReachability;\n };\n\n /**\n * Creates an instance of Reachability.\n * @param {object} webex\n * @memberof Reachability\n */\n constructor(webex: object) {\n this.webex = webex;\n\n /**\n * internal request object for the server\n * @instance\n * @type {Array}\n * @private\n * @memberof Reachability\n */\n this.reachabilityRequest = new ReachabilityRequest(this.webex);\n\n this.clusterReachability = {};\n }\n\n /**\n * Gets a list of media clusters from the backend and performs reachability checks on all the clusters\n * @returns {Promise<ReachabilityResults>} reachability results\n * @public\n * @memberof Reachability\n */\n public async gatherReachability(): Promise<ReachabilityResults> {\n // Fetch clusters and measure latency\n try {\n const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(\n MeetingUtil.getIpVersion(this.webex)\n );\n\n // Perform Reachability Check\n const results = await this.performReachabilityChecks(clusters);\n\n // @ts-ignore\n await this.webex.boundedStorage.put(\n this.namespace,\n REACHABILITY.localStorageResult,\n JSON.stringify(results)\n );\n // @ts-ignore\n await this.webex.boundedStorage.put(\n this.namespace,\n REACHABILITY.localStorageJoinCookie,\n JSON.stringify(joinCookie)\n );\n\n LoggerProxy.logger.log(\n 'Reachability:index#gatherReachability --> Reachability checks completed'\n );\n\n return results;\n } catch (error) {\n LoggerProxy.logger.error(`Reachability:index#gatherReachability --> Error:`, error);\n\n return {};\n }\n }\n\n /**\n * Returns statistics about last reachability results. The returned value is an object\n * with a flat list of properties so that it can be easily sent with metrics\n *\n * @returns {Promise} Promise with metrics values, it never rejects/throws.\n */\n async getReachabilityMetrics(): Promise<ReachabilityMetrics> {\n const stats: ReachabilityMetrics = {\n reachability_public_udp_success: 0,\n reachability_public_udp_failed: 0,\n reachability_public_tcp_success: 0,\n reachability_public_tcp_failed: 0,\n reachability_vmn_udp_success: 0,\n reachability_vmn_udp_failed: 0,\n reachability_vmn_tcp_success: 0,\n reachability_vmn_tcp_failed: 0,\n };\n\n const updateStats = (clusterType: 'public' | 'vmn', result: ClusterReachabilityResult) => {\n if (result.udp && result.udp.result !== 'untested') {\n const outcome = result.udp.result === 'reachable' ? 'success' : 'failed';\n stats[`reachability_${clusterType}_udp_${outcome}`] += 1;\n }\n if (result.tcp && result.tcp.result !== 'untested') {\n const outcome = result.tcp.result === 'reachable' ? 'success' : 'failed';\n stats[`reachability_${clusterType}_tcp_${outcome}`] += 1;\n }\n };\n\n try {\n // @ts-ignore\n const resultsJson = await this.webex.boundedStorage.get(\n REACHABILITY.namespace,\n REACHABILITY.localStorageResult\n );\n\n const results: ReachabilityResults = JSON.parse(resultsJson);\n\n Object.values(results).forEach((result) => {\n updateStats(result.isVideoMesh ? 'vmn' : 'public', result);\n });\n } catch (e) {\n // empty storage, that's ok\n LoggerProxy.logger.warn(\n 'Roap:request#getReachabilityMetrics --> Error parsing reachability data: ',\n e\n );\n }\n\n return stats;\n }\n\n /**\n * Maps our internal transport result to the format that backend expects\n * @param {TransportResult} transportResult\n * @returns {TransportResultForBackend}\n */\n private mapTransportResultToBackendDataFormat(\n transportResult: TransportResult\n ): TransportResultForBackend {\n const output: TransportResultForBackend = {};\n\n for (const [key, value] of Object.entries(transportResult)) {\n switch (key) {\n case 'result':\n switch (value) {\n case 'reachable':\n output.reachable = 'true';\n break;\n case 'unreachable':\n output.reachable = 'false';\n break;\n case 'untested':\n output.untested = 'true';\n break;\n }\n break;\n case 'latencyInMilliseconds':\n output.latencyInMilliseconds = value.toString();\n break;\n default:\n output[key] = value;\n }\n }\n\n return output;\n }\n\n /**\n * Reachability results as an object in the format that backend expects\n *\n * @returns {any} reachability results that need to be sent to the backend\n */\n async getReachabilityResults(): Promise<ReachabilityResultsForBackend | undefined> {\n let results: ReachabilityResultsForBackend;\n\n try {\n // @ts-ignore\n const resultsJson = await this.webex.boundedStorage.get(\n REACHABILITY.namespace,\n REACHABILITY.localStorageResult\n );\n\n const allClusterResults: ReachabilityResults = JSON.parse(resultsJson);\n\n results = mapValues(allClusterResults, (clusterResult) => ({\n udp: this.mapTransportResultToBackendDataFormat(clusterResult.udp || {result: 'untested'}),\n tcp: this.mapTransportResultToBackendDataFormat(clusterResult.tcp || {result: 'untested'}),\n xtls: this.mapTransportResultToBackendDataFormat(\n clusterResult.xtls || {result: 'untested'}\n ),\n }));\n } catch (e) {\n // empty storage, that's ok\n LoggerProxy.logger.warn(\n 'Roap:request#attachReachabilityData --> Error parsing reachability data: ',\n e\n );\n }\n\n return results;\n }\n\n /**\n * fetches reachability data and checks for cluster reachability\n * @returns {boolean}\n * @public\n * @memberof Reachability\n */\n async isAnyPublicClusterReachable() {\n let reachable = false;\n // @ts-ignore\n const reachabilityData = await this.webex.boundedStorage\n .get(this.namespace, REACHABILITY.localStorageResult)\n .catch(() => {});\n\n if (reachabilityData) {\n try {\n const reachabilityResults: ReachabilityResults = JSON.parse(reachabilityData);\n\n reachable = Object.values(reachabilityResults).some(\n (result) =>\n !result.isVideoMesh &&\n (result.udp?.result === 'reachable' || result.tcp?.result === 'reachable')\n );\n } catch (e) {\n LoggerProxy.logger.error(\n `Roap:request#attachReachabilityData --> Error in parsing reachability data: ${e}`\n );\n }\n }\n\n return reachable;\n }\n\n /**\n * Get list of all unreachable clusters\n * @returns {array} Unreachable clusters\n * @private\n * @memberof Reachability\n */\n private getUnreachableClusters(): Array<{name: string; protocol: string}> {\n const unreachableList = [];\n\n Object.entries(this.clusterReachability).forEach(([key, clusterReachability]) => {\n const result = clusterReachability.getResult();\n\n if (result.udp.result === 'unreachable') {\n unreachableList.push({name: key, protocol: 'udp'});\n }\n if (result.tcp.result === 'unreachable') {\n unreachableList.push({name: key, protocol: 'tcp'});\n }\n });\n\n return unreachableList;\n }\n\n /**\n * Make a log of unreachable clusters.\n * @returns {undefined}\n * @private\n * @memberof Reachability\n */\n private logUnreachableClusters() {\n const list = this.getUnreachableClusters();\n\n list.forEach(({name, protocol}) => {\n LoggerProxy.logger.log(\n `Reachability:index#logUnreachableClusters --> failed to reach ${name} over ${protocol}`\n );\n });\n }\n\n /**\n * Performs reachability checks for all clusters\n * @param {ClusterList} clusterList\n * @returns {Promise<ReachabilityResults>} reachability check results\n */\n private async performReachabilityChecks(clusterList: ClusterList): Promise<ReachabilityResults> {\n const results: ReachabilityResults = {};\n\n if (!clusterList || !Object.keys(clusterList).length) {\n return Promise.resolve(results);\n }\n\n LoggerProxy.logger.log(\n `Reachability:index#performReachabilityChecks --> doing UDP${\n // @ts-ignore\n this.webex.config.meetings.experimental.enableTcpReachability ? ' and TCP' : ''\n } reachability checks`\n );\n\n const clusterReachabilityChecks = Object.keys(clusterList).map((key) => {\n const cluster = clusterList[key];\n\n // Linus doesn't support TCP reachability checks on video mesh nodes\n const includeTcpReachability =\n // @ts-ignore\n this.webex.config.meetings.experimental.enableTcpReachability && !cluster.isVideoMesh;\n\n if (!includeTcpReachability) {\n cluster.tcp = [];\n }\n\n this.clusterReachability[key] = new ClusterReachability(key, cluster);\n\n return this.clusterReachability[key].start().then((result) => {\n results[key] = result;\n results[key].isVideoMesh = cluster.isVideoMesh;\n });\n });\n\n await Promise.all(clusterReachabilityChecks);\n\n this.logUnreachableClusters();\n\n return results;\n }\n}\n"],"mappings":"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"}
@@ -337,12 +337,12 @@ var ReconnectionManager = /*#__PURE__*/function () {
337
337
  key: "reconnect",
338
338
  value: function () {
339
339
  var _reconnect = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
340
- var _this3 = this;
341
340
  var _ref2,
342
341
  _ref2$networkDisconne,
343
342
  networkDisconnect,
344
343
  _ref2$networkRetry,
345
344
  networkRetry,
345
+ media,
346
346
  _args2 = arguments;
347
347
  return _regenerator.default.wrap(function _callee2$(_context2) {
348
348
  while (1) switch (_context2.prev = _context2.next) {
@@ -372,55 +372,75 @@ var ReconnectionManager = /*#__PURE__*/function () {
372
372
  }
373
373
  });
374
374
  }
375
- return _context2.abrupt("return", this.executeReconnection({
375
+ _context2.prev = 11;
376
+ _context2.next = 14;
377
+ return this.webex.meetings.startReachability();
378
+ case 14:
379
+ _context2.next = 19;
380
+ break;
381
+ case 16:
382
+ _context2.prev = 16;
383
+ _context2.t1 = _context2["catch"](11);
384
+ _loggerProxy.default.logger.info('ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ', _context2.t1);
385
+ case 19:
386
+ _context2.prev = 19;
387
+ _context2.next = 22;
388
+ return this.executeReconnection({
376
389
  networkDisconnect: networkDisconnect
377
- }).catch(function (reconnectError) {
378
- if (reconnectError instanceof NeedsRetryError) {
379
- _loggerProxy.default.logger.info('ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.');
380
- // Reset our reconnect status since we are looping back to the beginning
381
- _this3.status = _constants.RECONNECTION.STATE.DEFAULT_STATUS;
382
-
383
- // This is a network retry, so we should not log START metrics again
384
- return _this3.reconnect({
385
- networkDisconnect: true,
386
- networkRetry: true
387
- });
388
- }
389
-
390
- // Reconnect has failed
391
- _loggerProxy.default.logger.error('ReconnectionManager:index#reconnect --> Reconnection failed.', reconnectError.message);
392
- _loggerProxy.default.logger.info('ReconnectionManager:index#reconnect --> Sending reconnect abort metric.');
390
+ });
391
+ case 22:
392
+ media = _context2.sent;
393
+ return _context2.abrupt("return", media);
394
+ case 26:
395
+ _context2.prev = 26;
396
+ _context2.t2 = _context2["catch"](19);
397
+ if (!(_context2.t2 instanceof NeedsRetryError)) {
398
+ _context2.next = 32;
399
+ break;
400
+ }
401
+ _loggerProxy.default.logger.info('ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.');
402
+ // Reset our reconnect status since we are looping back to the beginning
403
+ this.status = _constants.RECONNECTION.STATE.DEFAULT_STATUS;
393
404
 
394
- // @ts-ignore
395
- _this3.webex.internal.newMetrics.submitClientEvent({
396
- name: 'client.call.aborted',
397
- payload: {
398
- errors: [{
399
- category: 'expected',
400
- errorCode: 2008,
401
- fatal: true,
402
- name: 'media-engine',
403
- shownToUser: false
404
- }]
405
- },
406
- options: {
407
- meetingId: _this3.meeting.id
408
- }
409
- });
410
- if (reconnectError instanceof NeedsRejoinError) {
411
- // send call aborded event with catogery as expected as we are trying to rejoin
405
+ // This is a network retry, so we should not log START metrics again
406
+ return _context2.abrupt("return", this.reconnect({
407
+ networkDisconnect: true,
408
+ networkRetry: true
409
+ }));
410
+ case 32:
411
+ // Reconnect has failed
412
+ _loggerProxy.default.logger.error('ReconnectionManager:index#reconnect --> Reconnection failed.', _context2.t2.message);
413
+ _loggerProxy.default.logger.info('ReconnectionManager:index#reconnect --> Sending reconnect abort metric.');
412
414
 
413
- if (_this3.autoRejoinEnabled) {
414
- return _this3.rejoinMeeting(reconnectError.wasSharing);
415
- }
415
+ // send call aborted event with catogery as expected as we are trying to rejoin
416
+ // @ts-ignore
417
+ this.webex.internal.newMetrics.submitClientEvent({
418
+ name: 'client.call.aborted',
419
+ payload: {
420
+ errors: [{
421
+ category: 'expected',
422
+ errorCode: 2008,
423
+ fatal: true,
424
+ name: 'media-engine',
425
+ shownToUser: false
426
+ }]
427
+ },
428
+ options: {
429
+ meetingId: this.meeting.id
416
430
  }
417
- throw reconnectError;
418
- }));
419
- case 12:
431
+ });
432
+ if (!(_context2.t2 instanceof NeedsRejoinError && this.autoRejoinEnabled)) {
433
+ _context2.next = 37;
434
+ break;
435
+ }
436
+ return _context2.abrupt("return", this.rejoinMeeting(_context2.t2.wasSharing));
437
+ case 37:
438
+ throw _context2.t2;
439
+ case 38:
420
440
  case "end":
421
441
  return _context2.stop();
422
442
  }
423
- }, _callee2, this, [[2, 6]]);
443
+ }, _callee2, this, [[2, 6], [11, 16], [19, 26]]);
424
444
  }));
425
445
  function reconnect() {
426
446
  return _reconnect.apply(this, arguments);
@@ -1 +1 @@
1
- {"version":3,"names":["NeedsRetryError","Error","NeedsRejoinError","wasSharing","error","ReconnectionManager","meeting","iceState","disconnected","resolve","timer","undefined","timeoutDuration","config","reconnection","iceReconnectionTimeout","status","RECONNECTION","STATE","DEFAULT_STATUS","tryCount","DEFAULT_TRY_COUNT","webex","maxRejoinAttempts","rejoinAttempts","autoRejoinEnabled","autoRejoin","reset","clearTimeout","LoggerProxy","logger","log","resetReconnectionTimer","reject","setTimeout","reason","unpublishStreams","mediaProperties","shareVideoStream","shareAudioStream","Trigger","trigger","file","function","EVENT_TRIGGERS","MEETING_STOPPED_SHARING_LOCAL","IN_PROGRESS","enabled","COMPLETE","info","ReconnectInProgress","ReconnectionError","networkDisconnect","networkRetry","id","validate","internal","newMetrics","submitClientEvent","name","options","meetingId","executeReconnection","catch","reconnectError","reconnect","message","payload","errors","category","errorCode","fatal","shownToUser","rejoinMeeting","shareStatus","SHARE_STATUS","LOCAL_SHARE_ACTIVE","stopLocalShareStream","SHARE_STOPPED_REASON","MEDIA_RECONNECTION","reconnectMercuryWebSocket","device","url","FAILURE","credentials","isUnverifiedGuest","meetings","syncMeetings","keepOnlyLocusMeetings","getMeetingByType","_ID_","state","_LEFT_","type","_CALL_","reconnectMedia","media","join","rejoin","MEETING_REJOIN","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","MEETING_MAX_REJOIN_FAILURE","locus_id","locusUrl","split","pop","stack","roap","doTurnDiscovery","turnServerResult","iceServers","turnServerInfo","push","urls","username","credential","password","webrtcMediaConnection","isMultistream","mediaRequestManagers","forEach","mediaRequestManager","clearPreviousRequests","commit","mercury","connected","disconnect","connect"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-disable no-warning-comments */\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\nimport {\n EVENT_TRIGGERS,\n RECONNECTION,\n SHARE_STATUS,\n SHARE_STOPPED_REASON,\n _CALL_,\n _LEFT_,\n _ID_,\n RECONNECTION_STATE,\n} from '../constants';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport ReconnectInProgress from '../common/errors/reconnection-in-progress';\nimport Metrics from '../metrics';\nimport Meeting from '../meeting';\nimport {MediaRequestManager} from '../multistream/mediaRequestManager';\nimport ReconnectionError from '../common/errors/reconnection';\n\n/**\n * Used to indicate that the reconnect logic needs to be retried.\n *\n * @class NeedsRetryError\n * @extends {Error}\n */\nclass NeedsRetryError extends Error {}\n\n/**\n * Used to indicate that the meeting needs to be rejoined, not just media reconnected\n *\n * @class NeedsRejoinError\n * @extends {Error}\n */\nclass NeedsRejoinError extends Error {\n wasSharing: any;\n\n /**\n * Creates an instance of NeedsRejoinError.\n * @param {Object} params\n * @param {boolean} params.wasSharing\n * @param {Error} params.error\n * @memberof NeedsRejoinError\n */\n constructor({\n wasSharing,\n error = new Error('Meeting needs to be rejoined'),\n }: {\n wasSharing?: boolean;\n error?: Error;\n }) {\n // @ts-ignore\n super(error);\n\n this.wasSharing = wasSharing;\n }\n}\n\n/**\n * @export\n * @class ReconnectionManager\n */\nexport default class ReconnectionManager {\n autoRejoinEnabled: any;\n iceState: any;\n maxRejoinAttempts: any;\n meeting: any;\n rejoinAttempts: any;\n shareStatus: any;\n status: any;\n tryCount: any;\n webex: any;\n /**\n * @param {Meeting} meeting\n */\n constructor(meeting: Meeting) {\n /**\n * Stores ICE reconnection state data.\n *\n * @instance\n * @type {Object}\n * @private\n * @memberof ReconnectionManager\n */\n this.iceState = {\n disconnected: false,\n resolve: () => {},\n timer: undefined,\n // @ts-ignore\n timeoutDuration: meeting.config.reconnection.iceReconnectionTimeout,\n };\n\n /**\n * @instance\n * @type {RECONNECTION_STATE}\n * @private\n * @memberof ReconnectionManager\n */\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n /**\n * @instance\n * @type {Number}\n * @private\n * @memberof ReconnectionManager\n */\n this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n /**\n * @instance\n * @type {Object}\n * @private\n * @memberof ReconnectionManager\n */\n // TODO : change this logic to not save the meeting instance\n // It gets complicated when meeting ends on remote side , We have a old meeting instance which is not up to date\n // @ts-ignore\n this.webex = meeting.webex;\n /**\n * @instance\n * @type {Meeting}\n * @private\n * @memberof ReconnectionManager\n */\n // TODO: try removing the circular dependency for meeting and reconnection manager\n // try moving this to meetings collection\n this.meeting = meeting;\n\n // @ts-ignore\n this.maxRejoinAttempts = meeting.config.reconnection.maxRejoinAttempts;\n this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n // @ts-ignore\n this.autoRejoinEnabled = meeting.config.reconnection.autoRejoin;\n\n // Make sure reconnection state is in default\n this.reset();\n }\n\n /**\n * @public\n * @memberof ReconnectionManager\n * @returns {void}\n */\n resetReconnectionTimer() {\n this.iceState.resolve();\n this.iceState.resolve = () => {};\n\n if (this.iceState.timer) {\n clearTimeout(this.iceState.timer);\n delete this.iceState.timer;\n }\n }\n\n /**\n * Sets the iceState to connected and clears any disconnect timeouts and\n * related timeout data within the iceState.\n *\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public iceReconnected() {\n if (this.iceState.disconnected) {\n LoggerProxy.logger.log('ReconnectionManager:index#iceReconnected --> ice has reconnected');\n\n this.resetReconnectionTimer();\n\n this.iceState.disconnected = false;\n }\n }\n\n /**\n * Set the iceState to disconnected and generates a timeout that waits for the\n * iceState to reconnect and then resolves. If the ice state is already\n * processing a reconnect, it immediately resolves. Rejects if the timeout\n * duration is reached.\n *\n * @returns {Promise<undefined>}\n * @public\n * @memberof ReconnectionManager\n */\n public waitForIceReconnect() {\n if (!this.iceState.disconnected) {\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#waitForIceReconnect --> waiting for ice reconnect'\n );\n\n this.iceState.disconnected = true;\n\n return new Promise<void>((resolve, reject) => {\n this.iceState.timer = setTimeout(() => {\n if (this.iceState.disconnected === false) {\n resolve();\n } else {\n this.iceState.disconnected = false;\n reject(\n new Error(`ice reconnection did not occur in ${this.iceState.timeoutDuration}ms`)\n );\n }\n }, this.iceState.timeoutDuration);\n\n this.iceState.resolve = resolve;\n });\n }\n\n // return a resolved promise to prevent multiple catch executions of reconnect\n return Promise.resolve();\n }\n\n /**\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public reset() {\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n }\n\n /**\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public cleanUp() {\n this.reset();\n }\n\n /**\n * Stop the local share stream.\n *\n * @param {string} reason a {@link SHARE_STOPPED_REASON}\n * @returns {undefined}\n * @private\n * @memberof ReconnectionManager\n */\n private async stopLocalShareStream(reason: string) {\n await this.meeting.unpublishStreams([\n this.meeting.mediaProperties.shareVideoStream,\n this.meeting.mediaProperties.shareAudioStream,\n ]);\n Trigger.trigger(\n this.meeting,\n {\n file: 'reconnection-manager/index',\n function: 'stopLocalShareStream',\n },\n EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,\n {\n reason,\n }\n );\n }\n\n /**\n * @public\n * @memberof ReconnectionManager\n * @returns {Boolean} true if reconnection operation is in progress\n */\n isReconnectInProgress() {\n return this.status === RECONNECTION.STATE.IN_PROGRESS;\n }\n\n /**\n * Sets the reconnection status\n *\n * @public\n * @param {RECONNECTION_STATE} status\n * @memberof ReconnectionManager\n * @returns {undefined}\n */\n public setStatus(status: RECONNECTION_STATE) {\n this.status = status;\n }\n\n /**\n * @returns {Boolean}\n * @throws {ReconnectionError}\n * @private\n * @memberof ReconnectionManager\n */\n private validate() {\n if (this.meeting.config.reconnection.enabled) {\n if (\n this.status === RECONNECTION.STATE.DEFAULT_STATUS ||\n this.status === RECONNECTION.STATE.COMPLETE\n ) {\n return true;\n }\n\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#validate --> Reconnection already in progress.'\n );\n\n throw new ReconnectInProgress('Reconnection already in progress.');\n }\n\n LoggerProxy.logger.info('ReconnectionManager:index#validate --> Reconnection is not enabled.');\n\n throw new ReconnectionError('Reconnection is not enabled.');\n }\n\n /**\n * Initiates a media reconnect for the active meeting\n * @param {Object} reconnectOptions\n * @param {boolean} [reconnectOptions.networkDisconnect=false] indicates if a network disconnect event happened\n * @param {boolean} [reconnectOptions.networkRetry=false] indicates if we are retrying the reconnect\n * @returns {Promise}\n * @public\n * @memberof ReconnectionManager\n */\n public async reconnect({\n networkDisconnect = false,\n networkRetry = false,\n }: {\n networkDisconnect?: boolean;\n networkRetry?: boolean;\n } = {}) {\n LoggerProxy.logger.info(\n `ReconnectionManager:index#reconnect --> Reconnection start for meeting ${this.meeting.id}.`\n );\n // First, validate that we can reconnect, if not, it will throw an error\n try {\n this.validate();\n } catch (error) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Reconnection unable to begin.',\n error\n );\n throw error;\n }\n\n if (!networkRetry) {\n // Only log START metrics on the initial reconnect\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'\n );\n\n // @ts-ignore\n this.webex.internal.newMetrics.submitClientEvent({\n name: 'client.media.reconnecting',\n options: {\n meetingId: this.meeting.id,\n },\n });\n }\n\n return this.executeReconnection({networkDisconnect}).catch((reconnectError) => {\n if (reconnectError instanceof NeedsRetryError) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.'\n );\n // Reset our reconnect status since we are looping back to the beginning\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n\n // This is a network retry, so we should not log START metrics again\n return this.reconnect({networkDisconnect: true, networkRetry: true});\n }\n\n // Reconnect has failed\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnect --> Reconnection failed.',\n reconnectError.message\n );\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'\n );\n\n // @ts-ignore\n this.webex.internal.newMetrics.submitClientEvent({\n name: 'client.call.aborted',\n payload: {\n errors: [\n {\n category: 'expected',\n errorCode: 2008,\n fatal: true,\n name: 'media-engine',\n shownToUser: false,\n },\n ],\n },\n options: {\n meetingId: this.meeting.id,\n },\n });\n if (reconnectError instanceof NeedsRejoinError) {\n // send call aborded event with catogery as expected as we are trying to rejoin\n\n if (this.autoRejoinEnabled) {\n return this.rejoinMeeting(reconnectError.wasSharing);\n }\n }\n\n throw reconnectError;\n });\n }\n\n /**\n * @param {Object} reconnectOptions\n * @param {boolean} [reconnectOptions.networkDisconnect=false] indicates if a network disconnect event happened\n * @returns {Promise}\n * @throws {NeedsRetryError}\n * @private\n * @memberof ReconnectionManager\n */\n private async executeReconnection({networkDisconnect = false}: {networkDisconnect?: boolean}) {\n this.status = RECONNECTION.STATE.IN_PROGRESS;\n\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.'\n );\n\n const wasSharing = this.meeting.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE;\n\n if (wasSharing) {\n await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEDIA_RECONNECTION);\n }\n\n if (networkDisconnect) {\n try {\n await this.reconnectMercuryWebSocket();\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> Websocket reconnected.',\n this.webex.internal.device.url\n );\n } catch (error) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> Unable to reconnect to websocket, giving up.'\n );\n this.status = RECONNECTION.STATE.FAILURE;\n throw error;\n }\n }\n\n if (!this.webex.credentials.isUnverifiedGuest) {\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'\n );\n await this.webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});\n } catch (syncError) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',\n syncError\n );\n throw new NeedsRetryError(syncError);\n }\n }\n\n // TODO: try to improve this logic as the reconnection manager saves the instance of deleted meeting object\n // So that on rejoin it known what parametrs it was using\n if (!this.meeting || !this.webex.meetings.getMeetingByType(_ID_, this.meeting.id)) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Meeting got deleted due to inactivity or ended remotely.'\n );\n\n throw new Error('Unable to rejoin a meeting already ended or inactive.');\n }\n\n LoggerProxy.logger.info(\n `ReconnectionManager:index#executeReconnection --> Current state of meeting is ${this.meeting.state}`\n );\n\n // If the meeting state was left, no longer reconnect media\n if (this.meeting.state === _LEFT_) {\n if (this.meeting.type === _CALL_) {\n throw new Error('Unable to rejoin a call in LEFT state.');\n }\n\n throw new NeedsRejoinError({wasSharing});\n }\n\n try {\n const media = await this.reconnectMedia();\n\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#executeReconnection --> webRTC media connection renewed and local sdp offer sent'\n );\n\n return media;\n } catch (error) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> failed to renew webRTC media connection or initiate offer'\n );\n this.status = RECONNECTION.STATE.FAILURE;\n\n throw error;\n }\n }\n\n /**\n * Rejoins a meeting after detecting the member was in a LEFT state\n *\n * @async\n * @param {boolean} wasSharing\n * @returns {Promise}\n */\n async rejoinMeeting(wasSharing = false) {\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#rejoinMeeting --> attemping meeting rejoin'\n );\n\n await this.meeting.join({rejoin: true});\n LoggerProxy.logger.info('ReconnectionManager:index#rejoinMeeting --> meeting rejoined');\n\n if (wasSharing) {\n await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEETING_REJOIN);\n }\n } catch (joinError) {\n this.rejoinAttempts += 1;\n if (this.rejoinAttempts <= this.maxRejoinAttempts) {\n LoggerProxy.logger.info(\n `ReconnectionManager:index#rejoinMeeting --> Unable to rejoin meeting, attempt #${this.rejoinAttempts}, retrying.`,\n joinError\n );\n this.rejoinMeeting();\n } else {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#rejoinMeeting --> Unable to rejoin meeting after max attempts.',\n joinError\n );\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_MAX_REJOIN_FAILURE, {\n locus_id: this.meeting.locusUrl.split('/').pop(),\n reason: joinError.message,\n stack: joinError.stack,\n });\n this.status = RECONNECTION.STATE.FAILURE;\n throw joinError;\n }\n }\n\n try {\n await this.reconnectMedia();\n } catch (mediaError) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#rejoinMeeting --> Unable to reestablish media after rejoining.',\n mediaError\n );\n throw mediaError;\n }\n }\n\n /**\n * @returns {Promise}\n * @private\n * @memberof ReconnectionManager\n */\n async reconnectMedia() {\n LoggerProxy.logger.log('ReconnectionManager:index#reconnectMedia --> do turn discovery');\n\n // do the TURN server discovery again and ignore reachability results since the TURN server might change\n const turnServerResult = await this.meeting.roap.doTurnDiscovery(this.meeting, true, true);\n\n const iceServers = [];\n\n if (turnServerResult.turnServerInfo) {\n iceServers.push({\n urls: turnServerResult.turnServerInfo.url,\n username: turnServerResult.turnServerInfo.username || '',\n credential: turnServerResult.turnServerInfo.password || '',\n });\n }\n\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#reconnectMedia --> renew webRTC media connection and send local sdp offer'\n );\n\n await this.meeting.mediaProperties.webrtcMediaConnection.reconnect(iceServers);\n\n // resend media requests\n if (this.meeting.isMultistream) {\n Object.values(this.meeting.mediaRequestManagers).forEach(\n (mediaRequestManager: MediaRequestManager) => {\n mediaRequestManager.clearPreviousRequests();\n mediaRequestManager.commit();\n }\n );\n }\n }\n\n /**\n * Attempt to Reconnect Mercury Websocket\n * @returns {Promise}\n * @private\n * @memberof ReconnectionManager\n */\n private async reconnectMercuryWebSocket() {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Reconnecting websocket.'\n );\n // First, attempt to disconnect if we think we are already connected.\n if (this.webex.internal.mercury.connected) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Disconnecting existing websocket.'\n );\n try {\n await this.webex.internal.mercury.disconnect();\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Websocket disconnected successfully.'\n );\n } catch (disconnectError) {\n // If we can't disconnect, the sdk is in such a bad state that reconnecting is not going to happen.\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Unable to disconnect from websocket, giving up.',\n disconnectError\n );\n throw disconnectError;\n }\n }\n\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Connecting websocket.'\n );\n await this.webex.internal.mercury.connect();\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Websocket connected successfully.'\n );\n } catch (connectError) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Unable to connect to websocket, giving up.',\n connectError\n );\n\n throw connectError;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["NeedsRetryError","Error","NeedsRejoinError","wasSharing","error","ReconnectionManager","meeting","iceState","disconnected","resolve","timer","undefined","timeoutDuration","config","reconnection","iceReconnectionTimeout","status","RECONNECTION","STATE","DEFAULT_STATUS","tryCount","DEFAULT_TRY_COUNT","webex","maxRejoinAttempts","rejoinAttempts","autoRejoinEnabled","autoRejoin","reset","clearTimeout","LoggerProxy","logger","log","resetReconnectionTimer","reject","setTimeout","reason","unpublishStreams","mediaProperties","shareVideoStream","shareAudioStream","Trigger","trigger","file","function","EVENT_TRIGGERS","MEETING_STOPPED_SHARING_LOCAL","IN_PROGRESS","enabled","COMPLETE","info","ReconnectInProgress","ReconnectionError","networkDisconnect","networkRetry","id","validate","internal","newMetrics","submitClientEvent","name","options","meetingId","meetings","startReachability","executeReconnection","media","reconnect","message","payload","errors","category","errorCode","fatal","shownToUser","rejoinMeeting","shareStatus","SHARE_STATUS","LOCAL_SHARE_ACTIVE","stopLocalShareStream","SHARE_STOPPED_REASON","MEDIA_RECONNECTION","reconnectMercuryWebSocket","device","url","FAILURE","credentials","isUnverifiedGuest","syncMeetings","keepOnlyLocusMeetings","getMeetingByType","_ID_","state","_LEFT_","type","_CALL_","reconnectMedia","join","rejoin","MEETING_REJOIN","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","MEETING_MAX_REJOIN_FAILURE","locus_id","locusUrl","split","pop","stack","roap","doTurnDiscovery","turnServerResult","iceServers","turnServerInfo","push","urls","username","credential","password","webrtcMediaConnection","isMultistream","mediaRequestManagers","forEach","mediaRequestManager","clearPreviousRequests","commit","mercury","connected","disconnect","connect"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint-disable no-warning-comments */\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\nimport {\n EVENT_TRIGGERS,\n RECONNECTION,\n SHARE_STATUS,\n SHARE_STOPPED_REASON,\n _CALL_,\n _LEFT_,\n _ID_,\n RECONNECTION_STATE,\n} from '../constants';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport ReconnectInProgress from '../common/errors/reconnection-in-progress';\nimport Metrics from '../metrics';\nimport Meeting from '../meeting';\nimport {MediaRequestManager} from '../multistream/mediaRequestManager';\nimport ReconnectionError from '../common/errors/reconnection';\n\n/**\n * Used to indicate that the reconnect logic needs to be retried.\n *\n * @class NeedsRetryError\n * @extends {Error}\n */\nclass NeedsRetryError extends Error {}\n\n/**\n * Used to indicate that the meeting needs to be rejoined, not just media reconnected\n *\n * @class NeedsRejoinError\n * @extends {Error}\n */\nclass NeedsRejoinError extends Error {\n wasSharing: any;\n\n /**\n * Creates an instance of NeedsRejoinError.\n * @param {Object} params\n * @param {boolean} params.wasSharing\n * @param {Error} params.error\n * @memberof NeedsRejoinError\n */\n constructor({\n wasSharing,\n error = new Error('Meeting needs to be rejoined'),\n }: {\n wasSharing?: boolean;\n error?: Error;\n }) {\n // @ts-ignore\n super(error);\n\n this.wasSharing = wasSharing;\n }\n}\n\n/**\n * @export\n * @class ReconnectionManager\n */\nexport default class ReconnectionManager {\n autoRejoinEnabled: any;\n iceState: any;\n maxRejoinAttempts: any;\n meeting: any;\n rejoinAttempts: any;\n shareStatus: any;\n status: any;\n tryCount: any;\n webex: any;\n /**\n * @param {Meeting} meeting\n */\n constructor(meeting: Meeting) {\n /**\n * Stores ICE reconnection state data.\n *\n * @instance\n * @type {Object}\n * @private\n * @memberof ReconnectionManager\n */\n this.iceState = {\n disconnected: false,\n resolve: () => {},\n timer: undefined,\n // @ts-ignore\n timeoutDuration: meeting.config.reconnection.iceReconnectionTimeout,\n };\n\n /**\n * @instance\n * @type {RECONNECTION_STATE}\n * @private\n * @memberof ReconnectionManager\n */\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n /**\n * @instance\n * @type {Number}\n * @private\n * @memberof ReconnectionManager\n */\n this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n /**\n * @instance\n * @type {Object}\n * @private\n * @memberof ReconnectionManager\n */\n // TODO : change this logic to not save the meeting instance\n // It gets complicated when meeting ends on remote side , We have a old meeting instance which is not up to date\n // @ts-ignore\n this.webex = meeting.webex;\n /**\n * @instance\n * @type {Meeting}\n * @private\n * @memberof ReconnectionManager\n */\n // TODO: try removing the circular dependency for meeting and reconnection manager\n // try moving this to meetings collection\n this.meeting = meeting;\n\n // @ts-ignore\n this.maxRejoinAttempts = meeting.config.reconnection.maxRejoinAttempts;\n this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n // @ts-ignore\n this.autoRejoinEnabled = meeting.config.reconnection.autoRejoin;\n\n // Make sure reconnection state is in default\n this.reset();\n }\n\n /**\n * @public\n * @memberof ReconnectionManager\n * @returns {void}\n */\n resetReconnectionTimer() {\n this.iceState.resolve();\n this.iceState.resolve = () => {};\n\n if (this.iceState.timer) {\n clearTimeout(this.iceState.timer);\n delete this.iceState.timer;\n }\n }\n\n /**\n * Sets the iceState to connected and clears any disconnect timeouts and\n * related timeout data within the iceState.\n *\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public iceReconnected() {\n if (this.iceState.disconnected) {\n LoggerProxy.logger.log('ReconnectionManager:index#iceReconnected --> ice has reconnected');\n\n this.resetReconnectionTimer();\n\n this.iceState.disconnected = false;\n }\n }\n\n /**\n * Set the iceState to disconnected and generates a timeout that waits for the\n * iceState to reconnect and then resolves. If the ice state is already\n * processing a reconnect, it immediately resolves. Rejects if the timeout\n * duration is reached.\n *\n * @returns {Promise<undefined>}\n * @public\n * @memberof ReconnectionManager\n */\n public waitForIceReconnect() {\n if (!this.iceState.disconnected) {\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#waitForIceReconnect --> waiting for ice reconnect'\n );\n\n this.iceState.disconnected = true;\n\n return new Promise<void>((resolve, reject) => {\n this.iceState.timer = setTimeout(() => {\n if (this.iceState.disconnected === false) {\n resolve();\n } else {\n this.iceState.disconnected = false;\n reject(\n new Error(`ice reconnection did not occur in ${this.iceState.timeoutDuration}ms`)\n );\n }\n }, this.iceState.timeoutDuration);\n\n this.iceState.resolve = resolve;\n });\n }\n\n // return a resolved promise to prevent multiple catch executions of reconnect\n return Promise.resolve();\n }\n\n /**\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public reset() {\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n this.tryCount = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n this.rejoinAttempts = RECONNECTION.STATE.DEFAULT_TRY_COUNT;\n }\n\n /**\n * @returns {undefined}\n * @public\n * @memberof ReconnectionManager\n */\n public cleanUp() {\n this.reset();\n }\n\n /**\n * Stop the local share stream.\n *\n * @param {string} reason a {@link SHARE_STOPPED_REASON}\n * @returns {undefined}\n * @private\n * @memberof ReconnectionManager\n */\n private async stopLocalShareStream(reason: string) {\n await this.meeting.unpublishStreams([\n this.meeting.mediaProperties.shareVideoStream,\n this.meeting.mediaProperties.shareAudioStream,\n ]);\n Trigger.trigger(\n this.meeting,\n {\n file: 'reconnection-manager/index',\n function: 'stopLocalShareStream',\n },\n EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,\n {\n reason,\n }\n );\n }\n\n /**\n * @public\n * @memberof ReconnectionManager\n * @returns {Boolean} true if reconnection operation is in progress\n */\n isReconnectInProgress() {\n return this.status === RECONNECTION.STATE.IN_PROGRESS;\n }\n\n /**\n * Sets the reconnection status\n *\n * @public\n * @param {RECONNECTION_STATE} status\n * @memberof ReconnectionManager\n * @returns {undefined}\n */\n public setStatus(status: RECONNECTION_STATE) {\n this.status = status;\n }\n\n /**\n * @returns {Boolean}\n * @throws {ReconnectionError}\n * @private\n * @memberof ReconnectionManager\n */\n private validate() {\n if (this.meeting.config.reconnection.enabled) {\n if (\n this.status === RECONNECTION.STATE.DEFAULT_STATUS ||\n this.status === RECONNECTION.STATE.COMPLETE\n ) {\n return true;\n }\n\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#validate --> Reconnection already in progress.'\n );\n\n throw new ReconnectInProgress('Reconnection already in progress.');\n }\n\n LoggerProxy.logger.info('ReconnectionManager:index#validate --> Reconnection is not enabled.');\n\n throw new ReconnectionError('Reconnection is not enabled.');\n }\n\n /**\n * Initiates a media reconnect for the active meeting\n * @param {Object} reconnectOptions\n * @param {boolean} [reconnectOptions.networkDisconnect=false] indicates if a network disconnect event happened\n * @param {boolean} [reconnectOptions.networkRetry=false] indicates if we are retrying the reconnect\n * @returns {Promise}\n * @public\n * @memberof ReconnectionManager\n */\n public async reconnect({\n networkDisconnect = false,\n networkRetry = false,\n }: {\n networkDisconnect?: boolean;\n networkRetry?: boolean;\n } = {}) {\n LoggerProxy.logger.info(\n `ReconnectionManager:index#reconnect --> Reconnection start for meeting ${this.meeting.id}.`\n );\n // First, validate that we can reconnect, if not, it will throw an error\n try {\n this.validate();\n } catch (error) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Reconnection unable to begin.',\n error\n );\n throw error;\n }\n\n if (!networkRetry) {\n // Only log START metrics on the initial reconnect\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'\n );\n\n // @ts-ignore\n this.webex.internal.newMetrics.submitClientEvent({\n name: 'client.media.reconnecting',\n options: {\n meetingId: this.meeting.id,\n },\n });\n }\n\n try {\n await this.webex.meetings.startReachability();\n } catch (err) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ',\n err\n );\n }\n\n try {\n const media = await this.executeReconnection({networkDisconnect});\n\n return media;\n } catch (reconnectError) {\n if (reconnectError instanceof NeedsRetryError) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.'\n );\n // Reset our reconnect status since we are looping back to the beginning\n this.status = RECONNECTION.STATE.DEFAULT_STATUS;\n\n // This is a network retry, so we should not log START metrics again\n return this.reconnect({networkDisconnect: true, networkRetry: true});\n }\n\n // Reconnect has failed\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnect --> Reconnection failed.',\n reconnectError.message\n );\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'\n );\n\n // send call aborted event with catogery as expected as we are trying to rejoin\n // @ts-ignore\n this.webex.internal.newMetrics.submitClientEvent({\n name: 'client.call.aborted',\n payload: {\n errors: [\n {\n category: 'expected',\n errorCode: 2008,\n fatal: true,\n name: 'media-engine',\n shownToUser: false,\n },\n ],\n },\n options: {\n meetingId: this.meeting.id,\n },\n });\n\n if (reconnectError instanceof NeedsRejoinError && this.autoRejoinEnabled) {\n return this.rejoinMeeting(reconnectError.wasSharing);\n }\n\n throw reconnectError;\n }\n }\n\n /**\n * @param {Object} reconnectOptions\n * @param {boolean} [reconnectOptions.networkDisconnect=false] indicates if a network disconnect event happened\n * @returns {Promise}\n * @throws {NeedsRetryError}\n * @private\n * @memberof ReconnectionManager\n */\n private async executeReconnection({networkDisconnect = false}: {networkDisconnect?: boolean}) {\n this.status = RECONNECTION.STATE.IN_PROGRESS;\n\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.'\n );\n\n const wasSharing = this.meeting.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE;\n\n if (wasSharing) {\n await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEDIA_RECONNECTION);\n }\n\n if (networkDisconnect) {\n try {\n await this.reconnectMercuryWebSocket();\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> Websocket reconnected.',\n this.webex.internal.device.url\n );\n } catch (error) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> Unable to reconnect to websocket, giving up.'\n );\n this.status = RECONNECTION.STATE.FAILURE;\n throw error;\n }\n }\n\n if (!this.webex.credentials.isUnverifiedGuest) {\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'\n );\n await this.webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});\n } catch (syncError) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',\n syncError\n );\n throw new NeedsRetryError(syncError);\n }\n }\n\n // TODO: try to improve this logic as the reconnection manager saves the instance of deleted meeting object\n // So that on rejoin it known what parametrs it was using\n if (!this.meeting || !this.webex.meetings.getMeetingByType(_ID_, this.meeting.id)) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#executeReconnection --> Meeting got deleted due to inactivity or ended remotely.'\n );\n\n throw new Error('Unable to rejoin a meeting already ended or inactive.');\n }\n\n LoggerProxy.logger.info(\n `ReconnectionManager:index#executeReconnection --> Current state of meeting is ${this.meeting.state}`\n );\n\n // If the meeting state was left, no longer reconnect media\n if (this.meeting.state === _LEFT_) {\n if (this.meeting.type === _CALL_) {\n throw new Error('Unable to rejoin a call in LEFT state.');\n }\n\n throw new NeedsRejoinError({wasSharing});\n }\n\n try {\n const media = await this.reconnectMedia();\n\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#executeReconnection --> webRTC media connection renewed and local sdp offer sent'\n );\n\n return media;\n } catch (error) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#executeReconnection --> failed to renew webRTC media connection or initiate offer'\n );\n this.status = RECONNECTION.STATE.FAILURE;\n\n throw error;\n }\n }\n\n /**\n * Rejoins a meeting after detecting the member was in a LEFT state\n *\n * @async\n * @param {boolean} wasSharing\n * @returns {Promise}\n */\n async rejoinMeeting(wasSharing = false) {\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#rejoinMeeting --> attemping meeting rejoin'\n );\n\n await this.meeting.join({rejoin: true});\n LoggerProxy.logger.info('ReconnectionManager:index#rejoinMeeting --> meeting rejoined');\n\n if (wasSharing) {\n await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEETING_REJOIN);\n }\n } catch (joinError) {\n this.rejoinAttempts += 1;\n if (this.rejoinAttempts <= this.maxRejoinAttempts) {\n LoggerProxy.logger.info(\n `ReconnectionManager:index#rejoinMeeting --> Unable to rejoin meeting, attempt #${this.rejoinAttempts}, retrying.`,\n joinError\n );\n this.rejoinMeeting();\n } else {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#rejoinMeeting --> Unable to rejoin meeting after max attempts.',\n joinError\n );\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_MAX_REJOIN_FAILURE, {\n locus_id: this.meeting.locusUrl.split('/').pop(),\n reason: joinError.message,\n stack: joinError.stack,\n });\n this.status = RECONNECTION.STATE.FAILURE;\n throw joinError;\n }\n }\n\n try {\n await this.reconnectMedia();\n } catch (mediaError) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#rejoinMeeting --> Unable to reestablish media after rejoining.',\n mediaError\n );\n throw mediaError;\n }\n }\n\n /**\n * @returns {Promise}\n * @private\n * @memberof ReconnectionManager\n */\n async reconnectMedia() {\n LoggerProxy.logger.log('ReconnectionManager:index#reconnectMedia --> do turn discovery');\n\n // do the TURN server discovery again and ignore reachability results since the TURN server might change\n const turnServerResult = await this.meeting.roap.doTurnDiscovery(this.meeting, true, true);\n\n const iceServers = [];\n\n if (turnServerResult.turnServerInfo) {\n iceServers.push({\n urls: turnServerResult.turnServerInfo.url,\n username: turnServerResult.turnServerInfo.username || '',\n credential: turnServerResult.turnServerInfo.password || '',\n });\n }\n\n LoggerProxy.logger.log(\n 'ReconnectionManager:index#reconnectMedia --> renew webRTC media connection and send local sdp offer'\n );\n\n await this.meeting.mediaProperties.webrtcMediaConnection.reconnect(iceServers);\n\n // resend media requests\n if (this.meeting.isMultistream) {\n Object.values(this.meeting.mediaRequestManagers).forEach(\n (mediaRequestManager: MediaRequestManager) => {\n mediaRequestManager.clearPreviousRequests();\n mediaRequestManager.commit();\n }\n );\n }\n }\n\n /**\n * Attempt to Reconnect Mercury Websocket\n * @returns {Promise}\n * @private\n * @memberof ReconnectionManager\n */\n private async reconnectMercuryWebSocket() {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Reconnecting websocket.'\n );\n // First, attempt to disconnect if we think we are already connected.\n if (this.webex.internal.mercury.connected) {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Disconnecting existing websocket.'\n );\n try {\n await this.webex.internal.mercury.disconnect();\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Websocket disconnected successfully.'\n );\n } catch (disconnectError) {\n // If we can't disconnect, the sdk is in such a bad state that reconnecting is not going to happen.\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Unable to disconnect from websocket, giving up.',\n disconnectError\n );\n throw disconnectError;\n }\n }\n\n try {\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Connecting websocket.'\n );\n await this.webex.internal.mercury.connect();\n LoggerProxy.logger.info(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Websocket connected successfully.'\n );\n } catch (connectError) {\n LoggerProxy.logger.error(\n 'ReconnectionManager:index#reconnectMercuryWebSocket --> Unable to connect to websocket, giving up.',\n connectError\n );\n\n throw connectError;\n }\n }\n}\n"],"mappings":"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"}
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.0.0-beta.367"
65
+ version: "3.0.0-beta.368"
66
66
  });
67
67
  var _default = Webinar;
68
68
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.367",
3
+ "version": "3.0.0-beta.368",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -33,12 +33,12 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@peculiar/webcrypto": "^1.4.3",
36
- "@webex/plugin-meetings": "3.0.0-beta.367",
37
- "@webex/test-helper-chai": "3.0.0-beta.367",
38
- "@webex/test-helper-mocha": "3.0.0-beta.367",
39
- "@webex/test-helper-mock-webex": "3.0.0-beta.367",
40
- "@webex/test-helper-retry": "3.0.0-beta.367",
41
- "@webex/test-helper-test-users": "3.0.0-beta.367",
36
+ "@webex/plugin-meetings": "3.0.0-beta.368",
37
+ "@webex/test-helper-chai": "3.0.0-beta.368",
38
+ "@webex/test-helper-mocha": "3.0.0-beta.368",
39
+ "@webex/test-helper-mock-webex": "3.0.0-beta.368",
40
+ "@webex/test-helper-retry": "3.0.0-beta.368",
41
+ "@webex/test-helper-test-users": "3.0.0-beta.368",
42
42
  "chai": "^4.3.4",
43
43
  "chai-as-promised": "^7.1.1",
44
44
  "jsdom-global": "3.0.2",
@@ -47,19 +47,19 @@
47
47
  "typescript": "^4.7.4"
48
48
  },
49
49
  "dependencies": {
50
- "@webex/common": "3.0.0-beta.367",
50
+ "@webex/common": "3.0.0-beta.368",
51
51
  "@webex/internal-media-core": "2.2.7",
52
- "@webex/internal-plugin-conversation": "3.0.0-beta.367",
53
- "@webex/internal-plugin-device": "3.0.0-beta.367",
54
- "@webex/internal-plugin-llm": "3.0.0-beta.367",
55
- "@webex/internal-plugin-mercury": "3.0.0-beta.367",
56
- "@webex/internal-plugin-metrics": "3.0.0-beta.367",
57
- "@webex/internal-plugin-support": "3.0.0-beta.367",
58
- "@webex/internal-plugin-user": "3.0.0-beta.367",
59
- "@webex/media-helpers": "3.0.0-beta.367",
60
- "@webex/plugin-people": "3.0.0-beta.367",
61
- "@webex/plugin-rooms": "3.0.0-beta.367",
62
- "@webex/webex-core": "3.0.0-beta.367",
52
+ "@webex/internal-plugin-conversation": "3.0.0-beta.368",
53
+ "@webex/internal-plugin-device": "3.0.0-beta.368",
54
+ "@webex/internal-plugin-llm": "3.0.0-beta.368",
55
+ "@webex/internal-plugin-mercury": "3.0.0-beta.368",
56
+ "@webex/internal-plugin-metrics": "3.0.0-beta.368",
57
+ "@webex/internal-plugin-support": "3.0.0-beta.368",
58
+ "@webex/internal-plugin-user": "3.0.0-beta.368",
59
+ "@webex/media-helpers": "3.0.0-beta.368",
60
+ "@webex/plugin-people": "3.0.0-beta.368",
61
+ "@webex/plugin-rooms": "3.0.0-beta.368",
62
+ "@webex/webex-core": "3.0.0-beta.368",
63
63
  "ampersand-collection": "^2.0.2",
64
64
  "bowser": "^2.11.0",
65
65
  "btoa": "^1.2.1",
@@ -95,12 +95,6 @@ export default class Reachability {
95
95
  * @memberof Reachability
96
96
  */
97
97
  public async gatherReachability(): Promise<ReachabilityResults> {
98
- // Remove stored reachability results to ensure no stale data
99
- // @ts-ignore
100
- await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageResult);
101
- // @ts-ignore
102
- await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageJoinCookie);
103
-
104
98
  // Fetch clusters and measure latency
105
99
  try {
106
100
  const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(
@@ -349,7 +349,20 @@ export default class ReconnectionManager {
349
349
  });
350
350
  }
351
351
 
352
- return this.executeReconnection({networkDisconnect}).catch((reconnectError) => {
352
+ try {
353
+ await this.webex.meetings.startReachability();
354
+ } catch (err) {
355
+ LoggerProxy.logger.info(
356
+ 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ',
357
+ err
358
+ );
359
+ }
360
+
361
+ try {
362
+ const media = await this.executeReconnection({networkDisconnect});
363
+
364
+ return media;
365
+ } catch (reconnectError) {
353
366
  if (reconnectError instanceof NeedsRetryError) {
354
367
  LoggerProxy.logger.info(
355
368
  'ReconnectionManager:index#reconnect --> Reconnection not successful, retrying.'
@@ -370,6 +383,7 @@ export default class ReconnectionManager {
370
383
  'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'
371
384
  );
372
385
 
386
+ // send call aborted event with catogery as expected as we are trying to rejoin
373
387
  // @ts-ignore
374
388
  this.webex.internal.newMetrics.submitClientEvent({
375
389
  name: 'client.call.aborted',
@@ -388,16 +402,13 @@ export default class ReconnectionManager {
388
402
  meetingId: this.meeting.id,
389
403
  },
390
404
  });
391
- if (reconnectError instanceof NeedsRejoinError) {
392
- // send call aborded event with catogery as expected as we are trying to rejoin
393
405
 
394
- if (this.autoRejoinEnabled) {
395
- return this.rejoinMeeting(reconnectError.wasSharing);
396
- }
406
+ if (reconnectError instanceof NeedsRejoinError && this.autoRejoinEnabled) {
407
+ return this.rejoinMeeting(reconnectError.wasSharing);
397
408
  }
398
409
 
399
410
  throw reconnectError;
400
- });
411
+ }
401
412
  }
402
413
 
403
414
  /**
@@ -128,6 +128,11 @@ describe('gatherReachability', () => {
128
128
  'reachability.result',
129
129
  JSON.stringify({old: 'results'})
130
130
  );
131
+ await webex.boundedStorage.put(
132
+ 'Reachability',
133
+ 'reachability.joinCookie',
134
+ JSON.stringify({old: 'joinCookie'})
135
+ );
131
136
  });
132
137
 
133
138
  afterEach(() => {
@@ -169,6 +174,75 @@ describe('gatherReachability', () => {
169
174
  assert.equal(JSON.stringify(getClustersResult.joinCookie), storedResultForJoinCookie);
170
175
  });
171
176
 
177
+ it('keeps the stored reachability from previous call to gatherReachability if getClusters fails', async () => {
178
+ const reachability = new Reachability(webex);
179
+
180
+ const reachabilityResults = {
181
+ clusters: {
182
+ clusterId: {
183
+ udp: 'testUDP',
184
+ },
185
+ },
186
+ };
187
+ const getClustersResult = {
188
+ clusters: {clusterId: 'cluster'},
189
+ joinCookie: {id: 'id'},
190
+ };
191
+
192
+ reachability.reachabilityRequest.getClusters = sinon.stub().throws();
193
+
194
+ const result = await reachability.gatherReachability();
195
+
196
+ assert.empty(result);
197
+
198
+ const storedResultForReachabilityResult = await webex.boundedStorage.get(
199
+ 'Reachability',
200
+ 'reachability.result'
201
+ );
202
+ const storedResultForJoinCookie = await webex.boundedStorage.get(
203
+ 'Reachability',
204
+ 'reachability.joinCookie'
205
+ );
206
+
207
+ assert.equal(JSON.stringify({old: 'results'}), storedResultForReachabilityResult);
208
+ assert.equal(JSON.stringify({old: 'joinCookie'}), storedResultForJoinCookie);
209
+ });
210
+
211
+ it('keeps the stored reachability from previous call to gatherReachability if performReachabilityChecks fails', async () => {
212
+ const reachability = new Reachability(webex);
213
+
214
+ const reachabilityResults = {
215
+ clusters: {
216
+ clusterId: {
217
+ udp: 'testUDP',
218
+ },
219
+ },
220
+ };
221
+ const getClustersResult = {
222
+ clusters: {clusterId: 'cluster'},
223
+ joinCookie: {id: 'id'},
224
+ };
225
+
226
+ reachability.reachabilityRequest.getClusters = sinon.stub().returns(getClustersResult);
227
+ (reachability as any).performReachabilityChecks = sinon.stub().throws();
228
+
229
+ const result = await reachability.gatherReachability();
230
+
231
+ assert.empty(result);
232
+
233
+ const storedResultForReachabilityResult = await webex.boundedStorage.get(
234
+ 'Reachability',
235
+ 'reachability.result'
236
+ );
237
+ const storedResultForJoinCookie = await webex.boundedStorage.get(
238
+ 'Reachability',
239
+ 'reachability.joinCookie'
240
+ );
241
+
242
+ assert.equal(JSON.stringify({old: 'results'}), storedResultForReachabilityResult);
243
+ assert.equal(JSON.stringify({old: 'joinCookie'}), storedResultForJoinCookie);
244
+ });
245
+
172
246
  it('starts ClusterReachability on each media cluster', async () => {
173
247
  webex.config.meetings.experimental = {enableTcpReachability: true};
174
248
 
@@ -4,6 +4,8 @@ import chaiAsPromised from 'chai-as-promised';
4
4
  import sinon from 'sinon';
5
5
  import ReconnectionManager from '@webex/plugin-meetings/src/reconnection-manager';
6
6
  import { RECONNECTION } from '../../../../src/constants';
7
+ import LoggerProxy from '../../../../src/common/logs/logger-proxy';
8
+ import LoggerConfig from '../../../../src/common/logs/logger-config';
7
9
 
8
10
  const {assert} = chai;
9
11
 
@@ -12,8 +14,16 @@ sinon.assert.expose(chai.assert, {prefix: ''});
12
14
 
13
15
  describe('plugin-meetings', () => {
14
16
  describe('ReconnectionManager.reconnect', () => {
17
+ const sandbox = sinon.createSandbox();
15
18
  let fakeMediaConnection;
16
19
  let fakeMeeting;
20
+ let loggerSpy;
21
+
22
+ before(() => {
23
+ LoggerConfig.set({ enable: false });
24
+ LoggerProxy.set();
25
+ loggerSpy = sandbox.spy(LoggerProxy.logger, 'info');
26
+ });
17
27
 
18
28
  beforeEach(() => {
19
29
  fakeMediaConnection = {
@@ -65,6 +75,7 @@ describe('plugin-meetings', () => {
65
75
  meetings: {
66
76
  getMeetingByType: sinon.stub().returns(true),
67
77
  syncMeetings: sinon.stub().resolves({}),
78
+ startReachability: sinon.stub().resolves({}),
68
79
  },
69
80
  internal: {
70
81
  newMetrics: {
@@ -75,6 +86,10 @@ describe('plugin-meetings', () => {
75
86
  };
76
87
  });
77
88
 
89
+ afterEach(() => {
90
+ sandbox.reset();
91
+ });
92
+
78
93
  it('syncs meetings if it is not an unverified guest', async () => {
79
94
  const rm = new ReconnectionManager(fakeMeeting);
80
95
 
@@ -94,6 +109,27 @@ describe('plugin-meetings', () => {
94
109
  assert.notCalled(rm.webex.meetings.syncMeetings);
95
110
  });
96
111
 
112
+ it('calls startReachability on reconnect', async () => {
113
+ const rm = new ReconnectionManager(fakeMeeting);
114
+
115
+ await rm.reconnect();
116
+
117
+ assert.calledOnce(rm.webex.meetings.startReachability);
118
+ });
119
+
120
+ it('continues with reconnection attempt if startReachability throws an error', async () => {
121
+ const reachabilityError = new Error();
122
+ fakeMeeting.webex.meetings.startReachability = sinon.stub().throws(reachabilityError);
123
+
124
+ const rm = new ReconnectionManager(fakeMeeting);
125
+
126
+ await rm.reconnect();
127
+
128
+ assert.calledOnce(rm.webex.meetings.startReachability);
129
+ assert.calledWith(loggerSpy, 'ReconnectionManager:index#reconnect --> Reachability failed, continuing with reconnection attempt, err: ', reachabilityError);
130
+ assert.calledWith(loggerSpy, 'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.');
131
+ });
132
+
97
133
  it('uses correct TURN TLS information on the reconnection', async () => {
98
134
  const rm = new ReconnectionManager(fakeMeeting);
99
135
 
@@ -142,7 +178,6 @@ describe('plugin-meetings', () => {
142
178
  assert.calledOnce(fakeMeeting.mediaRequestManagers.video.commit);
143
179
  });
144
180
 
145
-
146
181
  it('sends the correct client event when reconnection fails', async () => {
147
182
  sinon.stub(ReconnectionManager.prototype, 'executeReconnection').rejects();
148
183
  fakeMeeting.isMultistream = true;