@webex/plugin-meetings 3.8.0-next.8 → 3.8.0-web-workers-keepalive.1

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.
Files changed (64) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.js +1 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/interpretation/index.js +1 -1
  6. package/dist/interpretation/siLanguage.js +1 -1
  7. package/dist/locus-info/controlsUtils.js +1 -1
  8. package/dist/locus-info/controlsUtils.js.map +1 -1
  9. package/dist/meeting/index.js +51 -5
  10. package/dist/meeting/index.js.map +1 -1
  11. package/dist/meeting/util.js +4 -1
  12. package/dist/meeting/util.js.map +1 -1
  13. package/dist/meeting-info/meeting-info-v2.js +359 -60
  14. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  15. package/dist/meetings/index.js +60 -1
  16. package/dist/meetings/index.js.map +1 -1
  17. package/dist/member/index.js +10 -0
  18. package/dist/member/index.js.map +1 -1
  19. package/dist/member/util.js +3 -0
  20. package/dist/member/util.js.map +1 -1
  21. package/dist/metrics/constants.js +9 -0
  22. package/dist/metrics/constants.js.map +1 -1
  23. package/dist/reachability/clusterReachability.js +52 -8
  24. package/dist/reachability/clusterReachability.js.map +1 -1
  25. package/dist/reachability/index.js +70 -45
  26. package/dist/reachability/index.js.map +1 -1
  27. package/dist/reachability/reachability.types.js +14 -0
  28. package/dist/reachability/reachability.types.js.map +1 -1
  29. package/dist/reachability/request.js +19 -3
  30. package/dist/reachability/request.js.map +1 -1
  31. package/dist/types/config.d.ts +1 -0
  32. package/dist/types/meeting/index.d.ts +8 -0
  33. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  34. package/dist/types/meetings/index.d.ts +29 -0
  35. package/dist/types/member/index.d.ts +1 -0
  36. package/dist/types/metrics/constants.d.ts +9 -0
  37. package/dist/types/reachability/clusterReachability.d.ts +13 -1
  38. package/dist/types/reachability/index.d.ts +2 -1
  39. package/dist/types/reachability/reachability.types.d.ts +5 -0
  40. package/dist/webinar/index.js +1 -1
  41. package/package.json +22 -22
  42. package/src/config.ts +1 -0
  43. package/src/locus-info/controlsUtils.ts +2 -2
  44. package/src/meeting/index.ts +51 -7
  45. package/src/meeting/util.ts +2 -1
  46. package/src/meeting-info/meeting-info-v2.ts +247 -6
  47. package/src/meetings/index.ts +72 -1
  48. package/src/member/index.ts +11 -0
  49. package/src/member/util.ts +3 -0
  50. package/src/metrics/constants.ts +9 -0
  51. package/src/reachability/clusterReachability.ts +47 -1
  52. package/src/reachability/index.ts +15 -0
  53. package/src/reachability/reachability.types.ts +6 -0
  54. package/src/reachability/request.ts +7 -0
  55. package/test/unit/spec/locus-info/controlsUtils.js +8 -0
  56. package/test/unit/spec/meeting/index.js +62 -4
  57. package/test/unit/spec/meeting/utils.js +55 -0
  58. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  59. package/test/unit/spec/meetings/index.js +78 -1
  60. package/test/unit/spec/member/index.js +7 -0
  61. package/test/unit/spec/member/util.js +24 -0
  62. package/test/unit/spec/reachability/clusterReachability.ts +47 -1
  63. package/test/unit/spec/reachability/index.ts +12 -0
  64. package/test/unit/spec/reachability/request.js +47 -2
