@webex/plugin-meetings 3.3.1-next.14 → 3.3.1-next.16

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.
@@ -1,8 +1,10 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
+ import { Defer } from '@webex/common';
4
5
  import ReachabilityRequest from './request';
5
6
  import { ClusterReachability, ClusterReachabilityResult } from './clusterReachability';
7
+ import EventsScope from '../common/events/events-scope';
6
8
  export type ReachabilityMetrics = {
7
9
  reachability_public_udp_success: number;
8
10
  reachability_public_udp_failed: number;
@@ -40,13 +42,37 @@ export type ReachabilityResults = Record<string, ClusterReachabilityResult & {
40
42
  * @class Reachability
41
43
  * @export
42
44
  */
43
- export default class Reachability {
45
+ export default class Reachability extends EventsScope {
44
46
  namespace: string;
45
47
  webex: object;
46
48
  reachabilityRequest: ReachabilityRequest;
47
49
  clusterReachability: {
48
50
  [key: string]: ClusterReachability;
49
51
  };
52
+ reachabilityDefer?: Defer;
53
+ vmnTimer?: ReturnType<typeof setTimeout>;
54
+ publicCloudTimer?: ReturnType<typeof setTimeout>;
55
+ overallTimer?: ReturnType<typeof setTimeout>;
56
+ expectedResultsCount: {
57
+ videoMesh: {
58
+ udp: number;
59
+ };
60
+ public: {
61
+ udp: number;
62
+ tcp: number;
63
+ xtls: number;
64
+ };
65
+ };
66
+ resultsCount: {
67
+ videoMesh: {
68
+ udp: number;
69
+ };
70
+ public: {
71
+ udp: number;
72
+ tcp: number;
73
+ xtls: number;
74
+ };
75
+ };
50
76
  /**
51
77
  * Creates an instance of Reachability.
52
78
  * @param {object} webex
@@ -111,10 +137,75 @@ export default class Reachability {
111
137
  * @memberof Reachability
112
138
  */
113
139
  private logUnreachableClusters;
140
+ /**
141
+ * Returns true if we've obtained all the reachability results for all the public clusters
142
+ * In other words, it means that all public clusters are reachable over each protocol,
143
+ * because we only get a "result" if we managed to reach a cluster
144
+ *
145
+ * @returns {boolean}
146
+ */
147
+ private areAllPublicClusterResultsReady;
148
+ /**
149
+ * Returns true if we've obtained all the reachability results for all the clusters
150
+ *
151
+ * @returns {boolean}
152
+ */
153
+ private areAllResultsReady;
154
+ /**
155
+ * Resolves the promise returned by gatherReachability() method
156
+ * @returns {void}
157
+ */
158
+ private resolveReachabilityPromise;
159
+ /**
160
+ * Aborts all cluster reachability checks that are in progress
161
+ *
162
+ * @returns {void}
163
+ */
164
+ private abortClusterReachability;
165
+ /**
166
+ * Helper function for calculating min/max/average values of latency
167
+ *
168
+ * @param {Array<any>} results
169
+ * @param {string} protocol
170
+ * @param {boolean} isVideoMesh
171
+ * @returns {{min:number, max: number, average: number}}
172
+ */
173
+ protected getStatistics(results: Array<ClusterReachabilityResult & {
174
+ isVideoMesh: boolean;
175
+ }>, protocol: 'udp' | 'tcp' | 'xtls', isVideoMesh: boolean): {
176
+ min: number;
177
+ max: number;
178
+ average: number;
179
+ };
180
+ /**
181
+ * Sends a metric with all the statistics about how long reachability took
182
+ *
183
+ * @returns {void}
184
+ */
185
+ protected sendMetric(): Promise<void>;
186
+ /**
187
+ * Starts all the timers used for various timeouts
188
+ *
189
+ * @returns {void}
190
+ */
191
+ private startTimers;
192
+ /**
193
+ * Stores given reachability results in local storage
194
+ *
195
+ * @param {ReachabilityResults} results
196
+ * @returns {Promise<void>}
197
+ */
198
+ private storeResults;
199
+ /**
200
+ * Resets all the internal counters that keep track of the results
201
+ *
202
+ * @returns {void}
203
+ */
204
+ private resetResultCounters;
114
205
  /**
115
206
  * Performs reachability checks for all clusters
116
207
  * @param {ClusterList} clusterList
117
- * @returns {Promise<ReachabilityResults>} reachability check results
208
+ * @returns {Promise<void>} promise that's resolved as soon as the checks are started
118
209
  */
119
210
  private performReachabilityChecks;
120
211
  }
@@ -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.3.1-next.14"
65
+ version: "3.3.1-next.16"
66
66
  });
67
67
  var _default = exports.default = Webinar;
68
68
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -43,7 +43,7 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.3.1-next.14",
46
+ "@webex/plugin-meetings": "3.3.1-next.16",
47
47
  "@webex/plugin-rooms": "3.3.1-next.3",
48
48
  "@webex/test-helper-chai": "3.3.1-next.2",
49
49
  "@webex/test-helper-mocha": "3.3.1-next.2",
@@ -70,10 +70,11 @@
70
70
  "@webex/internal-plugin-metrics": "3.3.1-next.2",
71
71
  "@webex/internal-plugin-support": "3.3.1-next.3",
72
72
  "@webex/internal-plugin-user": "3.3.1-next.2",
73
- "@webex/internal-plugin-voicea": "3.3.1-next.14",
73
+ "@webex/internal-plugin-voicea": "3.3.1-next.16",
74
74
  "@webex/media-helpers": "3.3.1-next.4",
75
75
  "@webex/plugin-people": "3.3.1-next.3",
76
76
  "@webex/plugin-rooms": "3.3.1-next.3",
77
+ "@webex/web-capabilities": "^1.3.0",
77
78
  "@webex/webex-core": "3.3.1-next.2",
78
79
  "ampersand-collection": "^2.0.2",
79
80
  "bowser": "^2.11.0",
@@ -91,5 +92,5 @@
91
92
  "//": [
92
93
  "TODO: upgrade jwt-decode when moving to node 18"
93
94
  ],
94
- "version": "3.3.1-next.14"
95
+ "version": "3.3.1-next.16"
95
96
  }
