@webex/calling 3.8.0-next.31 → 3.8.0-next.33

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 (145) hide show
  1. package/dist/CallHistory/CallHistory.js +100 -63
  2. package/dist/CallHistory/CallHistory.js.map +1 -1
  3. package/dist/CallHistory/CallHistory.test.js +115 -19
  4. package/dist/CallHistory/CallHistory.test.js.map +1 -1
  5. package/dist/CallHistory/constants.js +9 -1
  6. package/dist/CallHistory/constants.js.map +1 -1
  7. package/dist/CallSettings/CallSettings.js +46 -13
  8. package/dist/CallSettings/CallSettings.js.map +1 -1
  9. package/dist/CallSettings/UcmBackendConnector.js +62 -18
  10. package/dist/CallSettings/UcmBackendConnector.js.map +1 -1
  11. package/dist/CallSettings/UcmBackendConnector.test.js +70 -7
  12. package/dist/CallSettings/UcmBackendConnector.test.js.map +1 -1
  13. package/dist/CallSettings/WxCallBackendConnector.js +153 -103
  14. package/dist/CallSettings/WxCallBackendConnector.js.map +1 -1
  15. package/dist/CallSettings/WxCallBackendConnector.test.js +52 -15
  16. package/dist/CallSettings/WxCallBackendConnector.test.js.map +1 -1
  17. package/dist/CallSettings/constants.js +15 -1
  18. package/dist/CallSettings/constants.js.map +1 -1
  19. package/dist/CallingClient/CallingClient.js +148 -107
  20. package/dist/CallingClient/CallingClient.js.map +1 -1
  21. package/dist/CallingClient/CallingClient.test.js +53 -24
  22. package/dist/CallingClient/CallingClient.test.js.map +1 -1
  23. package/dist/CallingClient/calling/call.js +251 -189
  24. package/dist/CallingClient/calling/call.js.map +1 -1
  25. package/dist/CallingClient/calling/call.test.js +96 -41
  26. package/dist/CallingClient/calling/call.test.js.map +1 -1
  27. package/dist/CallingClient/calling/callManager.js +73 -48
  28. package/dist/CallingClient/calling/callManager.js.map +1 -1
  29. package/dist/CallingClient/calling/callManager.test.js +96 -37
  30. package/dist/CallingClient/calling/callManager.test.js.map +1 -1
  31. package/dist/CallingClient/constants.js +104 -3
  32. package/dist/CallingClient/constants.js.map +1 -1
  33. package/dist/CallingClient/line/index.js +47 -18
  34. package/dist/CallingClient/line/index.js.map +1 -1
  35. package/dist/CallingClient/line/line.test.js +2 -2
  36. package/dist/CallingClient/line/line.test.js.map +1 -1
  37. package/dist/CallingClient/registration/register.js +261 -219
  38. package/dist/CallingClient/registration/register.js.map +1 -1
  39. package/dist/CallingClient/registration/register.test.js +533 -155
  40. package/dist/CallingClient/registration/register.test.js.map +1 -1
  41. package/dist/CallingClient/registration/types.js.map +1 -1
  42. package/dist/Contacts/ContactsClient.js +156 -102
  43. package/dist/Contacts/ContactsClient.js.map +1 -1
  44. package/dist/Contacts/ContactsClient.test.js +197 -49
  45. package/dist/Contacts/ContactsClient.test.js.map +1 -1
  46. package/dist/Contacts/constants.js +11 -1
  47. package/dist/Contacts/constants.js.map +1 -1
  48. package/dist/Events/impl/index.js +1 -1
  49. package/dist/Events/impl/index.js.map +1 -1
  50. package/dist/Metrics/index.js +93 -39
  51. package/dist/Metrics/index.js.map +1 -1
  52. package/dist/Metrics/types.js +4 -1
  53. package/dist/Metrics/types.js.map +1 -1
  54. package/dist/SDKConnector/types.js.map +1 -1
  55. package/dist/Voicemail/BroadworksBackendConnector.js +154 -91
  56. package/dist/Voicemail/BroadworksBackendConnector.js.map +1 -1
  57. package/dist/Voicemail/BroadworksBackendConnector.test.js +99 -19
  58. package/dist/Voicemail/BroadworksBackendConnector.test.js.map +1 -1
  59. package/dist/Voicemail/UcmBackendConnector.js +105 -54
  60. package/dist/Voicemail/UcmBackendConnector.js.map +1 -1
  61. package/dist/Voicemail/UcmBackendConnector.test.js +127 -17
  62. package/dist/Voicemail/UcmBackendConnector.test.js.map +1 -1
  63. package/dist/Voicemail/Voicemail.js +198 -79
  64. package/dist/Voicemail/Voicemail.js.map +1 -1
  65. package/dist/Voicemail/Voicemail.test.js +188 -23
  66. package/dist/Voicemail/Voicemail.test.js.map +1 -1
  67. package/dist/Voicemail/WxCallBackendConnector.js +123 -76
  68. package/dist/Voicemail/WxCallBackendConnector.js.map +1 -1
  69. package/dist/Voicemail/WxCallBackendConnector.test.js +69 -6
  70. package/dist/Voicemail/WxCallBackendConnector.test.js.map +1 -1
  71. package/dist/Voicemail/constants.js +25 -1
  72. package/dist/Voicemail/constants.js.map +1 -1
  73. package/dist/common/Utils.js +167 -104
  74. package/dist/common/Utils.js.map +1 -1
  75. package/dist/common/Utils.test.js +199 -35
  76. package/dist/common/Utils.test.js.map +1 -1
  77. package/dist/common/constants.js +2 -1
  78. package/dist/common/constants.js.map +1 -1
  79. package/dist/common/types.js.map +1 -1
  80. package/dist/module/CallHistory/CallHistory.js +32 -13
  81. package/dist/module/CallHistory/constants.js +6 -0
  82. package/dist/module/CallSettings/CallSettings.js +36 -3
  83. package/dist/module/CallSettings/UcmBackendConnector.js +50 -5
  84. package/dist/module/CallSettings/WxCallBackendConnector.js +54 -18
  85. package/dist/module/CallSettings/constants.js +12 -0
  86. package/dist/module/CallingClient/CallingClient.js +52 -14
  87. package/dist/module/CallingClient/calling/call.js +172 -121
  88. package/dist/module/CallingClient/calling/callManager.js +51 -26
  89. package/dist/module/CallingClient/constants.js +101 -2
  90. package/dist/module/CallingClient/line/index.js +37 -8
  91. package/dist/module/CallingClient/registration/register.js +90 -54
  92. package/dist/module/Contacts/ContactsClient.js +65 -21
  93. package/dist/module/Contacts/constants.js +10 -0
  94. package/dist/module/Events/impl/index.js +1 -1
  95. package/dist/module/Metrics/index.js +49 -1
  96. package/dist/module/Metrics/types.js +3 -0
  97. package/dist/module/Voicemail/BroadworksBackendConnector.js +66 -17
  98. package/dist/module/Voicemail/UcmBackendConnector.js +51 -11
  99. package/dist/module/Voicemail/Voicemail.js +109 -9
  100. package/dist/module/Voicemail/WxCallBackendConnector.js +50 -17
  101. package/dist/module/Voicemail/constants.js +21 -0
  102. package/dist/module/common/Utils.js +50 -12
  103. package/dist/module/common/constants.js +1 -0
  104. package/dist/types/CallHistory/CallHistory.d.ts.map +1 -1
  105. package/dist/types/CallHistory/constants.d.ts +6 -0
  106. package/dist/types/CallHistory/constants.d.ts.map +1 -1
  107. package/dist/types/CallSettings/CallSettings.d.ts.map +1 -1
  108. package/dist/types/CallSettings/UcmBackendConnector.d.ts.map +1 -1
  109. package/dist/types/CallSettings/WxCallBackendConnector.d.ts.map +1 -1
  110. package/dist/types/CallSettings/constants.d.ts +12 -0
  111. package/dist/types/CallSettings/constants.d.ts.map +1 -1
  112. package/dist/types/CallingClient/CallingClient.d.ts +2 -3
  113. package/dist/types/CallingClient/CallingClient.d.ts.map +1 -1
  114. package/dist/types/CallingClient/calling/call.d.ts.map +1 -1
  115. package/dist/types/CallingClient/calling/callManager.d.ts.map +1 -1
  116. package/dist/types/CallingClient/constants.d.ts +101 -2
  117. package/dist/types/CallingClient/constants.d.ts.map +1 -1
  118. package/dist/types/CallingClient/line/index.d.ts.map +1 -1
  119. package/dist/types/CallingClient/registration/register.d.ts +3 -1
  120. package/dist/types/CallingClient/registration/register.d.ts.map +1 -1
  121. package/dist/types/CallingClient/registration/types.d.ts +1 -0
  122. package/dist/types/CallingClient/registration/types.d.ts.map +1 -1
  123. package/dist/types/Contacts/ContactsClient.d.ts.map +1 -1
  124. package/dist/types/Contacts/constants.d.ts +10 -0
  125. package/dist/types/Contacts/constants.d.ts.map +1 -1
  126. package/dist/types/Metrics/index.d.ts +1 -1
  127. package/dist/types/Metrics/index.d.ts.map +1 -1
  128. package/dist/types/Metrics/types.d.ts +5 -1
  129. package/dist/types/Metrics/types.d.ts.map +1 -1
  130. package/dist/types/SDKConnector/types.d.ts +8 -2
  131. package/dist/types/SDKConnector/types.d.ts.map +1 -1
  132. package/dist/types/Voicemail/BroadworksBackendConnector.d.ts.map +1 -1
  133. package/dist/types/Voicemail/UcmBackendConnector.d.ts.map +1 -1
  134. package/dist/types/Voicemail/Voicemail.d.ts +1 -1
  135. package/dist/types/Voicemail/Voicemail.d.ts.map +1 -1
  136. package/dist/types/Voicemail/WxCallBackendConnector.d.ts.map +1 -1
  137. package/dist/types/Voicemail/constants.d.ts +21 -0
  138. package/dist/types/Voicemail/constants.d.ts.map +1 -1
  139. package/dist/types/common/Utils.d.ts +4 -4
  140. package/dist/types/common/Utils.d.ts.map +1 -1
  141. package/dist/types/common/constants.d.ts +1 -0
  142. package/dist/types/common/constants.d.ts.map +1 -1
  143. package/dist/types/common/types.d.ts +12 -0
  144. package/dist/types/common/types.d.ts.map +1 -1
  145. package/package.json +1 -1
