@webex/internal-plugin-metrics 3.12.0-next.3 → 3.12.0-next.30

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 (39) hide show
  1. package/dist/batcher.js +3 -0
  2. package/dist/batcher.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js +23 -0
  4. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +68 -51
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +59 -8
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +5 -0
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  11. package/dist/call-diagnostic/config.js +16 -3
  12. package/dist/call-diagnostic/config.js.map +1 -1
  13. package/dist/config.js +1 -0
  14. package/dist/config.js.map +1 -1
  15. package/dist/metrics.js +1 -1
  16. package/dist/metrics.types.js.map +1 -1
  17. package/dist/prelogin-metrics-batcher.js +23 -0
  18. package/dist/prelogin-metrics-batcher.js.map +1 -1
  19. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +9 -0
  20. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +39 -13
  21. package/dist/types/call-diagnostic/config.d.ts +4 -0
  22. package/dist/types/config.d.ts +1 -0
  23. package/dist/types/metrics.types.d.ts +2 -2
  24. package/package.json +11 -11
  25. package/src/batcher.js +4 -0
  26. package/src/call-diagnostic/call-diagnostic-metrics-batcher.ts +26 -0
  27. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +140 -69
  28. package/src/call-diagnostic/call-diagnostic-metrics.ts +51 -1
  29. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +5 -0
  30. package/src/call-diagnostic/config.ts +14 -0
  31. package/src/config.js +1 -0
  32. package/src/metrics.types.ts +1 -1
  33. package/src/prelogin-metrics-batcher.ts +26 -0
  34. package/test/unit/spec/batcher.js +43 -0
  35. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +150 -2
  36. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +243 -288
  37. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +689 -159
  38. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -0
  39. package/test/unit/spec/prelogin-metrics-batcher.ts +190 -36
@@ -193,7 +193,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
193
193
  */
194
194
  public getShowInterstitialTime() {
195
195
  return this.getDiffBetweenTimestamps(
196
- 'client.interstitial-window.start-launch',
196
+ 'internal.client.meeting.interstitial-window.showed',
197
197
  'internal.client.interstitial-window.click.joinbutton'
198
198
  );
199
199
  }
@@ -224,11 +224,17 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
224
224
  * @returns - latency
225
225
  */