@@ -285,7 +285,8 @@ describe('plugin-meetings', () => {
285
285
 
286
286
  describe('failure', () => {
287
287
  it('should not accept non-number input', () => {
288
- const logUploadIntervalMultiplicationFactor = webex.meetings.config.logUploadIntervalMultiplicationFactor;
288
+ const logUploadIntervalMultiplicationFactor =
289
+ webex.meetings.config.logUploadIntervalMultiplicationFactor;
289
290
 
290
291
  webex.meetings._setLogUploadIntervalMultiplicationFactor('test');
291
292
  assert.equal(
@@ -441,6 +442,19 @@ describe('plugin-meetings', () => {
441
442
  assert.isTrue(webex.meetings.registered);
442
443
  });
443
444
 
445
+ it('resolves even if startReachability() rejects', async () => {
446
+ webex.canAuthorize = true;
447
+ webex.meetings.registered = false;
448
+ webex.meetings.startReachability = sinon.stub().rejects(new Error('fake error'));
449
+
450
+ await webex.meetings.register();
451
+ assert.calledOnceWithExactly(webex.internal.device.register, undefined);
452
+ assert.called(webex.internal.services.getMeetingPreferences);
453
+ assert.called(webex.internal.services.fetchClientRegionInfo);
454
+ assert.called(webex.internal.mercury.connect);
455
+ assert.isTrue(webex.meetings.registered);
456
+ });
457
+
444
458
  it('passes on the device registration options', async () => {
445
459
  webex.canAuthorize = true;
446
460
  webex.meetings.registered = false;
@@ -918,6 +932,69 @@ describe('plugin-meetings', () => {
918
932
  });
919
933
  });
920
934
  });
935
+ describe('#fetchStaticMeetingLink', () => {
936
+ const conversationUrl = 'conv.fakeconversationurl.com';
937
+
938
+ afterEach(() => {
939
+ sinon.restore();
940
+ });
941
+
942
+ it('should have #fetchStaticMeetingLink', () => {
943
+ assert.exists(webex.meetings.fetchStaticMeetingLink);
944
+ });
945
+
946
+ it('should call MeetingInfo#fetchStaticMeetingLink() with proper params', () => {
947
+ webex.meetings.meetingInfo.fetchStaticMeetingLink = sinon
948
+ .stub()
949
+ .resolves(conversationUrl);
950
+
951
+ return webex.meetings.fetchStaticMeetingLink(conversationUrl).then(() => {
952
+ assert.calledWith(webex.meetings.meetingInfo.fetchStaticMeetingLink, conversationUrl);
953
+ });
954
+ });
955
+ });
956
+ describe('#enableStaticMeetingLink', () => {
957
+ const conversationUrl = 'conv.fakeconversationurl.com';
958
+
959
+ afterEach(() => {
960
+ sinon.restore();
961
+ });
962
+
963
+ it('should have #enableStaticMeetingLink', () => {
964
+ assert.exists(webex.meetings.enableStaticMeetingLink);
965
+ });
966
+
967
+ it('should call MeetingInfo#enableStaticMeetingLink() with proper params', () => {
968
+ webex.meetings.meetingInfo.enableStaticMeetingLink = sinon
969
+ .stub()
970
+ .resolves(conversationUrl);
971
+
972
+ return webex.meetings.enableStaticMeetingLink(conversationUrl).then(() => {
973
+ assert.calledWith(webex.meetings.meetingInfo.enableStaticMeetingLink, conversationUrl);
974
+ });
975
+ });
976
+ });
977
+ describe('#disableStaticMeetingLink', () => {
978
+ const conversationUrl = 'conv.fakeconversationurl.com';
979
+
980
+ afterEach(() => {
981
+ sinon.restore();
982
+ });
983
+
984
+ it('should have #disableStaticMeetingLink', () => {
985
+ assert.exists(webex.meetings.disableStaticMeetingLink);
986
+ });
987
+
988
+ it('should call MeetingInfo#disableStaticMeetingLink() with proper params', () => {
989
+ webex.meetings.meetingInfo.disableStaticMeetingLink = sinon
990
+ .stub()
991
+ .resolves(conversationUrl);
992
+
993
+ return webex.meetings.disableStaticMeetingLink(conversationUrl).then(() => {
994
+ assert.calledWith(webex.meetings.meetingInfo.disableStaticMeetingLink, conversationUrl);
995
+ });
996
+ });
997
+ });
921
998
  describe('#create', () => {
922
999
  let infoOptions;
923
1000
 
@@ -50,6 +50,13 @@ describe('member', () => {
50
50
 
51
51
  assert.calledOnceWithExactly(MemberUtil.canReclaimHost, participant);
52
52
  });
53
+
54
+ it('checks that processParticipant calls isPresenterAssignmentProhibited', () => {
55
+ sinon.spy(MemberUtil, 'isPresenterAssignmentProhibited');
56
+ member.processParticipant(participant);
57
+
58
+ assert.calledOnceWithExactly(MemberUtil.isPresenterAssignmentProhibited, participant);
59
+ });
53
60
  })
54
61
 
55
62
  describe('#processMember', () => {
@@ -557,6 +557,30 @@ describe('plugin-meetings', () => {
557
557
  testResult(false, undefined, false);
558
558
  });
559
559
  });
560
+
561
+ describe('MemberUtil.isPresenterAssignmentProhibited', () => {
562
+ it('returns true when isPresenterAssignmentProhibited is true', () => {
563
+ const participant = {
564
+ presenterAssignmentNotAllowed: true
565
+ };
566
+
567
+ assert.isTrue(MemberUtil.isPresenterAssignmentProhibited(participant));
568
+ });
569
+
570
+ it('returns false when isPresenterAssignmentProhibited is false', () => {
571
+ const participant = {
572
+ presenterAssignmentNotAllowed: false,
573
+ };
574
+
575
+ assert.isFalse(MemberUtil.isPresenterAssignmentProhibited(participant));
576
+ });
577
+
578
+ it('returns undefined when isPresenterAssignmentProhibited is undefined', () => {
579
+ const participant = {};
580
+
581
+ assert.isUndefined(MemberUtil.isPresenterAssignmentProhibited(participant));
582
+ });
583
+ });
560
584
  });
561
585
 
562
586
  describe('extractMediaStatus', () => {
@@ -9,7 +9,9 @@ import {
9
9
  ResultEventData,
10
10
  Events,
11
11
  ClientMediaIpsUpdatedEventData,
12
+ NatTypeUpdatedEventData,
12
13
  } from '@webex/plugin-meetings/src/reachability/clusterReachability'; // replace with actual path
14
+ import { NatType } from 'packages/@webex/plugin-meetings/dist/reachability/reachability.types';
13
15
 
14
16
  describe('ClusterReachability', () => {
15
17
  let previousRTCPeerConnection;
@@ -17,15 +19,17 @@ describe('ClusterReachability', () => {
17
19
  let fakePeerConnection;
18
20
  let gatherIceCandidatesSpy;
19
21
 
20
- const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
22
+ const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData | NatTypeUpdatedEventData)[]> = {
21
23
  [Events.resultReady]: [],
22
24
  [Events.clientMediaIpsUpdated]: [],
25
+ [Events.natTypeUpdated]: [],
23
26
  };
24
27
  const FAKE_OFFER = {type: 'offer', sdp: 'fake sdp'};
25
28
 
26
29
  const resetEmittedEvents = () => {
27
30
  emittedEvents[Events.resultReady].length = 0;
28
31
  emittedEvents[Events.clientMediaIpsUpdated].length = 0;
32
+ emittedEvents[Events.natTypeUpdated].length = 0;
29
33
  };
30
34
  beforeEach(() => {
31
35
  fakePeerConnection = {
@@ -56,6 +60,10 @@ describe('ClusterReachability', () => {
56
60
  clusterReachability.on(Events.clientMediaIpsUpdated, (data: ClientMediaIpsUpdatedEventData) => {
57
61
  emittedEvents[Events.clientMediaIpsUpdated].push(data);
58
62
  });
63
+
64
+ clusterReachability.on(Events.natTypeUpdated, (data: NatTypeUpdatedEventData) => {
65
+ emittedEvents[Events.natTypeUpdated].push(data);
66
+ });
59
67
  });
60
68
 
61
69
  afterEach(() => {
@@ -440,5 +448,43 @@ describe('ClusterReachability', () => {
440
448
  xtls: {result: 'reachable', latencyInMilliseconds: 40},
441
449
  });
442
450
  });
451
+
452
+ it('determines correctly if symmetric-nat is detected', async () => {
453
+ const promise = clusterReachability.start();
454
+
455
+ // generate candidates with duplicate addresses
456
+ await clock.tickAsync(10);
457
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 1000}});
458
+
459
+ // check events emitted: there shouldn't be any natTypeUpdated emitted
460
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 0);
461
+
462
+ await clock.tickAsync(10);
463
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 2000}});
464
+
465
+ // should emit natTypeUpdated event
466
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 1);
467
+ assert.deepEqual(emittedEvents[Events.natTypeUpdated][0], {
468
+ natType: 'symmetric-nat',
469
+ });
470
+
471
+ // send also a relay candidate so that the reachability check finishes
472
+ fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
473
+ fakePeerConnection.onicecandidate({
474
+ candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
475
+ });
476
+
477
+ await promise;
478
+
479
+ assert.deepEqual(clusterReachability.getResult(), {
480
+ udp: {
481
+ result: 'reachable',
482
+ latencyInMilliseconds: 10,
483
+ clientMediaIPs: ['somePublicIp1'],
484
+ },
485
+ tcp: {result: 'reachable', latencyInMilliseconds: 20},
486
+ xtls: {result: 'reachable', latencyInMilliseconds: 20},
487
+ });
488
+ });
443
489
  });
444
490
  });