@@ -4,6 +4,11 @@ export const emptyMqaInterval = {
4
4
  intervalMetadata: {
5
5
  peerReflexiveIP: '0.0.0.0',
6
6
  peripherals: [],
7
+ cpuInfo: {
8
+ numberOfCores: 1, // default value from spec if CpuInfo.getNumLogicalCores cannot be determined
9
+ description: 'NA',
10
+ architecture: 'unknown',
11
+ },
7
12
  processAverageCPU: 0,
8
13
  processMaximumCPU: 0,
9
14
  systemAverageCPU: 0,
@@ -69,6 +69,7 @@ const BEHAVIORAL_METRICS = {
69
69
  ROAP_OFFER_TO_ANSWER_LATENCY: 'js_sdk_roap_offer_to_answer_latency',
70
70
  ROAP_HTTP_RESPONSE_MISSING: 'js_sdk_roap_http_response_missing',
71
71
  TURN_DISCOVERY_REQUIRES_OK: 'js_sdk_turn_discovery_requires_ok',
72
+ REACHABILITY_COMPLETED: 'js_sdk_reachability_completed',
72
73
  };
73
74
 
74
75
  export {BEHAVIORAL_METRICS as default};
@@ -3,11 +3,9 @@ import {Defer} from '@webex/common';
3
3
  import LoggerProxy from '../common/logs/logger-proxy';
4
4
  import {ClusterNode} from './request';
5
5
  import {convertStunUrlToTurn, convertStunUrlToTurnTls} from './util';
6
+ import EventsScope from '../common/events/events-scope';
6
7
 
7
- import {ICE_GATHERING_STATE, CONNECTION_STATE} from '../constants';
8
-
9
- const DEFAULT_TIMEOUT = 3000;
10
- const VIDEO_MESH_TIMEOUT = 1000;
8
+ import {CONNECTION_STATE, Enum, ICE_GATHERING_STATE} from '../constants';
11
9
 
12
10
  // result for a specific transport protocol (like udp or tcp)
13
11
  export type TransportResult = {
@@ -23,10 +21,32 @@ export type ClusterReachabilityResult = {
23
21
  xtls: TransportResult;
24
22
  };
25
23
 
24
+ // data for the Events.resultReady event
25
+ export type ResultEventData = {
26
+ protocol: 'udp' | 'tcp' | 'xtls';
27
+ result: 'reachable' | 'unreachable' | 'untested';
28
+ latencyInMilliseconds: number; // amount of time it took to get the ICE candidate
29
+ clientMediaIPs?: string[];
30
+ };
31
+
32
+ // data for the Events.clientMediaIpsUpdated event
33
+ export type ClientMediaIpsUpdatedEventData = {
34
+ protocol: 'udp' | 'tcp' | 'xtls';
35
+ clientMediaIPs: string[];
36
+ };
37
+
38
+ export const Events = {
39
+ resultReady: 'resultReady', // emitted when a cluster is reached successfully using specific protocol
40
+ clientMediaIpsUpdated: 'clientMediaIpsUpdated', // emitted when more public IPs are found after resultReady was already sent for a given protocol
41
+ } as const;
42
+
43
+ export type Events = Enum<typeof Events>;
44
+
26
45
  /**
27
46
  * A class that handles reachability checks for a single cluster.
47
+ * It emits events from Events enum
28
48
  */
29
- export class ClusterReachability {
49
+ export class ClusterReachability extends EventsScope {
30
50
  private numUdpUrls: number;
31
51
  private numTcpUrls: number;
32
52
  private numXTlsUrls: number;
@@ -43,6 +63,7 @@ export class ClusterReachability {
43
63
  * @param {ClusterNode} clusterInfo information about the media cluster
44
64
  */
45
65
  constructor(name: string, clusterInfo: ClusterNode) {
66
+ super();
46
67
  this.name = name;
47
68
  this.isVideoMesh = clusterInfo.isVideoMesh;
48
69
  this.numUdpUrls = clusterInfo.udp.length;
@@ -162,23 +183,54 @@ export class ClusterReachability {
162
183
  this.defer.resolve();
163
184
  }
164
185
 
186
+ /**
187
+ * Aborts the cluster reachability checks by closing the peer connection
188
+ *
189
+ * @returns {void}
190
+ */
191
+ public abort() {
192
+ const {CLOSED} = CONNECTION_STATE;
193
+
194
+ if (this.pc.connectionState !== CLOSED) {
195
+ this.closePeerConnection();
196
+ this.finishReachabilityCheck();
197
+ }
198
+ }
199
+
165
200
  /**
166
201
  * Adds public IP (client media IPs)
167
202
  * @param {string} protocol
168
203
  * @param {string} publicIP
169
204
  * @returns {void}
170
205
  */
171
- private addPublicIP(protocol: 'udp' | 'tcp', publicIP?: string | null) {
206
+ private addPublicIP(protocol: 'udp' | 'tcp' | 'xtls', publicIP?: string | null) {
172
207
  const result = this.result[protocol];
173
208
 
174
209
  if (publicIP) {
210
+ let ipAdded = false;
211
+
175
212
  if (result.clientMediaIPs) {
176
213
  if (!result.clientMediaIPs.includes(publicIP)) {
177
214
  result.clientMediaIPs.push(publicIP);
215
+ ipAdded = true;
178
216
  }
179
217
  } else {
180
218
  result.clientMediaIPs = [publicIP];
219
+ ipAdded = true;
181
220
  }
221
+
222
+ if (ipAdded)
223
+ this.emit(
224
+ {
225
+ file: 'clusterReachability',
226
+ function: 'addPublicIP',
227
+ },
228
+ Events.clientMediaIpsUpdated,
229
+ {
230
+ protocol,
231
+ clientMediaIPs: result.clientMediaIPs,
232
+ }
233
+ );
182
234
  }
183
235
  }
184
236
 
@@ -211,22 +263,43 @@ export class ClusterReachability {
211
263
  }
212
264
 
213
265
  /**
214
- * Stores the latency in the result for the given protocol and marks it as reachable
266
+ * Saves the latency in the result for the given protocol and marks it as reachable,
267
+ * emits the "resultReady" event if this is the first result for that protocol,
268
+ * emits the "clientMediaIpsUpdated" event if we already had a result and only found
269
+ * a new client IP
215
270
  *
216
271
  * @param {string} protocol
217
272
  * @param {number} latency
273
+ * @param {string|null} [publicIp]
218
274
  * @returns {void}
219
275
  */
220
- private storeLatencyResult(protocol: 'udp' | 'tcp' | 'xtls', latency: number) {
276
+ private saveResult(protocol: 'udp' | 'tcp' | 'xtls', latency: number, publicIp?: string | null) {
221
277
  const result = this.result[protocol];
222
278
 
223
279
  if (result.latencyInMilliseconds === undefined) {
224
280
  LoggerProxy.logger.log(
225
281
  // @ts-ignore
226
- `Reachability:index#storeLatencyResult --> Successfully reached ${this.name} over ${protocol}: ${latency}ms`
282
+ `Reachability:index#saveResult --> Successfully reached ${this.name} over ${protocol}: ${latency}ms`
227
283
  );
228
284
  result.latencyInMilliseconds = latency;
229
285
  result.result = 'reachable';
286
+ if (publicIp) {
287
+ result.clientMediaIPs = [publicIp];
288
+ }
289
+
290
+ this.emit(
291
+ {
292
+ file: 'clusterReachability',
293
+ function: 'saveResult',
294
+ },
295
+ Events.resultReady,
296
+ {
297
+ protocol,
298
+ ...result,
299
+ }
300
+ );
301
+ } else {
302
+ this.addPublicIP(protocol, publicIp);
230
303
  }
231
304
  }
232
305
 
@@ -243,15 +316,16 @@ export class ClusterReachability {
243
316
  RELAY: 'relay',
244
317
  };
245
318
 
319
+ const latencyInMilliseconds = this.getElapsedTime();
320
+
246
321
  if (e.candidate) {
247
322
  if (e.candidate.type === CANDIDATE_TYPES.SERVER_REFLEXIVE) {
248
- this.storeLatencyResult('udp', this.getElapsedTime());
249
- this.addPublicIP('udp', e.candidate.address);
323
+ this.saveResult('udp', latencyInMilliseconds, e.candidate.address);
250
324
  }
251
325
 
252
326
  if (e.candidate.type === CANDIDATE_TYPES.RELAY) {
253
327
  const protocol = e.candidate.port === TURN_TLS_PORT ? 'xtls' : 'tcp';
254
- this.storeLatencyResult(protocol, this.getElapsedTime());
328
+ this.saveResult(protocol, latencyInMilliseconds);
255
329
  // we don't add public IP for TCP, because in the case of relay candidates
256
330
  // e.candidate.address is the TURN server address, not the client's public IP
257
331
  }
@@ -314,22 +388,9 @@ export class ClusterReachability {
314
388
  * @returns {Promise} promise that's resolved once reachability checks for this cluster are completed or timeout is reached
315
389
  */
316
390
  private gatherIceCandidates() {
317
- const timeout = this.isVideoMesh ? VIDEO_MESH_TIMEOUT : DEFAULT_TIMEOUT;
318
-
319
391
  this.registerIceGatheringStateChangeListener();
320
392
  this.registerIceCandidateListener();
321
393
 
322
- // Set maximum timeout
323
- setTimeout(() => {
324
- const {CLOSED} = CONNECTION_STATE;
325
-
326
- // Close any open peerConnections
327
- if (this.pc.connectionState !== CLOSED) {
328
- this.closePeerConnection();
329
- this.finishReachabilityCheck();
330
- }
331
- }, timeout);
332
-
333
394
  return this.defer.promise;
334
395
  }
335
396
  }