@@ -1,13 +1,13 @@
1
1
  import { v4 as uuid } from 'uuid';
2
- import { ERROR_CODE } from '../../Errors/types';
3
- import { emitFinalFailure, handleRegistrationErrors } from '../../common';
2
+ import { METHOD_START_MESSAGE } from '../../common/constants';
3
+ import { emitFinalFailure, handleRegistrationErrors, uploadLogs } from '../../common';
4
4
  import { METRIC_EVENT, METRIC_TYPE, REG_ACTION } from '../../Metrics/types';
5
5
  import { getMetricManager } from '../../Metrics';
6
6
  import { getCallManager } from '../calling';
7
7
  import log from '../../Logger';
8
8
  import SDKConnector from '../../SDKConnector';
9
9
  import { ALLOWED_SERVICES, HTTP_METHODS, RegistrationStatus, ServiceIndicator, } from '../../common/types';
10
- import { CALLING_USER_AGENT, CISCO_DEVICE_URL, DEVICES_ENDPOINT_RESOURCE, SPARK_USER_AGENT, WEBEX_WEB_CLIENT, BASE_REG_RETRY_TIMER_VAL_IN_SEC, BASE_REG_TIMER_MFACTOR, SEC_TO_MSEC_MFACTOR, REG_RANDOM_T_FACTOR_UPPER_LIMIT, REG_TRY_BACKUP_TIMER_VAL_IN_SEC, MINUTES_TO_SEC_MFACTOR, FAILBACK_429_RETRY_UTIL, REG_FAILBACK_429_MAX_RETRIES, FAILBACK_UTIL, REGISTRATION_FILE, DEFAULT_REHOMING_INTERVAL_MIN, DEFAULT_REHOMING_INTERVAL_MAX, DEFAULT_KEEPALIVE_INTERVAL, REG_TRY_BACKUP_TIMER_VAL_FOR_CC_IN_SEC, } from '../constants';
10
+ import { CALLING_USER_AGENT, CISCO_DEVICE_URL, DEVICES_ENDPOINT_RESOURCE, SPARK_USER_AGENT, WEBEX_WEB_CLIENT, BASE_REG_RETRY_TIMER_VAL_IN_SEC, BASE_REG_TIMER_MFACTOR, SEC_TO_MSEC_MFACTOR, REG_RANDOM_T_FACTOR_UPPER_LIMIT, REG_TRY_BACKUP_TIMER_VAL_IN_SEC, MINUTES_TO_SEC_MFACTOR, REG_429_RETRY_UTIL, REG_FAILBACK_429_MAX_RETRIES, FAILBACK_UTIL, REGISTRATION_FILE, DEFAULT_REHOMING_INTERVAL_MIN, DEFAULT_REHOMING_INTERVAL_MAX, DEFAULT_KEEPALIVE_INTERVAL, REG_TRY_BACKUP_TIMER_VAL_FOR_CC_IN_SEC, FAILOVER_UTIL, REGISTER_UTIL, RETRY_TIMER_UPPER_LIMIT, METHODS, } from '../constants';
11
11
  import { LINE_EVENTS } from '../line/types';