@@ -538,6 +538,14 @@ describe('gatherReachability', () => {
538
538
  assert.equal(storedResultForJoinCookie, JSON.stringify(expectedJoinCookie));
539
539
  };
540
540
 
541
+ it('rejects if reachability is disabled in config', async () => {
542
+ webex.config.meetings.enableReachabilityChecks = false;
543
+
544
+ const reachability = new Reachability(webex);
545
+
546
+ await assert.isRejected(reachability.gatherReachability('test'), 'enableReachabilityChecks is disabled in config');
547
+ });
548
+
541
549
  [
542
550
  // ========================================================================
543
551
  {
@@ -2148,6 +2156,7 @@ describe('getReachabilityMetrics', () => {
2148
2156
  reachability_vmn_tcp_failed: 0,
2149
2157
  reachability_vmn_xtls_success: 0,
2150
2158
  reachability_vmn_xtls_failed: 0,
2159
+ natType: 'unknown'
2151
2160
  });
2152
2161
  });
2153
2162
 
@@ -2215,6 +2224,7 @@ describe('getReachabilityMetrics', () => {
2215
2224
  reachability_vmn_tcp_failed: 1,
2216
2225
  reachability_vmn_xtls_success: 0,
2217
2226
  reachability_vmn_xtls_failed: 0,
2227
+ natType: 'unknown'
2218
2228
  }
2219
2229
  );
2220
2230
  });