226
226
  public getCallInitJoinReq() {
227
- return this.getDiffBetweenTimestamps(
228
- 'internal.client.interstitial-window.click.joinbutton',
229
- 'client.locus.join.request',
230
- {maximum: 1200000}
227
+ const interstitialShowedToJoinReq = this.getDiffBetweenTimestamps(
228
+ 'internal.client.meeting.interstitial-window.showed',
229
+ 'client.locus.join.request'
231
230
  );
231
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
232
+
233
+ if (typeof interstitialShowedToJoinReq !== 'number') {
234
+ return undefined;
235
+ }
236
+
237
+ return clamp(interstitialShowedToJoinReq - showInterstitialTime, 0, 1200000);
232
238
  }
233
239
 
234
240
  /**
@@ -303,7 +309,39 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
303
309
  * @returns - latency
304
310
  */
305
311
  public getStayLobbyTime() {
306
- return this.getDiffBetweenTimestamps('client.locus.join.response', 'client.lobby.exited');
312
+ return this.getDiffBetweenTimestamps('client.lobby.entered', 'client.lobby.exited');
313
+ }
314
+
315
+ /**
316
+ * Stay lobby time capped by a certain timestamp.
317
+ * This is to handle the case where the target end timestamp could happen before the lobby is exited,
318
+ * for example media-engine.ready or client.ice.end
319
+ * This is supposed to be called AFTER the end timestamp happens
320
+ * @param endTimestampKey name of the target end event
321
+ * @returns - latency
322
+ */
323
+ public getStayLobbyTimeCappedBy(endTimestampKey: MetricEventNames) {
324
+ const lobbyStartTimestamp = this.latencyTimestamps.get('client.lobby.entered'); // might not exist (some meetings don't have lobby)
325
+
326
+ if (typeof lobbyStartTimestamp !== 'number') {
327
+ // no lobby in the meeting, stayLobbyTime is 0
328
+ return 0;
329
+ }
330
+
331
+ const lobbyEndTimestamp = this.latencyTimestamps.get('client.lobby.exited'); // might not exist (if user still in lobby at the time of measurement)
332
+ const maximumEndTimestamp = this.latencyTimestamps.get(endTimestampKey); // must exist
333
+
334
+ if (typeof maximumEndTimestamp !== 'number') {
335
+ // the provided timestamp to be used as a cap should exist, return undefined if it doesn't
336
+ return undefined;
337
+ }
338
+
339
+ const endTimestamp =
340
+ typeof lobbyEndTimestamp === 'number'
341
+ ? Math.min(lobbyEndTimestamp, maximumEndTimestamp)
342
+ : maximumEndTimestamp;
343
+
344
+ return clamp(endTimestamp - lobbyStartTimestamp, 0, this.MAX_INTEGER);
307
345
  }
308
346
 
309
347
  /**
@@ -331,14 +369,6 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
331
369
  * @returns - latency
332
370
  */
333
371
  public getClickToInterstitial() {
334
- // for normal join (where green join button exists before interstitial, i.e reminder, space list etc)
335
- if (this.latencyTimestamps.get('internal.client.meeting.click.joinbutton')) {
336
- return this.getDiffBetweenTimestamps(
337
- 'internal.client.meeting.click.joinbutton',
338
- 'internal.client.meeting.interstitial-window.showed'
339
- );
340
- }
341
-
342
372
  const clickToInterstitialLatency = this.precomputedLatencies.get(
343
373
  'internal.click.to.interstitial'
344
374
  );
@@ -355,14 +385,6 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
355
385
  * @returns - latency
356
386
  */
357
387
  public getClickToInterstitialWithUserDelay() {
358
- // for normal join (where green join button exists before interstitial, i.e reminder, space list etc)
359
- if (this.latencyTimestamps.get('internal.client.meeting.click.joinbutton')) {
360
- return this.getDiffBetweenTimestamps(
361
- 'internal.client.meeting.click.joinbutton',
362
- 'internal.client.meeting.interstitial-window.showed'
363
- );
364
- }
365
-
366
388
  const clickToInterstitialWithUserDelayLatency = this.precomputedLatencies.get(
367
389
  'internal.click.to.interstitial.with.user.delay'
368
390
  );
@@ -379,10 +401,17 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
379
401
  * @returns - latency
380
402
  */
381
403
  public getInterstitialToJoinOK() {
382
- return this.getDiffBetweenTimestamps(
383
- 'internal.client.interstitial-window.click.joinbutton',
404
+ const interstitialShowedToJoinResp = this.getDiffBetweenTimestamps(
405
+ 'internal.client.meeting.interstitial-window.showed',
384
406
  'client.locus.join.response'
385
407
  );
408
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
409
+
410
+ if (typeof interstitialShowedToJoinResp !== 'number') {
411
+ return undefined;
412
+ }
413
+
414
+ return clamp(interstitialShowedToJoinResp - showInterstitialTime, 0, this.MAX_INTEGER);
386
415
  }
387
416
 
388
417
  /**
@@ -390,11 +419,7 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
390
419
  * @returns - latency
391
420
  */
392
421
  public getCallInitMediaEngineReady() {
393
- return this.getDiffBetweenTimestamps(
394
- 'internal.client.interstitial-window.click.joinbutton',
395
- 'client.media-engine.ready',
396
- {maximum: 1200000}
397
- );
422
+ return this.getInterstitialToMediaOKJMT();
398
423
  }
399
424
 
400
425
  /**
@@ -402,20 +427,22 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
402
427
  * @returns - latency
403
428
  */
404
429
  public getInterstitialToMediaOKJMT() {
405
- const interstitialJoinClickTimestamp = this.latencyTimestamps.get(
406
- 'internal.client.interstitial-window.click.joinbutton'
430
+ const interstitialShowedToIceEnd = this.getDiffBetweenTimestamps(
431
+ 'internal.client.meeting.interstitial-window.showed',
432
+ 'client.ice.end'
407
433
  );
434
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
435
+ const stayLobbyTimeCappedByIceEnd = this.getStayLobbyTimeCappedBy('client.ice.end');
408
436
 
409
- // get the first timestamp
410
- const connectedMedia = this.latencyTimestamps.get('client.ice.end');
411
-
412
- const lobbyTimeLatency = this.getStayLobbyTime();
413
- const lobbyTime = typeof lobbyTimeLatency === 'number' ? lobbyTimeLatency : 0;
414
-
415
- if (interstitialJoinClickTimestamp && connectedMedia) {
416
- const interstitialToMediaOKJmt = connectedMedia - interstitialJoinClickTimestamp - lobbyTime;
417
-
418
- return clamp(interstitialToMediaOKJmt, 0, this.MAX_INTEGER);
437
+ if (
438
+ typeof interstitialShowedToIceEnd === 'number' &&
439
+ typeof stayLobbyTimeCappedByIceEnd === 'number'
440
+ ) {
441
+ return clamp(
442
+ interstitialShowedToIceEnd - showInterstitialTime - stayLobbyTimeCappedByIceEnd,
443
+ 0,
444
+ this.MAX_INTEGER
445
+ );
419
446
  }
420
447
 
421
448
  return undefined;
@@ -427,10 +454,21 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
427
454
  */
428
455
  public getTotalJMT() {
429
456
  const clickToInterstitial = this.getClickToInterstitial();
430
- const interstitialToJoinOk = this.getInterstitialToJoinOK();
457
+ const interstitialShowedToJoinLocusResponse = this.getDiffBetweenTimestamps(
458
+ 'internal.client.meeting.interstitial-window.showed',
459
+ 'client.locus.join.response'
460
+ );
461
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
431
462
 
432
- if (typeof clickToInterstitial === 'number' && typeof interstitialToJoinOk === 'number') {
433
- return clamp(clickToInterstitial + interstitialToJoinOk, 0, this.MAX_INTEGER);
463
+ if (
464
+ typeof clickToInterstitial === 'number' &&
465
+ typeof interstitialShowedToJoinLocusResponse === 'number'
466
+ ) {
467
+ return clamp(
468
+ clickToInterstitial + interstitialShowedToJoinLocusResponse - showInterstitialTime,
469
+ 0,
470
+ this.MAX_INTEGER
471
+ );
434
472
  }
435
473
 
436
474
  return undefined;
@@ -442,13 +480,20 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
442
480
  */
443
481
  public getTotalJMTWithUserDelay() {
444
482
  const clickToInterstitialWithUserDelay = this.getClickToInterstitialWithUserDelay();
445
- const interstitialToJoinOk = this.getInterstitialToJoinOK();
483
+ const interstitialShowedToJoinLocusResponse = this.getDiffBetweenTimestamps(
484
+ 'internal.client.meeting.interstitial-window.showed',
485
+ 'client.locus.join.response'
486
+ );
446
487
 
447
488
  if (
448
489
  typeof clickToInterstitialWithUserDelay === 'number' &&
449
- typeof interstitialToJoinOk === 'number'
490
+ typeof interstitialShowedToJoinLocusResponse === 'number'
450
491
  ) {
451
- return clamp(clickToInterstitialWithUserDelay + interstitialToJoinOk, 0, this.MAX_INTEGER);
492
+ return clamp(
493
+ clickToInterstitialWithUserDelay + interstitialShowedToJoinLocusResponse,
494
+ 0,
495
+ this.MAX_INTEGER
496
+ );
452
497
  }
453
498
 
454
499
  return undefined;
@@ -475,22 +520,28 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
475
520
  */
476
521
  public getTotalMediaJMT() {
477
522
  const clickToInterstitial = this.getClickToInterstitial();
478
- const interstitialToJoinOk = this.getInterstitialToJoinOK();
479
- const joinConfJMT = this.getJoinConfJMT();
480
- const lobbyTimeLatency = this.getStayLobbyTime();
481
- const lobbyTime = typeof lobbyTimeLatency === 'number' ? lobbyTimeLatency : 0;
482
-
483
- if (clickToInterstitial && interstitialToJoinOk && joinConfJMT) {
484
- const totalMediaJMT = clamp(
485
- clickToInterstitial + interstitialToJoinOk + joinConfJMT,
523
+ const interstitialShowedToMediaEngineReady = this.getDiffBetweenTimestamps(
524
+ 'internal.client.meeting.interstitial-window.showed',
525
+ 'client.media-engine.ready'
526
+ );
527
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
528
+ const stayLobbyTimeCappedByMediaEngineReady = this.getStayLobbyTimeCappedBy(
529
+ 'client.media-engine.ready'
530
+ );
531
+
532
+ if (
533
+ typeof clickToInterstitial === 'number' &&
534
+ typeof interstitialShowedToMediaEngineReady === 'number' &&
535
+ typeof stayLobbyTimeCappedByMediaEngineReady === 'number'
536
+ ) {
537
+ return clamp(
538
+ clickToInterstitial +
539
+ interstitialShowedToMediaEngineReady -
540
+ showInterstitialTime -
541
+ stayLobbyTimeCappedByMediaEngineReady,
486
542
  0,
487
- Infinity
543
+ this.MAX_INTEGER
488
544
  );
489
- if (this.getMeeting()?.allowMediaInLobby) {
490
- return clamp(totalMediaJMT, 0, this.MAX_INTEGER);
491
- }
492
-
493
- return clamp(totalMediaJMT - lobbyTime, 0, this.MAX_INTEGER);
494
545
  }
495
546
 
496
547
  return undefined;
@@ -502,12 +553,17 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
502
553
  */
503
554
  public getTotalMediaJMTWithUserDelay() {
504
555
  const clickToInterstitialWithUserDelay = this.getClickToInterstitialWithUserDelay();
505
- const interstitialToJoinOk = this.getInterstitialToJoinOK();
506
- const joinConfJMT = this.getJoinConfJMT();
556
+ const interstitialShowedToMediaEngineReady = this.getDiffBetweenTimestamps(
557
+ 'internal.client.meeting.interstitial-window.showed',
558
+ 'client.media-engine.ready'
559
+ );
507
560
 
508
- if (clickToInterstitialWithUserDelay && interstitialToJoinOk && joinConfJMT) {
561
+ if (
562
+ typeof clickToInterstitialWithUserDelay === 'number' &&
563
+ typeof interstitialShowedToMediaEngineReady === 'number'
564
+ ) {
509
565
  return clamp(
510
- clickToInterstitialWithUserDelay + interstitialToJoinOk + joinConfJMT,
566
+ clickToInterstitialWithUserDelay + interstitialShowedToMediaEngineReady,
511
567
  0,
512
568
  this.MAX_INTEGER
513
569
  );
@@ -521,11 +577,26 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
521
577
  * @returns - latency
522
578
  */
523
579
  public getClientJMT() {
524
- const interstitialToJoinOk = this.getInterstitialToJoinOK();
525
- const joinConfJMT = this.getJoinConfJMT();
580
+ const clickToInterstitialForClientJmt = this.precomputedLatencies.get(
581
+ 'internal.click.to.interstitial.for.client.jmt'
582
+ );
583
+ const interstitialShowedToLocusJoinRequest = this.getDiffBetweenTimestamps(
584
+ 'internal.client.meeting.interstitial-window.showed',
585
+ 'client.locus.join.request'
586
+ );
587
+ const showInterstitialTime = this.getShowInterstitialTime() || 0;
526
588
 
527
- if (typeof interstitialToJoinOk === 'number' && typeof joinConfJMT === 'number') {
528
- return clamp(interstitialToJoinOk - joinConfJMT, 0, this.MAX_INTEGER);
589
+ if (
590
+ typeof clickToInterstitialForClientJmt === 'number' &&
591
+ typeof interstitialShowedToLocusJoinRequest === 'number'
592
+ ) {
593
+ return clamp(
594
+ clickToInterstitialForClientJmt +
595
+ interstitialShowedToLocusJoinRequest -
596
+ showInterstitialTime,
597
+ 0,
598
+ this.MAX_INTEGER
599
+ );
529
600
  }
530
601
 
531
602
  return undefined;
@@ -108,6 +108,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
108
108
  private isMercuryConnected = false;
109
109
  private eventLimitTracker: Map<string, number> = new Map();
110
110
  private eventLimitWarningsLogged: Set<string> = new Set();
111
+ private isTelemetryOptOutManual = false;
112
+ private isTelemetryOptOutAutomatic = false;
111
113
 
112
114
  // the default validator before piping an event to the batcher
113
115
  // this function can be overridden by the user
@@ -145,6 +147,37 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
145
147
  return null;
146
148
  }
147
149
 
150
+ /**
151
+ * Returns the telemetryOptOut value of the current user
152
+ * @returns one of 'manual', 'automatic', undefined
153
+ */
154
+ public getTelemetryOptOut() {
155
+ if (this.isTelemetryOptOutManual) {
156
+ return 'manual';
157
+ }
158
+ if (this.isTelemetryOptOutAutomatic) {
159
+ return 'automatic';
160
+ }
161
+
162
+ return undefined;
163
+ }
164
+
165
+ /**
166
+ * Sets the manual telemetry opt-out status for the current user
167
+ * @param value - boolean value indicating manual telemetry opt-out status
168
+ */
169
+ public setIsTelemetryOptOutManual(value: boolean) {
170
+ this.isTelemetryOptOutManual = value;
171
+ }
172
+
173
+ /**
174
+ * Sets the automatic telemetry opt-out status for the current user
175
+ * @param value - boolean value indicating automatic telemetry opt-out status
176
+ */
177
+ public setIsTelemetryOptOutAutomatic(value: boolean) {
178
+ this.isTelemetryOptOutAutomatic = value;
179
+ }
180
+
148
181
  /**
149
182
  * Returns if the meeting has converged architecture enabled
150
183
  * @param options.meetingId
@@ -190,6 +223,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
190
223
 
191
224
  // if ConvergedArchitecture enable and isConvergedWebinarWebcast -- then webcast
192
225
  if (meetingInfo?.enableConvergedArchitecture && meetingInfo?.enableEvent) {
226
+ // if enableConvergedWebinarLargeScale - then large scale webinar
227
+ if (meetingInfo?.enableConvergedWebinarLargeScale) {
228
+ return WEBEX_SUB_SERVICE_TYPES.LARGE_SCALE_WEBINAR;
229
+ }
230
+
193
231
  return meetingInfo?.isConvergedWebinarWebcast
194
232
  ? WEBEX_SUB_SERVICE_TYPES.WEBCAST
195
233
  : WEBEX_SUB_SERVICE_TYPES.WEBINAR;
@@ -602,6 +640,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
602
640
  mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
603
641
  startTime: new Date().toISOString(),
604
642
  },
643
+ webexSubServiceType: this.getSubServiceType(meeting),
605
644
  };
606
645
 
607
646
  // merge any new properties, or override existing ones
@@ -984,7 +1023,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
984
1023
  sessionCorrelationId,
985
1024
  });
986
1025
 
987
- // create common event object structur
1026
+ // create common event object structure
988
1027
  const commonEventObject = {
989
1028
  name,
990
1029
  canProceed: true,
@@ -997,6 +1036,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
997
1036
  'loginType' in meeting.callStateForMetrics
998
1037
  ? meeting.callStateForMetrics.loginType
999
1038
  : this.getCurLoginType(),
1039
+ telemetryOptOut: this.getTelemetryOptOut(),
1000
1040
  isConvergedArchitectureEnabled: this.getIsConvergedArchitectureEnabled({
1001
1041
  meetingId,
1002
1042
  }),
@@ -1005,6 +1045,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1005
1045
  webexSubServiceType: this.getSubServiceType(meeting),
1006
1046
  // @ts-ignore
1007
1047
  webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
1048
+ isVipMeeting: meeting?.meetingInfo?.vipmeeting || false,
1049
+ isAutomatedUser:
1050
+ typeof window !== 'undefined' && typeof navigator !== 'undefined' && !!navigator?.webdriver, // if webdriver is true, it's most likely in a test environment
1008
1051
  };
1009
1052
 
1010
1053
  const joinFlowVersion = options.joinFlowVersion ?? meeting.callStateForMetrics?.joinFlowVersion;
@@ -1124,8 +1167,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1124
1167
  isMercuryConnected: this.isMercuryConnected,
1125
1168
  },
1126
1169
  loginType: this.getCurLoginType(),
1170
+ telemetryOptOut: this.getTelemetryOptOut(),
1127
1171
  // @ts-ignore
1128
1172
  webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
1173
+ isAutomatedUser:
1174
+ typeof window !== 'undefined' && typeof navigator !== 'undefined' && !!navigator?.webdriver, // if webdriver is true, it's most likely in a test environment
1129
1175
  };
1130
1176
 
1131
1177
  if (options.joinFlowVersion) {
@@ -1318,6 +1364,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1318
1364
  const finalEvent = {
1319
1365
  eventPayload: event,
1320
1366
  type: ['diagnostic-event'],
1367
+ markTelemetryOptOutOnResponse: true,
1321
1368
  };
1322
1369
 
1323
1370
  return this.callDiagnosticEventsBatcher.request(finalEvent);
@@ -1327,6 +1374,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1327
1374
  * Prepare the event and send the request to metrics-a service, pre login.
1328
1375
  * @param event
1329
1376
  * @param preLoginId
1377
+ * @param markTelemetryOptOutOnResponse
1330
1378
  * @returns
1331
1379
  */
1332
1380
  submitToCallDiagnosticsPreLogin = (event: Event, preLoginId?: string): Promise<any> => {
@@ -1334,7 +1382,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1334
1382
  const finalEvent = {
1335
1383
  eventPayload: event,
1336
1384
  type: ['diagnostic-event'],
1385
+ markTelemetryOptOutOnResponse: true,
1337
1386
  };
1387
+
1338
1388
  this.preLoginMetricsBatcher.savePreLoginId(preLoginId);
1339
1389
 
1340
1390
  return this.preLoginMetricsBatcher.request(finalEvent);
@@ -390,6 +390,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
390
390
 
391
391
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
392
392
 
393
+ // Mark call milestones in logs for easier filtering and analysis
394
+ if (eventName) {
395
+ webex.logger.log('Milestone,CallDiagnostic', eventName);
396
+ }
397
+
393
398
  webex.logger.log(
394
399
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
395
400
  latencies: Object.fromEntries(cdl.latencyTimestamps),
@@ -26,6 +26,7 @@ export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
26
26
  SCHEDULED_MEETING: 'ScheduledMeeting',
27
27
  WEBINAR: 'Webinar',
28
28
  WEBCAST: 'Webcast',
29
+ LARGE_SCALE_WEBINAR: 'LargeScaleWebinar',
29
30
  };
30
31
 
31
32
  // Found in https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
@@ -136,6 +137,7 @@ export const ERROR_DESCRIPTIONS = {
136
137
  WEBRTC_API_NOT_AVAILABLE: 'WebrtcApiNotAvailableError',
137
138
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
138
139
  USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
140
+ INVALID_MEETING_INFO: 'InvalidMeetingInfo',
139
141
  };
140
142
 
141
143
  export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
@@ -146,6 +148,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
146
148
  99002: 4100,
147
149
  // Cannot find the data. Unkown meeting.
148
150
  99009: 4100,
151
+ // The input parameters contain invalid item
152
+ 99019: 4105,
149
153
  // Meeting is not allow to cross env
150
154
  58500: 4100,
151
155
  // Input parameters contain invalit item
@@ -201,6 +205,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
201
205
  423005: 4005,
202
206
  // Wrong password or host key with too many requests
203
207
  423006: 4005,
208
+ // PanelistPasswordError too many time,please input captcha code
209
+ 423008: 4005,
204
210
  // PasswordError with right captcha, please input captcha code
205
211
  423010: 4005,
206
212
  // PasswordOrHostKeyError with right captcha, please input captcha code
@@ -227,6 +233,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
227
233
  403003: 4101,
228
234
  // Attendee email is required
229
235
  403030: 4101,
236
+ // webinar need login when un-invited attendee join
237
+ 403106: 4104,
230
238
 
231
239
  // ---- Locus ------
232
240
  // FREE_USER_MAX_PARTICIPANTS_EXCEEDED
@@ -696,6 +704,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
696
704
  category: 'expected',
697
705
  fatal: true,
698
706
  },
707
+ 4105: {
708
+ errorDescription: ERROR_DESCRIPTIONS.INVALID_MEETING_INFO,
709
+ category: 'expected',
710
+ fatal: false,
711
+ shownToUser: true,
712
+ },
699
713
  2729: {
700
714
  errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
701
715
  category: 'expected',
package/src/config.js CHANGED
@@ -19,6 +19,7 @@ export default {
19
19
  batcherMaxCalls: 50,
20
20
  batcherMaxWait: 1500,
21
21
  batcherRetryPlateau: 32000,
22
+ batcherRetryOnNetworkError: true,
22
23
  waitForServiceTimeout: 30,
23
24
  },
24
25
  };
@@ -156,7 +156,6 @@ export type InternalEvent = {
156
156
  | 'internal.register.device.request'
157
157
  | 'internal.register.device.response'
158
158
  | 'internal.reset.join.latencies'
159
- | 'internal.client.meeting.click.joinbutton'
160
159
  | 'internal.host.meeting.participant.admitted'
161
160
  | 'internal.client.meeting.interstitial-window.showed'
162
161
  | 'internal.client.interstitial-window.click.joinbutton'
@@ -319,6 +318,7 @@ export type PreComputedLatencies =
319
318
  | 'internal.get.cluster.time'
320
319
  | 'internal.click.to.interstitial'
321
320
  | 'internal.click.to.interstitial.with.user.delay'
321
+ | 'internal.click.to.interstitial.for.client.jmt'
322
322
  | 'internal.refresh.captcha.time'
323
323
  | 'internal.exchange.ci.token.time'
324
324
  | 'internal.get.u2c.time'
@@ -78,6 +78,8 @@ const PreLoginMetricsBatcher = Batcher.extend({
78
78
  `PreLoginMetricsBatcher: @submitHttpRequest#${batchId}. Request successful.`
79
79
  );
80
80
 
81
+ this.handleHttpResponseStatus(res?.statusCode, payload);
82
+
81
83
  return res;
82
84
  })
83
85
  .catch((err) => {
@@ -87,9 +89,33 @@ const PreLoginMetricsBatcher = Batcher.extend({
87
89
  `error: ${generateCommonErrorMetadata(err)}`
88
90
  );
89
91
 
92
+ this.handleHttpResponseStatus(err?.statusCode, payload);
93
+
90
94
  return Promise.reject(err);
91
95
  });
92
96
  },
97
+
98
+ /**
99
+ * React to the HTTP status code returned by the prelogin metrics endpoint.
100
+ * Only items submitted with `markTelemetryOptOutOnResponse: true` opt into
101
+ * this behavior.
102
+ * @param {number | undefined} statusCode
103
+ * @param {any[]} payload Items flushed in this HTTP batch.
104
+ * @returns {void}
105
+ */
106
+ handleHttpResponseStatus(statusCode: number | undefined, payload: any[]) {
107
+ const shouldMark =
108
+ Array.isArray(payload) &&
109
+ payload.some((item) => item?.markTelemetryOptOutOnResponse === true);
110
+
111
+ if (!shouldMark) {
112
+ return;
113
+ }
114
+
115
+ if (statusCode === 200) {
116
+ this.webex.internal.newMetrics?.callDiagnosticMetrics?.setIsTelemetryOptOutAutomatic(true);
117
+ }
118
+ },
93
119
  });
94
120
 
95
121
  export default PreLoginMetricsBatcher;
@@ -177,6 +177,49 @@ describe('plugin-metrics', () => {
177
177
  assert.lengthOf(webex.internal.metrics.batcher.queue, 0);
178
178
  });
179
179
  });
180
+
181
+ it('rejects the deferred without reenqueuing when batcherRetryOnNetworkError is false', () => {
182
+ webex.config.metrics = {...config.metrics, batcherRetryOnNetworkError: false};
183
+
184
+ webex.request = function () {
185
+ // noop
186
+ };
187
+
188
+ sinon.stub(webex, 'request').callsFake((options) => {
189
+ options.headers = {
190
+ trackingid: 'test-no-retry',
191
+ };
192
+
193
+ return Promise.reject(
194
+ new WebexHttpError.NetworkOrCORSError({
195
+ statusCode: 0,
196
+ options,
197
+ })
198
+ );
199
+ });
200
+
201
+ const promise = webex.internal.metrics.batcher.request({
202
+ key: 'testMetric',
203
+ });
204
+
205
+ return promiseTick(50)
206
+ .then(() => assert.lengthOf(webex.internal.metrics.batcher.queue, 1))
207
+ .then(() => clock.tick(config.metrics.batcherWait))
208
+ .then(() => assert.calledOnce(webex.request))
209
+ .then(() => promiseTick(50))
210
+ .then(() =>
211
+ promise.then(
212
+ () => {
213
+ assert.fail('promise should have been rejected');
214
+ },
215
+ (reason) => {
216
+ assert.instanceOf(reason, WebexHttpError.NetworkOrCORSError);
217
+ assert.lengthOf(webex.internal.metrics.batcher.queue, 0);
218
+ assert.calledOnce(webex.request);
219
+ }
220
+ )
221
+ );
222
+ });
180
223
  });
181
224
  });
182
225
  });