12
12
  export class Registration {
13
13
  sdkConnector;
@@ -33,6 +33,8 @@ export class Registration {
33
33
  jwe;
34
34
  isCCFlow = false;
35
35
  failoverImmediately = false;
36
+ retryAfter;
37
+ scheduled429Retry = false;
36
38
  constructor(webex, serviceData, mutex, lineEmitter, logLevel, jwe) {
37
39
  this.jwe = jwe;
38
40
  this.sdkConnector = SDKConnector;
@@ -59,11 +61,15 @@ export class Registration {
59
61
  return this.activeMobiusUrl;
60
62
  }
61
63
  setActiveMobiusUrl(url) {
62
- log.info(`ActiveMobiusUrl: ${url}`, { method: 'setActiveMobiusUrl', file: REGISTRATION_FILE });
64
+ log.info(`${METHOD_START_MESSAGE} with ${url}`, {
65
+ method: METHODS.UPDATE_ACTIVE_MOBIUS,
66
+ file: REGISTRATION_FILE,
67
+ });
63
68
  this.activeMobiusUrl = url;
64
69
  this.callManager.updateActiveMobius(url);
65
70
  }
66
71
  setMobiusServers(primaryMobiusUris, backupMobiusUris) {
72
+ log.log(METHOD_START_MESSAGE, { method: METHODS.SET_MOBIUS_SERVERS, file: REGISTRATION_FILE });
67
73
  this.primaryMobiusUris = primaryMobiusUris;
68
74
  this.backupMobiusUris = backupMobiusUris;
69
75
  }
@@ -92,7 +98,10 @@ export class Registration {
92
98
  });
93
99
  }
94
100
  catch (error) {
95
- log.warn(`Delete failed with Mobius`, {});
101
+ log.warn(`Delete failed with Mobius ${error}`, {
102
+ file: REGISTRATION_FILE,
103
+ method: METHODS.DEREGISTER,
104
+ });
96
105
  }
97
106
  this.setStatus(RegistrationStatus.INACTIVE);
98
107
  this.lineEmitter(LINE_EVENTS.UNREGISTERED);
@@ -122,21 +131,27 @@ export class Registration {
122
131
  }
123
132
  return abort;
124
133
  }