@@ -2276,6 +2286,7 @@ describe('getReachabilityMetrics', () => {
2276
2286
  reachability_vmn_tcp_failed: 0,
2277
2287
  reachability_vmn_xtls_success: 0,
2278
2288
  reachability_vmn_xtls_failed: 0,
2289
+ natType: 'unknown'
2279
2290
  }
2280
2291
  );
2281
2292
  });
@@ -2337,6 +2348,7 @@ describe('getReachabilityMetrics', () => {
2337
2348
  reachability_vmn_tcp_failed: 3,
2338
2349
  reachability_vmn_xtls_success: 1,
2339
2350
  reachability_vmn_xtls_failed: 1,
2351
+ natType: 'unknown'
2340
2352
  }
2341
2353
  );
2342
2354
  });
@@ -12,6 +12,9 @@ describe('plugin-meetings/reachability', () => {
12
12
  let reachabilityRequest;
13
13
  let webex;
14
14
 
15
+ let appType;
16
+ let appVersion;
17
+
15
18
  beforeEach(() => {
16
19
  webex = new MockWebex({
17
20
  children: {
@@ -20,6 +23,14 @@ describe('plugin-meetings/reachability', () => {
20
23
  },
21
24
  });
22
25
 
26
+ webex.config.support = {
27
+ 'appType': 'NetworkChecker',
28
+ 'appVersion': '43.3.0.1',
29
+ }
30
+
31
+ appType = webex?.config?.support?.appType;
32
+ appVersion = webex?.config?.support?.appVersion;
33
+
23
34
  webex.meetings.clientRegion = {
24
35
  countryCode: 'US',
25
36
  regionCode: 'WEST-COAST',
@@ -56,7 +67,9 @@ describe('plugin-meetings/reachability', () => {
56
67
 
57
68
  previousReport = {
58
69
  id: 'fake previous report',
59
- }
70
+ };
71
+
72
+
60
73
  });
61
74
 
62
75
  afterEach(() => {
@@ -79,6 +92,7 @@ describe('plugin-meetings/reachability', () => {
79
92
  'report-version': 1,
80
93
  'early-call-min-clusters': true,
81
94
  },
95
+ 'client-environment': { components: { [appType]: appVersion } },
82
96
  'previous-report': previousReport,
83
97
  trigger: 'startup',
84
98
  },
@@ -105,6 +119,7 @@ describe('plugin-meetings/reachability', () => {
105
119
  'report-version': 1,
106
120
  'early-call-min-clusters': true,
107
121
  },
122
+ 'client-environment': { components: { [appType]: appVersion } },
108
123
  'previous-report': previousReport,
109
124
  trigger: 'early-call/no-min-reached',
110
125
  },
@@ -114,5 +129,35 @@ describe('plugin-meetings/reachability', () => {
114
129
  assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"})
115
130
  assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency);
116
131
  });
132
+
133
+ it('sends a POST request with the correct params when appVersion is undefined', async () => {
134
+ // Setting appType & appVersion to undefined
135
+ webex.config.support.appType = undefined;
136
+ webex.config.support.appVersion = undefined;
137
+
138
+ const res = await reachabilityRequest.getClusters('startup', IP_VERSION.only_ipv4, previousReport);
139
+ const requestParams = webex.request.getCall(0).args[0];
140
+
141
+ assert.deepEqual(requestParams, {
142
+ method: 'POST',
143
+ resource: `clusters`,
144
+ api: 'calliopeDiscovery',
145
+ shouldRefreshAccessToken: false,
146
+ timeout: 3000,
147
+ body: {
148
+ ipver: IP_VERSION.only_ipv4,
149
+ 'supported-options': {
150
+ 'report-version': 1,
151
+ 'early-call-min-clusters': true,
152
+ },
153
+ 'previous-report': previousReport,
154
+ trigger: 'startup',
155
+ },
156
+ });
157
+
158
+ assert.deepEqual(res.clusters.clusterId, {udp: "testUDP", isVideoMesh: true});
159
+ assert.deepEqual(res.joinCookie, {anycastEntryPoint: "aws-eu-west-1"});
160
+ assert.calledOnceWithExactly(webex.internal.newMetrics.callDiagnosticLatencies.measureLatency, sinon.match.func, 'internal.get.cluster.time');
161
+ });
117
162
  });
118
- });
163
+ });