125
- async scheduleFailback429Retry() {
126
- if (this.failback429RetryAttempts >= REG_FAILBACK_429_MAX_RETRIES) {
127
- return;
134
+ async handle429Retry(retryAfter, caller) {
135
+ if (caller === FAILBACK_UTIL) {
136
+ if (this.failback429RetryAttempts >= REG_FAILBACK_429_MAX_RETRIES) {
137
+ return;
138
+ }
139
+ this.clearFailbackTimer();
140
+ this.failback429RetryAttempts += 1;
141
+ log.log(`Received 429 while rehoming, 429 retry count : ${this.failback429RetryAttempts}`, {
142
+ file: REGISTRATION_FILE,
143
+ method: REG_429_RETRY_UTIL,
144
+ });
145
+ const interval = this.getRegRetryInterval(this.failback429RetryAttempts);
146
+ this.startFailbackTimer(interval);
147
+ this.scheduled429Retry = true;
148
+ const abort = await this.restorePreviousRegistration(REG_429_RETRY_UTIL);
149
+ if (!abort && !this.isDeviceRegistered()) {
150
+ await this.restartRegistration(REG_429_RETRY_UTIL);
151
+ }
128
152
  }
129
- this.clearFailbackTimer();
130
- this.failback429RetryAttempts += 1;
131
- log.log(`Received 429 while rehoming, 429 retry count : ${this.failback429RetryAttempts}`, {
132
- file: REGISTRATION_FILE,
133
- method: FAILBACK_429_RETRY_UTIL,
134
- });
135
- const interval = this.getRegRetryInterval(this.failback429RetryAttempts);
136
- this.startFailbackTimer(interval);
137
- const abort = await this.restorePreviousRegistration(FAILBACK_429_RETRY_UTIL);
138
- if (!abort && !this.isDeviceRegistered()) {
139
- await this.restartRegistration(FAILBACK_429_RETRY_UTIL);
153
+ else {
154
+ this.retryAfter = retryAfter;
140
155
  }
141
156
  }
142
157
  getRegRetryInterval(attempt = 1) {
@@ -149,7 +164,7 @@ export class Registration {
149
164
  async startFailoverTimer(attempt = 1, timeElapsed = 0) {
150
165
  const loggerContext = {
151
166
  file: REGISTRATION_FILE,
152
- method: this.startFailoverTimer.name,
167
+ method: FAILOVER_UTIL,
153
168
  };
154
169
  let interval = this.getRegRetryInterval(attempt);
155
170
  const TIMER_THRESHOLD = this.isCCFlow
@@ -159,12 +174,18 @@ export class Registration {
159
174
  const excessVal = timeElapsed + interval - TIMER_THRESHOLD;
160
175
  interval -= excessVal;
161
176
  }
177
+ if (this.retryAfter != null && interval < this.retryAfter) {
178
+ this.failoverImmediately = this.retryAfter + timeElapsed > TIMER_THRESHOLD;
179
+ }
162
180
  let abort;
163
181
  if (interval > BASE_REG_RETRY_TIMER_VAL_IN_SEC && !this.failoverImmediately) {
164
182
  const scheduledTime = Math.floor(Date.now() / 1000);
183
+ if (this.retryAfter != null) {
184
+ interval = Math.max(interval, this.retryAfter);
185
+ }
165
186
  setTimeout(async () => {
166
187
  await this.mutex.runExclusive(async () => {
167
- abort = await this.attemptRegistrationWithServers(this.startFailoverTimer.name);
188
+ abort = await this.attemptRegistrationWithServers(FAILOVER_UTIL);
168
189
  const currentTime = Math.floor(Date.now() / 1000);
169
190
  if (!abort && !this.isDeviceRegistered()) {
170
191
  await this.startFailoverTimer(attempt + 1, timeElapsed + (currentTime - scheduledTime));
@@ -174,15 +195,19 @@ export class Registration {
174
195
  log.log(`Scheduled retry with primary in ${interval} seconds, number of attempts : ${attempt}`, loggerContext);
175
196
  }
176
197
  else if (this.backupMobiusUris.length) {
177
- log.log('Failing over to backup servers.', loggerContext);
198
+ log.info('Failing over to backup servers.', loggerContext);
178
199
  this.failoverImmediately = false;
179
- abort = await this.attemptRegistrationWithServers(this.startFailoverTimer.name, this.backupMobiusUris);
200
+ abort = await this.attemptRegistrationWithServers(FAILOVER_UTIL, this.backupMobiusUris);
180
201
  if (!abort && !this.isDeviceRegistered()) {
181
202
  interval = this.getRegRetryInterval();
203
+ if (this.retryAfter != null && this.retryAfter < RETRY_TIMER_UPPER_LIMIT) {
204
+ interval = interval < this.retryAfter ? this.retryAfter : interval;
205
+ }
182
206
  setTimeout(async () => {
183
207
  await this.mutex.runExclusive(async () => {
184
- abort = await this.attemptRegistrationWithServers(this.startFailoverTimer.name, this.backupMobiusUris);
208
+ abort = await this.attemptRegistrationWithServers(FAILOVER_UTIL, this.backupMobiusUris);
185
209
  if (!abort && !this.isDeviceRegistered()) {
210
+ await uploadLogs();
186
211
  emitFinalFailure((clientError) => {
187
212
  this.lineEmitter(LINE_EVENTS.ERROR, undefined, clientError);
188
213
  }, loggerContext);
@@ -193,6 +218,7 @@ export class Registration {
193
218
  }
194
219
  }
195
220
  else {
221
+ await uploadLogs();
196
222
  emitFinalFailure((clientError) => {
197
223
  this.lineEmitter(LINE_EVENTS.ERROR, undefined, clientError);
198
224
  }, loggerContext);
@@ -241,19 +267,20 @@ export class Registration {
241
267
  });
242
268
  await this.deregister();
243
269
  const abort = await this.attemptRegistrationWithServers(FAILBACK_UTIL);
244
- if (!abort && !this.isDeviceRegistered()) {
245
- const abortNew = await this.restorePreviousRegistration(FAILBACK_UTIL);
246
- if (abortNew) {
247
- this.clearFailbackTimer();
248
- return;
249
- }
250
- if (!this.isDeviceRegistered()) {
251
- await this.restartRegistration(this.executeFailback.name);
252
- }
253
- else {
254
- this.failbackTimer = undefined;
255
- this.initiateFailback();
256
- }
270
+ if (this.scheduled429Retry || abort || this.isDeviceRegistered()) {
271
+ return;
272
+ }
273
+ const abortNew = await this.restorePreviousRegistration(FAILBACK_UTIL);
274
+ if (abortNew) {
275
+ this.clearFailbackTimer();
276
+ return;
277
+ }
278
+ if (!this.isDeviceRegistered()) {
279
+ await this.restartRegistration(this.executeFailback.name);
280
+ }
281
+ else {
282
+ this.failbackTimer = undefined;
283
+ this.initiateFailback();
257
284
  }
258
285
  }
259
286
  else {
@@ -298,9 +325,13 @@ export class Registration {
298
325
  }
299
326
  }
300
327
  async handleConnectionRestoration(retry) {
328
+ log.info(METHOD_START_MESSAGE, {
329
+ method: METHODS.HANDLE_CONNECTION_RESTORATION,
330
+ file: REGISTRATION_FILE,
331
+ });
301
332
  await this.mutex.runExclusive(async () => {
302
333
  if (retry) {
303
- log.info('Mercury connection is up again, re-registering with Webex Calling if needed', {
334
+ log.log('Mercury connection is up again, re-registering with Webex Calling if needed', {
304
335
  file: REGISTRATION_FILE,
305
336
  method: this.handleConnectionRestoration.name,
306
337
  });
@@ -353,13 +384,14 @@ export class Registration {
353
384
  }
354
385
  async attemptRegistrationWithServers(caller, servers = this.primaryMobiusUris) {
355
386
  let abort = false;
387
+ this.retryAfter = undefined;
356
388
  if (this.failoverImmediately) {
357
389
  return abort;
358
390
  }
359
391
  if (this.isDeviceRegistered()) {
360
- log.log(`[${caller}] : Device already registered with : ${this.activeMobiusUrl}`, {
392
+ log.info(`[${caller}] : Device already registered with : ${this.activeMobiusUrl}`, {
361
393
  file: REGISTRATION_FILE,
362
- method: this.attemptRegistrationWithServers.name,
394
+ method: REGISTER_UTIL,
363
395
  });
364
396
  return abort;
365
397
  }
@@ -368,14 +400,18 @@ export class Registration {
368
400
  abort = false;
369
401
  this.registrationStatus = RegistrationStatus.INACTIVE;
370
402
  this.lineEmitter(LINE_EVENTS.CONNECTING);
371
- log.log(`[${caller}] : Mobius url to contact: ${url}`, {
403
+ log.info(`[${caller}] : Mobius url to contact: ${url}`, {
372
404
  file: REGISTRATION_FILE,
373
- method: this.attemptRegistrationWithServers.name,
405
+ method: REGISTER_UTIL,
374
406
  });
375
407
  const resp = await this.postRegistration(url);
376
408
  this.deviceInfo = resp.body;
377
409
  this.registrationStatus = RegistrationStatus.ACTIVE;
378
410
  this.lineEmitter(LINE_EVENTS.REGISTERED, resp.body);
411
+ log.log(`Registration successful for deviceId: ${this.deviceInfo.device?.deviceId} userId: ${this.userId}`, {
412
+ file: REGISTRATION_FILE,
413
+ method: METHODS.REGISTER,
414
+ });
379
415
  this.setActiveMobiusUrl(url);
380
416
  this.setIntervalValues(this.deviceInfo);
381
417
  this.metricManager.setDeviceInfo(this.deviceInfo);
@@ -394,7 +430,7 @@ export class Registration {
394
430
  this.lineEmitter(LINE_EVENTS.UNREGISTERED);
395
431
  }
396
432
  this.metricManager.submitRegistrationMetric(METRIC_EVENT.REGISTRATION_ERROR, REG_ACTION.REGISTER, METRIC_TYPE.BEHAVIORAL, clientError);
397
- }, { method: this.attemptRegistrationWithServers.name, file: REGISTRATION_FILE }, this.restoreRegistrationCallBack());
433
+ }, { method: caller, file: REGISTRATION_FILE }, (retryAfter, retryCaller) => this.handle429Retry(retryAfter, retryCaller), this.restoreRegistrationCallBack());
398
434
  if (this.registrationStatus === RegistrationStatus.ACTIVE) {
399
435
  log.info(`[${caller}] : Device is already restored, active mobius url: ${this.activeMobiusUrl}`, {
400
436
  file: REGISTRATION_FILE,
@@ -406,14 +442,6 @@ export class Registration {
406
442
  this.setStatus(RegistrationStatus.INACTIVE);
407
443
  break;
408
444
  }
409
- else if (caller === this.executeFailback.name) {
410
- const error = body.statusCode;
411
- if (error === ERROR_CODE.TOO_MANY_REQUESTS) {
412
- await this.scheduleFailback429Retry();
413
- abort = true;
414
- break;
415
- }
416
- }
417
445
  }
418
446
  }
419
447
  return abort;
@@ -431,7 +459,7 @@ export class Registration {
431
459
  if (this.isDeviceRegistered() && keepAliveRetryCount < RETRY_COUNT_THRESHOLD) {
432
460
  try {
433
461
  const res = await this.postKeepAlive(url);
434
- log.info(`Sent Keepalive, status: ${res.statusCode}`, logContext);
462
+ log.log(`Sent Keepalive, status: ${res.statusCode}`, logContext);
435
463
  if (keepAliveRetryCount > 0) {
436
464
  this.lineEmitter(LINE_EVENTS.RECONNECTED);
437
465
  }
@@ -477,9 +505,16 @@ export class Registration {
477
505
  async deregister() {
478
506
  try {
479
507
  await this.deleteRegistration(this.activeMobiusUrl, this.deviceInfo.device?.deviceId, this.deviceInfo.device?.clientDeviceUri);
508
+ log.log('Registration successfully deregistered', {
509
+ file: REGISTRATION_FILE,
510
+ method: METHODS.DEREGISTER,
511
+ });
480
512
  }
481
513
  catch (err) {
482
- log.warn(`Delete failed with Mobius`, {});
514
+ log.warn(`Delete failed with Mobius: ${err}`, {
515
+ file: REGISTRATION_FILE,
516
+ method: METHODS.DEREGISTER,
517
+ });
483
518
  }
484
519
  this.clearKeepaliveTimer();
485
520
  this.setStatus(RegistrationStatus.INACTIVE);
@@ -508,6 +543,7 @@ export class Registration {
508
543
  return false;
509
544
  }
510
545
  async reconnectOnFailure(caller) {
546
+ log.info(METHOD_START_MESSAGE, { method: METHODS.RECONNECT_ON_FAILURE, file: REGISTRATION_FILE });
511
547
  this.reconnectPending = false;
512
548
  if (!this.isDeviceRegistered()) {
513
549
  if (Object.keys(this.callManager.getActiveCalls()).length === 0) {
@@ -520,7 +556,7 @@ export class Registration {
520
556
  this.reconnectPending = true;
521
557
  log.info('Active call(s) present, deferred reconnect till call cleanup.', {
522
558
  file: REGISTRATION_FILE,
523
- method: this.reconnectOnFailure.name,
559
+ method: METHODS.RECONNECT_ON_FAILURE,
524
560
  });
525
561
  }
526
562
  }
@@ -1,10 +1,10 @@
1
- import { FAILURE_MESSAGE, SCIM_ENTERPRISE_USER, SCIM_WEBEXIDENTITY_USER, STATUS_CODE, SUCCESS_MESSAGE, } from '../common/constants';
1
+ import { FAILURE_MESSAGE, METHOD_START_MESSAGE, SCIM_ENTERPRISE_USER, SCIM_WEBEXIDENTITY_USER, STATUS_CODE, SUCCESS_MESSAGE, } from '../common/constants';
2
2
  import { HTTP_METHODS } from '../common/types';
3
3
  import SDKConnector from '../SDKConnector';
4
4
  import log from '../Logger';
5
- import { CONTACTS_FILE, CONTACTS_SCHEMA, CONTACT_FILTER, DEFAULT_GROUP_NAME, ENCRYPT_FILTER, GROUP_FILTER, OR, SCIM_ID_FILTER, USERS, encryptedFields, } from './constants';
5
+ import { CONTACTS_FILE, CONTACTS_SCHEMA, CONTACT_FILTER, DEFAULT_GROUP_NAME, ENCRYPT_FILTER, GROUP_FILTER, METHODS, OR, SCIM_ID_FILTER, USERS, encryptedFields, } from './constants';
6
6
  import { ContactType, GroupType, } from './types';
7
- import { scimQuery, serviceErrorCodeHandler } from '../common/Utils';
7
+ import { scimQuery, serviceErrorCodeHandler, uploadLogs } from '../common/Utils';
8
8
  export class ContactsClient {
9
9
  sdkConnector;
10
10
  encryptionKeyUrl;
@@ -188,8 +188,9 @@ export class ContactsClient {
188
188
  async getContacts() {
189
189
  const loggerContext = {
190
190
  file: CONTACTS_FILE,
191
- method: 'getContacts',
191
+ method: METHODS.GET_CONTACTS,
192
192
  };
193
+ log.info(METHOD_START_MESSAGE, loggerContext);
193
194
  const contactList = [];
194
195
  const cloudContactsMap = {};
195
196
  try {
@@ -244,19 +245,24 @@ export class ContactsClient {
244
245
  },
245
246
  message: SUCCESS_MESSAGE,
246
247
  };
248
+ log.log('Successfully fetched contacts and groups', loggerContext);
247
249
  return contactResponse;
248
250
  }
249
251
  catch (err) {
250
252
  const errorInfo = err;
253
+ const extendedError = new Error(`Error fetching contacts: ${err}`);
254
+ log.error(extendedError, loggerContext);
251
255
  const errorStatus = serviceErrorCodeHandler(errorInfo, loggerContext);
256
+ await uploadLogs();
252
257
  return errorStatus;
253
258
  }
254
259
  }
255
260
  async createNewEncryptionKeyUrl() {
256
261
  const loggerContext = {
257
262
  file: CONTACTS_FILE,
258
- method: this.createNewEncryptionKeyUrl.name,
263
+ method: METHODS.CREATE_NEW_ENCRYPTION_KEY_URL,
259
264
  };
265
+ log.info(METHOD_START_MESSAGE, loggerContext);
260
266
  let unboundedKeyUri = '';
261
267
  log.info('Requesting kms for a new KRO and key', loggerContext);
262
268
  const unboundedKeys = await this.webex.internal.encryption.kms.createUnboundKeys({ count: 1 });
@@ -265,6 +271,11 @@ export class ContactsClient {
265
271
  return unboundedKeyUri;
266
272
  }
267
273
  async fetchEncryptionKeyUrl() {
274
+ const loggerContext = {
275
+ file: CONTACTS_FILE,
276
+ method: METHODS.FETCH_ENCRYPTION_KEY_URL,
277
+ };
278
+ log.info(METHOD_START_MESSAGE, loggerContext);
268
279
  if (this.encryptionKeyUrl) {
269
280
  return this.encryptionKeyUrl;
270
281
  }
@@ -275,45 +286,67 @@ export class ContactsClient {
275
286
  return this.groups[0].encryptionKeyUrl;
276
287
  }
277
288
  this.encryptionKeyUrl = await this.createNewEncryptionKeyUrl();
278
- log.info(`Creating a default group: ${DEFAULT_GROUP_NAME}`, {
289
+ log.log(`Creating a default group: ${DEFAULT_GROUP_NAME}`, {
279
290
  file: CONTACTS_FILE,
280
291
  method: this.fetchEncryptionKeyUrl.name,
281
292
  });
282
293
  const response = await this.createContactGroup(DEFAULT_GROUP_NAME, this.encryptionKeyUrl);
283
294
  if (response.data.group?.groupId) {
284
295
  this.defaultGroupId = response.data.group?.groupId;
296
+ log.log(`Successfully created default group with ID: ${this.defaultGroupId}`, {
297
+ file: CONTACTS_FILE,
298
+ method: this.fetchEncryptionKeyUrl.name,
299
+ });
285
300
  }
286
301
  return this.encryptionKeyUrl;
287
302
  }
288
303
  async fetchDefaultGroup() {
304
+ const loggerContext = {
305
+ file: CONTACTS_FILE,
306
+ method: METHODS.FETCH_DEFAULT_GROUP,
307
+ };
308
+ log.info(METHOD_START_MESSAGE, loggerContext);
289
309
  if (this.defaultGroupId) {
310
+ log.log(`Using existing default group with ID: ${this.defaultGroupId}`, {
311
+ file: CONTACTS_FILE,
312
+ method: this.fetchDefaultGroup.name,
313
+ });
290
314
  return this.defaultGroupId;
291
315
  }
292
316
  if (this.groups && this.groups.length) {
293
317
  for (let i = 0; i < this.groups.length; i += 1) {
294
318
  if (this.groups[i].displayName === DEFAULT_GROUP_NAME) {
295
319
  this.defaultGroupId = this.groups[i].groupId;
320
+ log.log(`Found default group with ID: ${this.defaultGroupId}`, {
321
+ file: CONTACTS_FILE,
322
+ method: this.fetchDefaultGroup.name,
323
+ });
296
324
  return this.defaultGroupId;
297
325
  }
298
326
  }
299
327
  }
300
- log.info('No default group found.', {
328
+ log.log('No default group found.', {
301
329
  file: CONTACTS_FILE,
302
330
  method: this.fetchDefaultGroup.name,
303
331
  });
304
332
  const response = await this.createContactGroup(DEFAULT_GROUP_NAME);
305
333
  const { group } = response.data;
306
334
  if (group) {
307
- return group.groupId;
335
+ const groupId = group.groupId;
336
+ log.log(`Successfully created new default group with ID: ${groupId}`, {
337
+ file: CONTACTS_FILE,
338
+ method: this.fetchDefaultGroup.name,
339
+ });
340
+ return groupId;
308
341
  }
309
342
  return '';
310
343
  }
311
344
  async createContactGroup(displayName, encryptionKeyUrl, groupType) {
312
345
  const loggerContext = {
313
346
  file: CONTACTS_FILE,
314
- method: this.createContactGroup.name,
347
+ method: METHODS.CREATE_CONTACT_GROUP,
315
348
  };
316
- log.info(`Creating contact group ${displayName}`, loggerContext);
349
+ log.info(`${METHOD_START_MESSAGE} with displayName: ${displayName}`, loggerContext);
317
350
  const encryptionKeyUrlFinal = encryptionKeyUrl || (await this.fetchEncryptionKeyUrl());
318
351
  if (this.groups === undefined) {
319
352
  await this.getContacts();
@@ -354,20 +387,24 @@ export class ContactsClient {
354
387
  message: SUCCESS_MESSAGE,
355
388
  };
356
389
  this.groups?.push(group);
390
+ log.log(`Contact group ${displayName} successfully created`, loggerContext);
357
391
  return contactResponse;
358
392
  }
359
393
  catch (err) {
360
- log.warn('Unable to create contact group.', loggerContext);
361
394
  const errorInfo = err;
395
+ const extendedError = new Error(`Unable to create contact group: ${err}`);
396
+ log.error(extendedError, loggerContext);
362
397
  const errorStatus = serviceErrorCodeHandler(errorInfo, loggerContext);
398
+ await uploadLogs();
363
399
  return errorStatus;
364
400
  }
365
401
  }
366
402
  async deleteContactGroup(groupId) {
367
403
  const loggerContext = {
368
404
  file: CONTACTS_FILE,
369
- method: this.deleteContactGroup.name,
405
+ method: METHODS.DELETE_CONTACT_GROUP,
370
406
  };
407
+ log.info(`${METHOD_START_MESSAGE} with groupId: ${groupId}`, loggerContext);
371
408
  try {
372
409
  log.info(`Deleting contact group: ${groupId}`, loggerContext);
373
410
  const response = await this.webex.request({
@@ -386,21 +423,24 @@ export class ContactsClient {
386
423
  if (!this.groups?.length) {
387
424
  this.defaultGroupId = '';
388
425
  }
426
+ log.log(`Contact group ${groupId} successfully deleted`, loggerContext);
389
427
  return contactResponse;
390
428
  }
391
429
  catch (err) {
392
- log.warn(`Unable to delete contact group ${groupId}`, loggerContext);
393
430
  const errorInfo = err;
431
+ const extendedError = new Error(`Unable to delete contact group ${groupId}: ${err}`);
432
+ log.error(extendedError, loggerContext);
394
433
  const errorStatus = serviceErrorCodeHandler(errorInfo, loggerContext);
434
+ await uploadLogs();
395
435
  return errorStatus;
396
436
  }
397
437
  }
398
438
  async createContact(contactInfo) {
399
439
  const loggerContext = {
400
440
  file: CONTACTS_FILE,
401
- method: this.createContact.name,
441
+ method: METHODS.CREATE_CONTACT,
402
442
  };
403
- log.info(`Request to create contact: contactType: ${contactInfo.contactType}`, loggerContext);
443
+ log.info(`${METHOD_START_MESSAGE} with contactType: ${contactInfo.contactType}`, loggerContext);
404
444
  try {
405
445
  const contact = { ...contactInfo };
406
446
  if (!contact.encryptionKeyUrl) {
@@ -467,23 +507,24 @@ export class ContactsClient {
467
507
  else {
468
508
  this.contacts?.push(contact);
469
509
  }
510
+ log.log(`Contact successfully created`, loggerContext);
470
511
  return contactResponse;
471
512
  }
472
513
  catch (err) {
473
- log.warn('Failed to create contact.', {
474
- file: CONTACTS_FILE,
475
- method: this.createContact.name,
476
- });
477
514
  const errorInfo = err;
515
+ const extendedError = new Error(`Failed to create contact: ${err}`);
516
+ log.error(extendedError, loggerContext);
478
517
  const errorStatus = serviceErrorCodeHandler(errorInfo, loggerContext);
518
+ await uploadLogs();
479
519
  return errorStatus;
480
520
  }
481
521
  }
482
522
  async deleteContact(contactId) {
483
523
  const loggerContext = {
484
524
  file: CONTACTS_FILE,
485
- method: this.deleteContact.name,
525
+ method: METHODS.DELETE_CONTACT,
486
526
  };
527
+ log.info(`${METHOD_START_MESSAGE} with contactId: ${contactId}`, loggerContext);
487
528
  try {
488
529
  log.info(`Deleting contact : ${contactId}`, loggerContext);
489
530
  const response = await this.webex.request({
@@ -499,12 +540,15 @@ export class ContactsClient {
499
540
  if (contactToDelete !== undefined && contactToDelete !== -1) {
500
541
  this.contacts?.splice(contactToDelete, 1);
501
542
  }
543
+ log.log(`Contact ${contactId} successfully deleted`, loggerContext);
502
544
  return contactResponse;
503
545
  }
504
546
  catch (err) {
505
- log.warn(`Unable to delete contact ${contactId}`, loggerContext);
506
547
  const errorInfo = err;
548
+ const extendedError = new Error(`Unable to delete contact ${contactId}: ${err}`);
549
+ log.error(extendedError, loggerContext);
507
550
  const errorStatus = serviceErrorCodeHandler(errorInfo, loggerContext);
551
+ await uploadLogs();
508
552
  return errorStatus;
509
553
  }
510
554
  }
@@ -20,3 +20,13 @@ export var encryptedFields;
20
20
  encryptedFields["SIP_ADDRESSES"] = "sipAddresses";
21
21
  encryptedFields["TITLE"] = "title";
22
22
  })(encryptedFields || (encryptedFields = {}));
23
+ export const METHODS = {
24
+ GET_CONTACTS: 'getContacts',
25
+ CREATE_NEW_ENCRYPTION_KEY_URL: 'createNewEncryptionKeyUrl',
26
+ FETCH_ENCRYPTION_KEY_URL: 'fetchEncryptionKeyUrl',
27
+ FETCH_DEFAULT_GROUP: 'fetchDefaultGroup',
28
+ CREATE_CONTACT_GROUP: 'createContactGroup',
29
+ DELETE_CONTACT_GROUP: 'deleteContactGroup',
30
+ CREATE_CONTACT: 'createContact',
31
+ DELETE_CONTACT: 'deleteContact',
32
+ };
@@ -4,7 +4,7 @@ import { LOG_PREFIX } from '../../Logger/types';
4
4
  export class Eventing extends EventEmitter {
5
5
  emit(event, ...args) {
6
6
  const timestamp = new Date().toUTCString();
7
- Logger.log(`${timestamp} ${LOG_PREFIX.EVENT}: ${event.toString()} - event emitted with parameters -> ${args} = `, {
7
+ Logger.info(`${timestamp} ${LOG_PREFIX.EVENT}: ${event.toString()} - event emitted with parameters -> ${args} = `, {
8
8
  file: 'Events/impl/index.ts',
9
9
  method: 'emit',
10
10
  });
@@ -11,6 +11,54 @@ class MetricManager {
11
11
  this.webex = webex;
12
12
  this.serviceIndicator = indicator;
13
13
  }
14
+ submitUploadLogsMetric(name, action, type, trackingId, feedbackId, correlationId, stack, callId) {
15
+ let data;
16
+ switch (name) {
17
+ case METRIC_EVENT.UPLOAD_LOGS_SUCCESS: {
18
+ data = {
19
+ tags: {
20
+ action,
21
+ device_id: this.deviceInfo?.device?.deviceId,
22
+ service_indicator: this.serviceIndicator,
23
+ },
24
+ fields: {
25
+ device_url: this.deviceInfo?.device?.clientDeviceUri,
26
+ mobius_url: this.deviceInfo?.device?.uri,
27
+ calling_sdk_version: process.env.CALLING_SDK_VERSION || VERSION,
28
+ correlation_id: correlationId,
29
+ tracking_id: trackingId,
30
+ feedback_id: feedbackId,
31
+ call_id: callId,
32
+ },
33
+ type,
34
+ };
35
+ break;
36
+ }
37
+ case METRIC_EVENT.UPLOAD_LOGS_FAILED: {
38
+ data = {
39
+ tags: {
40
+ action,
41
+ device_id: this.deviceInfo?.device?.deviceId,
42
+ service_indicator: this.serviceIndicator,
43
+ },
44
+ fields: {
45
+ device_url: this.deviceInfo?.device?.clientDeviceUri,
46
+ mobius_url: this.deviceInfo?.device?.uri,
47
+ calling_sdk_version: process.env.CALLING_SDK_VERSION || VERSION,
48
+ correlation_id: correlationId,
49
+ tracking_id: trackingId,
50
+ feedback_id: feedbackId,
51
+ error: stack,
52
+ call_id: callId,
53
+ },
54
+ type,
55
+ };
56
+ }
57
+ }
58
+ if (data) {
59
+ this.webex.internal.metrics.submitClientMetrics(name, data);
60
+ }
61
+ }
14
62
  setDeviceInfo(deviceInfo) {
15
63
  this.deviceInfo = deviceInfo;
16
64
  }
@@ -256,7 +304,7 @@ class MetricManager {
256
304
  }
257
305
  }
258
306
  export const getMetricManager = (webex, indicator) => {
259
- if (!metricManager) {
307
+ if (!metricManager && webex) {
260
308
  metricManager = new MetricManager(webex, indicator);
261
309
  }
262
310
  return metricManager;
@@ -15,6 +15,8 @@ export var METRIC_EVENT;
15
15
  METRIC_EVENT["REGISTRATION_ERROR"] = "web-calling-sdk-registration-error";
16
16
  METRIC_EVENT["VOICEMAIL"] = "web-calling-sdk-voicemail";
17
17
  METRIC_EVENT["VOICEMAIL_ERROR"] = "web-calling-sdk-voicemail-error";
18
+ METRIC_EVENT["UPLOAD_LOGS_SUCCESS"] = "web-calling-sdk-upload-logs-success";
19
+ METRIC_EVENT["UPLOAD_LOGS_FAILED"] = "web-calling-sdk-upload-logs-failed";
18
20
  })(METRIC_EVENT || (METRIC_EVENT = {}));
19
21
  export var REG_ACTION;
20
22
  (function (REG_ACTION) {
@@ -37,3 +39,4 @@ export var VOICEMAIL_ACTION;
37
39
  VOICEMAIL_ACTION["DELETE"] = "delete";
38
40
  VOICEMAIL_ACTION["TRANSCRIPT"] = "transcript";
39
41
  })(VOICEMAIL_ACTION || (VOICEMAIL_ACTION = {}));
42
+ export const UPLOAD_LOGS_ACTION = 'upload_logs';