@webex/calling 3.12.0-next.28 → 3.12.0-next.29

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 (189) hide show
  1. package/dist/CallingClient/CallingClient.js +408 -194
  2. package/dist/CallingClient/CallingClient.js.map +1 -1
  3. package/dist/CallingClient/CallingClient.test.js +119 -25
  4. package/dist/CallingClient/CallingClient.test.js.map +1 -1
  5. package/dist/CallingClient/calling/call.js +11 -8
  6. package/dist/CallingClient/calling/call.js.map +1 -1
  7. package/dist/CallingClient/calling/call.test.js +45 -4
  8. package/dist/CallingClient/calling/call.test.js.map +1 -1
  9. package/dist/CallingClient/calling/callManager.js +53 -30
  10. package/dist/CallingClient/calling/callManager.js.map +1 -1
  11. package/dist/CallingClient/calling/callManager.test.js +35 -0
  12. package/dist/CallingClient/calling/callManager.test.js.map +1 -1
  13. package/dist/CallingClient/calling/types.js +2 -0
  14. package/dist/CallingClient/calling/types.js.map +1 -1
  15. package/dist/CallingClient/constants.js +20 -2
  16. package/dist/CallingClient/constants.js.map +1 -1
  17. package/dist/CallingClient/line/line.test.js +16 -1
  18. package/dist/CallingClient/line/line.test.js.map +1 -1
  19. package/dist/CallingClient/registration/register.js +694 -406
  20. package/dist/CallingClient/registration/register.js.map +1 -1
  21. package/dist/CallingClient/registration/register.test.js +202 -21
  22. package/dist/CallingClient/registration/register.test.js.map +1 -1
  23. package/dist/CallingClient/registration/types.js.map +1 -1
  24. package/dist/CallingClient/registration/webWorker.js +41 -104
  25. package/dist/CallingClient/registration/webWorker.js.map +1 -1
  26. package/dist/CallingClient/registration/webWorker.test.js +39 -153
  27. package/dist/CallingClient/registration/webWorker.test.js.map +1 -1
  28. package/dist/CallingClient/registration/webWorkerStr.js +1 -1
  29. package/dist/CallingClient/registration/webWorkerStr.js.map +1 -1
  30. package/dist/CallingClient/utils/constants.js +46 -0
  31. package/dist/CallingClient/utils/constants.js.map +1 -0
  32. package/dist/CallingClient/utils/index.js +63 -0
  33. package/dist/CallingClient/utils/index.js.map +1 -0
  34. package/dist/CallingClient/utils/mobiusSocketMapper.js +122 -0
  35. package/dist/CallingClient/utils/mobiusSocketMapper.js.map +1 -0
  36. package/dist/CallingClient/utils/mobiusSocketMapper.test.js +211 -0
  37. package/dist/CallingClient/utils/mobiusSocketMapper.test.js.map +1 -0
  38. package/dist/CallingClient/utils/request.js +349 -0
  39. package/dist/CallingClient/utils/request.js.map +1 -0
  40. package/dist/CallingClient/utils/request.test.js +881 -0
  41. package/dist/CallingClient/utils/request.test.js.map +1 -0
  42. package/dist/CallingClient/utils/types.js +7 -0
  43. package/dist/CallingClient/utils/types.js.map +1 -0
  44. package/dist/CallingClient/utils/wsFeatureFlag.js +28 -0
  45. package/dist/CallingClient/utils/wsFeatureFlag.js.map +1 -0
  46. package/dist/CallingClient/utils/wsFeatureFlag.test.js +139 -0
  47. package/dist/CallingClient/utils/wsFeatureFlag.test.js.map +1 -0
  48. package/dist/Contacts/ContactsClient.test.js +3 -8
  49. package/dist/Contacts/ContactsClient.test.js.map +1 -1
  50. package/dist/Metrics/index.js +60 -0
  51. package/dist/Metrics/index.js.map +1 -1
  52. package/dist/Metrics/index.test.js +356 -0
  53. package/dist/Metrics/index.test.js.map +1 -1
  54. package/dist/Metrics/types.js +11 -1
  55. package/dist/Metrics/types.js.map +1 -1
  56. package/dist/SDKConnector/types.js.map +1 -1
  57. package/dist/common/Utils.js +136 -40
  58. package/dist/common/Utils.js.map +1 -1
  59. package/dist/common/testUtil.js +8 -4
  60. package/dist/common/testUtil.js.map +1 -1
  61. package/dist/common/types.js +2 -0
  62. package/dist/common/types.js.map +1 -1
  63. package/dist/mobius-socket/config.js +24 -0
  64. package/dist/mobius-socket/config.js.map +1 -0
  65. package/dist/mobius-socket/errors.js +150 -0
  66. package/dist/mobius-socket/errors.js.map +1 -0
  67. package/dist/mobius-socket/index.js +57 -0
  68. package/dist/mobius-socket/index.js.map +1 -0
  69. package/dist/mobius-socket/mobius-socket-events.test.js +485 -0
  70. package/dist/mobius-socket/mobius-socket-events.test.js.map +1 -0
  71. package/dist/mobius-socket/mobius-socket.js +804 -0
  72. package/dist/mobius-socket/mobius-socket.js.map +1 -0
  73. package/dist/mobius-socket/mobius-socket.test.js +1833 -0
  74. package/dist/mobius-socket/mobius-socket.test.js.map +1 -0
  75. package/dist/mobius-socket/socket/constants.js +34 -0
  76. package/dist/mobius-socket/socket/constants.js.map +1 -0
  77. package/dist/mobius-socket/socket/index.js +15 -0
  78. package/dist/mobius-socket/socket/index.js.map +1 -0
  79. package/dist/mobius-socket/socket/socket-base.js +604 -0
  80. package/dist/mobius-socket/socket/socket-base.js.map +1 -0
  81. package/dist/mobius-socket/socket/socket.js +19 -0
  82. package/dist/mobius-socket/socket/socket.js.map +1 -0
  83. package/dist/mobius-socket/socket/socket.shim.js +26 -0
  84. package/dist/mobius-socket/socket/socket.shim.js.map +1 -0
  85. package/dist/mobius-socket/socket/types.js +7 -0
  86. package/dist/mobius-socket/socket/types.js.map +1 -0
  87. package/dist/mobius-socket/socket.test.js +727 -0
  88. package/dist/mobius-socket/socket.test.js.map +1 -0
  89. package/dist/mobius-socket/test/mocha-helpers.js +23 -0
  90. package/dist/mobius-socket/test/mocha-helpers.js.map +1 -0
  91. package/dist/mobius-socket/test/promise-tick.js +28 -0
  92. package/dist/mobius-socket/test/promise-tick.js.map +1 -0
  93. package/dist/mobius-socket/types.js +7 -0
  94. package/dist/mobius-socket/types.js.map +1 -0
  95. package/dist/module/CallingClient/CallingClient.js +102 -5
  96. package/dist/module/CallingClient/calling/call.js +9 -6
  97. package/dist/module/CallingClient/calling/callManager.js +27 -7
  98. package/dist/module/CallingClient/calling/types.js +2 -0
  99. package/dist/module/CallingClient/constants.js +18 -0
  100. package/dist/module/CallingClient/registration/register.js +226 -62
  101. package/dist/module/CallingClient/registration/webWorker.js +42 -61
  102. package/dist/module/CallingClient/registration/webWorkerStr.js +47 -82
  103. package/dist/module/CallingClient/utils/constants.js +30 -0
  104. package/dist/module/CallingClient/utils/index.js +5 -0
  105. package/dist/module/CallingClient/utils/mobiusSocketMapper.js +72 -0
  106. package/dist/module/CallingClient/utils/request.js +162 -0
  107. package/dist/module/CallingClient/utils/types.js +1 -0
  108. package/dist/module/CallingClient/utils/wsFeatureFlag.js +12 -0
  109. package/dist/module/Metrics/index.js +46 -0
  110. package/dist/module/Metrics/types.js +10 -0
  111. package/dist/module/common/Utils.js +51 -8
  112. package/dist/module/common/testUtil.js +5 -1
  113. package/dist/module/common/types.js +2 -0
  114. package/dist/module/mobius-socket/config.js +15 -0
  115. package/dist/module/mobius-socket/errors.js +64 -0
  116. package/dist/module/mobius-socket/index.js +24 -0
  117. package/dist/module/mobius-socket/mobius-socket.js +571 -0
  118. package/dist/module/mobius-socket/socket/constants.js +10 -0
  119. package/dist/module/mobius-socket/socket/index.js +4 -0
  120. package/dist/module/mobius-socket/socket/socket-base.js +368 -0
  121. package/dist/module/mobius-socket/socket/socket.js +9 -0
  122. package/dist/module/mobius-socket/socket/socket.shim.js +12 -0
  123. package/dist/module/mobius-socket/socket/types.js +1 -0
  124. package/dist/module/mobius-socket/types.js +1 -0
  125. package/dist/types/CallingClient/CallingClient.d.ts +5 -0
  126. package/dist/types/CallingClient/CallingClient.d.ts.map +1 -1
  127. package/dist/types/CallingClient/calling/call.d.ts +1 -0
  128. package/dist/types/CallingClient/calling/call.d.ts.map +1 -1
  129. package/dist/types/CallingClient/calling/callManager.d.ts +3 -2
  130. package/dist/types/CallingClient/calling/callManager.d.ts.map +1 -1
  131. package/dist/types/CallingClient/calling/types.d.ts +21 -9
  132. package/dist/types/CallingClient/calling/types.d.ts.map +1 -1
  133. package/dist/types/CallingClient/constants.d.ts +18 -0
  134. package/dist/types/CallingClient/constants.d.ts.map +1 -1
  135. package/dist/types/CallingClient/registration/register.d.ts +6 -0
  136. package/dist/types/CallingClient/registration/register.d.ts.map +1 -1
  137. package/dist/types/CallingClient/registration/types.d.ts +3 -1
  138. package/dist/types/CallingClient/registration/types.d.ts.map +1 -1
  139. package/dist/types/CallingClient/registration/webWorker.d.ts.map +1 -1
  140. package/dist/types/CallingClient/registration/webWorkerStr.d.ts +1 -1
  141. package/dist/types/CallingClient/registration/webWorkerStr.d.ts.map +1 -1
  142. package/dist/types/CallingClient/utils/constants.d.ts +30 -0
  143. package/dist/types/CallingClient/utils/constants.d.ts.map +1 -0
  144. package/dist/types/CallingClient/utils/index.d.ts +6 -0
  145. package/dist/types/CallingClient/utils/index.d.ts.map +1 -0
  146. package/dist/types/CallingClient/utils/mobiusSocketMapper.d.ts +5 -0
  147. package/dist/types/CallingClient/utils/mobiusSocketMapper.d.ts.map +1 -0
  148. package/dist/types/CallingClient/utils/request.d.ts +23 -0
  149. package/dist/types/CallingClient/utils/request.d.ts.map +1 -0
  150. package/dist/types/CallingClient/utils/types.d.ts +29 -0
  151. package/dist/types/CallingClient/utils/types.d.ts.map +1 -0
  152. package/dist/types/CallingClient/utils/wsFeatureFlag.d.ts +4 -0
  153. package/dist/types/CallingClient/utils/wsFeatureFlag.d.ts.map +1 -0
  154. package/dist/types/Metrics/index.d.ts.map +1 -1
  155. package/dist/types/Metrics/types.d.ts +11 -1
  156. package/dist/types/Metrics/types.d.ts.map +1 -1
  157. package/dist/types/SDKConnector/types.d.ts +24 -0
  158. package/dist/types/SDKConnector/types.d.ts.map +1 -1
  159. package/dist/types/common/Utils.d.ts +8 -2
  160. package/dist/types/common/Utils.d.ts.map +1 -1
  161. package/dist/types/common/testUtil.d.ts +4 -1
  162. package/dist/types/common/testUtil.d.ts.map +1 -1
  163. package/dist/types/common/types.d.ts +3 -0
  164. package/dist/types/common/types.d.ts.map +1 -1
  165. package/dist/types/mobius-socket/config.d.ts +17 -0
  166. package/dist/types/mobius-socket/config.d.ts.map +1 -0
  167. package/dist/types/mobius-socket/errors.d.ts +32 -0
  168. package/dist/types/mobius-socket/errors.d.ts.map +1 -0
  169. package/dist/types/mobius-socket/index.d.ts +14 -0
  170. package/dist/types/mobius-socket/index.d.ts.map +1 -0
  171. package/dist/types/mobius-socket/mobius-socket.d.ts +48 -0
  172. package/dist/types/mobius-socket/mobius-socket.d.ts.map +1 -0
  173. package/dist/types/mobius-socket/socket/constants.d.ts +11 -0
  174. package/dist/types/mobius-socket/socket/constants.d.ts.map +1 -0
  175. package/dist/types/mobius-socket/socket/index.d.ts +5 -0
  176. package/dist/types/mobius-socket/socket/index.d.ts.map +1 -0
  177. package/dist/types/mobius-socket/socket/socket-base.d.ts +43 -0
  178. package/dist/types/mobius-socket/socket/socket-base.d.ts.map +1 -0
  179. package/dist/types/mobius-socket/socket/socket.d.ts +6 -0
  180. package/dist/types/mobius-socket/socket/socket.d.ts.map +1 -0
  181. package/dist/types/mobius-socket/socket/socket.shim.d.ts +6 -0
  182. package/dist/types/mobius-socket/socket/socket.shim.d.ts.map +1 -0
  183. package/dist/types/mobius-socket/socket/types.d.ts +61 -0
  184. package/dist/types/mobius-socket/socket/types.d.ts.map +1 -0
  185. package/dist/types/mobius-socket/types.d.ts +21 -0
  186. package/dist/types/mobius-socket/types.d.ts.map +1 -0
  187. package/package.json +16 -2
  188. package/src/mobius-socket/socket/socket.shim.ts +22 -0
  189. package/src/mobius-socket/socket/socket.ts +14 -0
@@ -1,4 +1,3 @@
1
- import { v4 as uuid } from 'uuid';
2
1
  import { METHOD_START_MESSAGE } from '../../common/constants';
3
2
  import { emitFinalFailure, handleRegistrationErrors, uploadLogs } from '../../common';
4
3
  import webWorkerStr from './webWorkerStr';
@@ -8,8 +7,9 @@ import { getCallManager } from '../calling';
8
7
  import log from '../../Logger';
9
8
  import SDKConnector from '../../SDKConnector';
10
9
  import { ALLOWED_SERVICES, HTTP_METHODS, RegistrationStatus, ServiceIndicator, WorkerMessageType, } from '../../common/types';
11
- 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, FAILOVER_UTIL, REGISTER_UTIL, RETRY_TIMER_UPPER_LIMIT, KEEPALIVE_UTIL, REGISTRATION_UTIL, METHODS, URL_ENDPOINT, RECONNECT_ON_FAILURE_UTIL, FAILOVER_CACHE_PREFIX, } from '../constants';
10
+ import { CALLING_USER_AGENT, CISCO_DEVICE_URL, DEVICES_ENDPOINT_RESOURCE, SPARK_USER_AGENT, 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, FAILOVER_UTIL, REGISTER_UTIL, RETRY_TIMER_UPPER_LIMIT, KEEPALIVE_UTIL, REGISTRATION_UTIL, METHODS, URL_ENDPOINT, RECONNECT_ON_FAILURE_UTIL, FAILOVER_CACHE_PREFIX, } from '../constants';
12
11
  import { LINE_EVENTS } from '../line/types';
12
+ import { APIRequest } from '../utils/request';
13
13
  export class Registration {
14
14
  sdkConnector;
15
15
  webex;
@@ -36,6 +36,7 @@ export class Registration {
36
36
  retryAfter;
37
37
  scheduled429Retry = false;
38
38
  webWorker;
39
+ apiRequest;
39
40
  constructor(webex, serviceData, mutex, lineEmitter, logLevel, jwe) {
40
41
  this.jwe = jwe;
41
42
  this.sdkConnector = SDKConnector;
@@ -57,6 +58,12 @@ export class Registration {
57
58
  this.lineEmitter = lineEmitter;
58
59
  this.primaryMobiusUris = [];
59
60
  this.backupMobiusUris = [];
61
+ this.apiRequest = APIRequest.getInstance({ webex: this.webex });
62
+ }
63
+ getServerType(url) {
64
+ return ((this.primaryMobiusUris.includes(url) && 'PRIMARY') ||
65
+ (this.backupMobiusUris?.includes(url) && 'BACKUP') ||
66
+ 'UNKNOWN');
60
67
  }
61
68
  getFailoverCacheKey() {
62
69
  return `${FAILOVER_CACHE_PREFIX}.${this.userId || 'unknown'}`;
@@ -131,16 +138,22 @@ export class Registration {
131
138
  }
132
139
  async deleteRegistration(url, deviceId, deviceUrl) {
133
140
  let response;
141
+ const requestObj = {
142
+ uri: `${url}${DEVICES_ENDPOINT_RESOURCE}/${deviceId}`,
143
+ method: HTTP_METHODS.DELETE,
144
+ headers: {
145
+ [CISCO_DEVICE_URL]: deviceUrl,
146
+ [SPARK_USER_AGENT]: CALLING_USER_AGENT,
147
+ },
148
+ service: ALLOWED_SERVICES.MOBIUS,
149
+ };
150
+ if (this.apiRequest.isSocketEnabled()) {
151
+ requestObj.body = {
152
+ deviceId,
153
+ };
154
+ }
134
155
  try {
135
- response = await fetch(`${url}${DEVICES_ENDPOINT_RESOURCE}/${deviceId}`, {
136
- method: HTTP_METHODS.DELETE,
137
- headers: {
138
- [CISCO_DEVICE_URL]: deviceUrl,
139
- Authorization: await this.webex.credentials.getUserToken(),
140
- trackingId: `${WEBEX_WEB_CLIENT}_${uuid()}`,
141
- [SPARK_USER_AGENT]: CALLING_USER_AGENT,
142
- },
143
- });
156
+ response = await this.apiRequest.makeRequest(requestObj);
144
157
  }
145
158
  catch (error) {
146
159
  log.warn(`Delete failed with Mobius: ${JSON.stringify(error)}`, {
@@ -151,7 +164,7 @@ export class Registration {
151
164
  }
152
165
  this.setStatus(RegistrationStatus.INACTIVE);
153
166
  this.lineEmitter(LINE_EVENTS.UNREGISTERED);
154
- return response?.json();
167
+ return response;
155
168
  }
156
169
  async postRegistration(url) {
157
170
  const deviceInfo = {
@@ -159,7 +172,7 @@ export class Registration {
159
172
  clientDeviceUri: this.webex.internal.device.url,
160
173
  serviceData: this.jwe ? { ...this.serviceData, jwe: this.jwe } : this.serviceData,
161
174
  };
162
- return this.webex.request({
175
+ return this.apiRequest.makeRequest({
163
176
  uri: `${url}device`,
164
177
  method: HTTP_METHODS.POST,
165
178
  headers: {
@@ -171,7 +184,22 @@ export class Registration {
171
184
  });
172
185
  }
173
186
  async restorePreviousRegistration(caller) {
187
+ const loggerContext = {
188
+ file: REGISTRATION_FILE,
189
+ method: METHODS.RESTORE_PREVIOUS_REGISTRATION,
190
+ };
191
+ log.info(`${METHOD_START_MESSAGE} - caller: ${caller}, activeMobiusUrl: ${this.activeMobiusUrl}`, loggerContext);
174
192
  let abort = false;
193
+ if (this.apiRequest.isSocketEnabled()) {
194
+ log.info(`Disconnecting from Mobius socket to restore previous registration.`, {
195
+ file: REGISTRATION_FILE,
196
+ method: 'restorePreviousRegistration',
197
+ });
198
+ await this.apiRequest.disconnectFromMobiusSocket({
199
+ code: 3050,
200
+ reason: 'done (permanent)',
201
+ });
202
+ }
175
203
  if (this.activeMobiusUrl) {
176
204
  abort = await this.attemptRegistrationWithServers(caller, [this.activeMobiusUrl]);
177
205
  if (this.retryAfter) {
@@ -185,20 +213,31 @@ export class Registration {
185
213
  abort = await this.attemptRegistrationWithServers(caller, this.backupMobiusUris);
186
214
  }
187
215
  else {
188
- this.restartRegistration(caller);
216
+ await this.restartRegistration(caller);
189
217
  }
190
218
  this.retryAfter = undefined;
219
+ log.log(`restorePreviousRegistration completed via 429 retry-after path - caller: ${caller}`, loggerContext);
191
220
  return true;
192
221
  }
193
222
  }
223
+ log.log(`restorePreviousRegistration completed - caller: ${caller}, deviceRegistered: ${this.isDeviceRegistered()}, abort: ${abort}`, loggerContext);
194
224
  return abort;
195
225
  }
196
226
  async handle404KeepaliveFailure(caller) {
227
+ const loggerContext = {
228
+ file: REGISTRATION_FILE,
229
+ method: METHODS.HANDLE_404_KEEPALIVE_FAILURE,
230
+ };
231
+ log.info(`${METHOD_START_MESSAGE} - caller: ${caller}`, loggerContext);
197
232
  if (caller === KEEPALIVE_UTIL) {
198
233
  const abort = await this.attemptRegistrationWithServers(caller);
199
234
  if (!abort && !this.isDeviceRegistered()) {
235
+ log.warn('Keepalive 404 recovery: re-registration did not complete, starting failover timer', loggerContext);
200
236
  await this.startFailoverTimer();
201
237
  }
238
+ else {
239
+ log.log(`Keepalive 404 recovery handled - deviceRegistered: ${this.isDeviceRegistered()}, abort: ${abort}`, loggerContext);
240
+ }
202
241
  }
203
242
  }
204
243
  async handle429Retry(retryAfter, caller) {
@@ -279,6 +318,14 @@ export class Registration {
279
318
  log.log(`Scheduled retry with primary in ${interval} seconds, number of attempts : ${attempt}`, loggerContext);
280
319
  }
281
320
  else if (this.backupMobiusUris.length) {
321
+ if (this.apiRequest.isSocketEnabled()) {
322
+ log.info('Disconnecting from primary Mobius socket for failover to backup servers', loggerContext);
323
+ await this.apiRequest.disconnectFromMobiusSocket({
324
+ code: 3050,
325
+ reason: 'done (permanent)',
326
+ });
327
+ log.log('Mobius socket disconnect complete prior to backup failover', loggerContext);
328
+ }
282
329
  this.saveFailoverState({
283
330
  attempt,
284
331
  timeElapsed,
@@ -311,7 +358,7 @@ export class Registration {
311
358
  await uploadLogs();
312
359
  emitFinalFailure((clientError) => {
313
360
  this.lineEmitter(LINE_EVENTS.ERROR, undefined, clientError);
314
- }, loggerContext);
361
+ }, loggerContext, interval < 0 ? 'Timer threshold exceeded during failover' : undefined);
315
362
  }
316
363
  }
317
364
  clearFailbackTimer() {
@@ -320,11 +367,25 @@ export class Registration {
320
367
  this.failbackTimer = undefined;
321
368
  }
322
369
  }
370
+ async postKeepAlive(deviceUrl, url) {
371
+ return this.apiRequest.makeRequest({
372
+ uri: `${url}/status`,
373
+ method: HTTP_METHODS.POST,
374
+ headers: {
375
+ [CISCO_DEVICE_URL]: deviceUrl,
376
+ [SPARK_USER_AGENT]: CALLING_USER_AGENT,
377
+ },
378
+ body: {
379
+ deviceId: this.deviceInfo.device?.deviceId,
380
+ },
381
+ service: ALLOWED_SERVICES.MOBIUS,
382
+ });
383
+ }
323
384
  async isPrimaryActive() {
324
385
  let status;
325
386
  for (const mobiusUrl of this.primaryMobiusUris) {
326
387
  try {
327
- const baseUri = mobiusUrl.replace(URL_ENDPOINT, '/');
388
+ const baseUri = mobiusUrl.replace(URL_ENDPOINT, '/').replace('wss://', 'https://');
328
389
  const response = await this.webex.request({
329
390
  uri: `${baseUri}ping`,
330
391
  method: HTTP_METHODS.GET,
@@ -362,14 +423,23 @@ export class Registration {
362
423
  this.rehomingIntervalMin);
363
424
  }
364
425
  initiateFailback() {
426
+ const loggerContext = {
427
+ file: REGISTRATION_FILE,
428
+ method: METHODS.INITIATE_FAILBACK,
429
+ };
365
430
  if (this.isFailbackRequired()) {
366
431
  if (!this.failbackTimer) {
367
432
  this.failback429RetryAttempts = 0;
368
433
  const intervalInMinutes = this.getFailbackInterval();
434
+ log.info(`Scheduling failback to primary - intervalMinutes: ${intervalInMinutes}`, loggerContext);
369
435
  this.startFailbackTimer(intervalInMinutes * MINUTES_TO_SEC_MFACTOR);
370
436
  }
437
+ else {
438
+ log.info('Failback timer already scheduled, skipping', loggerContext);
439
+ }
371
440
  }
372
441
  else {
442
+ log.info('Failback not required, clearing any pending failback timer', loggerContext);
373
443
  this.failback429RetryAttempts = 0;
374
444
  this.clearFailbackTimer();
375
445
  }
@@ -382,15 +452,25 @@ export class Registration {
382
452
  });
383
453
  }
384
454
  async executeFailback() {
455
+ const loggerContext = {
456
+ file: REGISTRATION_FILE,
457
+ method: METHODS.EXECUTE_FAILBACK,
458
+ };
459
+ log.info(METHOD_START_MESSAGE, loggerContext);
385
460
  await this.mutex.runExclusive(async () => {
386
461
  if (this.isFailbackRequired()) {
387
462
  const primaryServerStatus = await this.isPrimaryActive();
388
463
  if (Object.keys(this.callManager.getActiveCalls()).length === 0 && primaryServerStatus) {
389
- log.info(`Attempting failback to primary.`, {
390
- file: REGISTRATION_FILE,
391
- method: this.executeFailback.name,
392
- });
464
+ log.info(`Attempting failback to primary.`, loggerContext);
393
465
  await this.deregister();
466
+ if (this.apiRequest.isSocketEnabled()) {
467
+ log.info('Disconnecting from backup Mobius socket for failback to primary', loggerContext);
468
+ await this.apiRequest.disconnectFromMobiusSocket({
469
+ code: 3050,
470
+ reason: 'done (permanent)',
471
+ });
472
+ log.log('Mobius socket disconnect complete prior to primary failback', loggerContext);
473
+ }
394
474
  const abort = await this.attemptRegistrationWithServers(FAILBACK_UTIL);
395
475
  if (this.scheduled429Retry || abort || this.isDeviceRegistered()) {
396
476
  return;
@@ -401,7 +481,7 @@ export class Registration {
401
481
  return;
402
482
  }
403
483
  if (!this.isDeviceRegistered()) {
404
- await this.restartRegistration(this.executeFailback.name);
484
+ await this.restartRegistration(loggerContext.method);
405
485
  }
406
486
  else {
407
487
  this.failbackTimer = undefined;
@@ -409,10 +489,7 @@ export class Registration {
409
489
  }
410
490
  }
411
491
  else {
412
- log.info('Active calls present or primary Mobius is down, deferring failback to next cycle.', {
413
- file: REGISTRATION_FILE,
414
- method: this.executeFailback.name,
415
- });
492
+ log.info('Active calls present or primary Mobius is down, deferring failback to next cycle.', loggerContext);
416
493
  this.failbackTimer = undefined;
417
494
  this.initiateFailback();
418
495
  }
@@ -442,12 +519,18 @@ export class Registration {
442
519
  this.registrationStatus = value;
443
520
  }
444
521
  async restartRegistration(caller) {
522
+ const loggerContext = {
523
+ file: REGISTRATION_FILE,
524
+ method: METHODS.RESTART_REGISTRATION,
525
+ };
526
+ log.info(`${METHOD_START_MESSAGE} - caller: ${caller}`, loggerContext);
445
527
  this.clearFailbackTimer();
446
528
  this.failback429RetryAttempts = 0;
447
529
  const abort = await this.attemptRegistrationWithServers(caller, this.primaryMobiusUris);
448
530
  if (!abort && !this.isDeviceRegistered()) {
449
531
  await this.startFailoverTimer();
450
532
  }
533
+ log.log(`restartRegistration completed - caller: ${caller}, deviceRegistered: ${this.isDeviceRegistered()}, abort: ${abort}`, loggerContext);
451
534
  }
452
535
  async handleConnectionRestoration(retry) {
453
536
  log.info(METHOD_START_MESSAGE, {
@@ -500,7 +583,13 @@ export class Registration {
500
583
  };
501
584
  }
502
585
  async triggerRegistration() {
586
+ const loggerContext = {
587
+ file: REGISTRATION_FILE,
588
+ method: METHODS.TRIGGER_REGISTRATION,
589
+ };
590
+ log.info(METHOD_START_MESSAGE, loggerContext);
503
591
  if (await this.resumeFailover()) {
592
+ log.info('Registration trigger handled by resumeFailover path', loggerContext);
504
593
  return;
505
594
  }
506
595
  if (this.primaryMobiusUris.length > 0) {
@@ -508,43 +597,48 @@ export class Registration {
508
597
  if (!this.isDeviceRegistered() && !abort) {
509
598
  await this.startFailoverTimer();
510
599
  }
600
+ log.log(`triggerRegistration completed - deviceRegistered: ${this.isDeviceRegistered()}, abort: ${abort}`, loggerContext);
601
+ }
602
+ else {
603
+ log.warn('triggerRegistration skipped: no primary Mobius URIs available', loggerContext);
511
604
  }
512
605
  }
513
606
  async attemptRegistrationWithServers(caller, servers = this.primaryMobiusUris) {
607
+ const loggerContext = {
608
+ file: REGISTRATION_FILE,
609
+ method: REGISTER_UTIL,
610
+ };
514
611
  let abort = false;
515
612
  this.retryAfter = undefined;
613
+ let connectedWebSocketUrl;
516
614
  if (this.failoverImmediately) {
517
615
  return abort;
518
616
  }
519
617
  if (this.isDeviceRegistered()) {
520
- log.info(`[${caller}] : Device already registered with : ${this.activeMobiusUrl}`, {
521
- file: REGISTRATION_FILE,
522
- method: REGISTER_UTIL,
523
- });
618
+ log.info(`[${caller}] : Device already registered with : ${this.activeMobiusUrl}`, loggerContext);
524
619
  return abort;
525
620
  }
526
621
  for (const url of servers) {
527
- const serverType = (this.primaryMobiusUris.includes(url) && 'PRIMARY') ||
528
- (this.backupMobiusUris?.includes(url) && 'BACKUP') ||
529
- 'UNKNOWN';
622
+ const serverType = this.getServerType(url);
530
623
  try {
531
624
  abort = false;
532
625
  this.registrationStatus = RegistrationStatus.INACTIVE;
533
626
  this.lineEmitter(LINE_EVENTS.CONNECTING);
534
- log.info(`[${caller}] : Mobius url to contact: ${url}`, {
535
- file: REGISTRATION_FILE,
536
- method: REGISTER_UTIL,
537
- });
627
+ log.info(`[${caller}] : Mobius url to contact: ${url}`, loggerContext);
628
+ if (this.apiRequest.isSocketEnabled()) {
629
+ const wssNormalizedUrl = url.endsWith('/') ? url.slice(0, -1) : url;
630
+ log.info(`[${caller}] : Connecting to Mobius WebSocket - serverType: ${serverType}, wssUrl: ${wssNormalizedUrl}`, loggerContext);
631
+ connectedWebSocketUrl = await this.apiRequest.connectToMobiusSocket(wssNormalizedUrl);
632
+ connectedWebSocketUrl = connectedWebSocketUrl ? `${connectedWebSocketUrl}/` : undefined;
633
+ log.log(`[${caller}] : Mobius WebSocket connected - serverType: ${serverType}, connectedWebSocketUrl: ${connectedWebSocketUrl}`, loggerContext);
634
+ }
538
635
  const resp = await this.postRegistration(url);
539
636
  this.clearFailoverState();
540
637
  this.deviceInfo = resp.body;
541
638
  this.registrationStatus = RegistrationStatus.ACTIVE;
542
- this.setActiveMobiusUrl(url);
639
+ this.setActiveMobiusUrl(connectedWebSocketUrl || url);
543
640
  this.lineEmitter(LINE_EVENTS.REGISTERED, resp.body);
544
- log.log(`Registration successful for deviceId: ${this.deviceInfo.device?.deviceId} userId: ${this.userId} responseTrackingId: ${resp.headers?.trackingid}`, {
545
- file: REGISTRATION_FILE,
546
- method: METHODS.REGISTER,
547
- });
641
+ log.log(`Registration successful for deviceId: ${this.deviceInfo.device?.deviceId} userId: ${this.userId} responseTrackingId: ${resp.headers?.trackingid}`, loggerContext);
548
642
  this.setIntervalValues(this.deviceInfo);
549
643
  this.metricManager.setDeviceInfo(this.deviceInfo);
550
644
  this.metricManager.submitRegistrationMetric(METRIC_EVENT.REGISTRATION, REG_ACTION.REGISTER, METRIC_TYPE.BEHAVIORAL, caller, serverType, resp.headers?.trackingid ?? '', undefined, undefined);
@@ -554,22 +648,29 @@ export class Registration {
554
648
  }
555
649
  catch (err) {
556
650
  const body = err;
557
- abort = await handleRegistrationErrors(body, (clientError, finalError) => {
558
- if (finalError) {
651
+ const { finalError, shouldDisconnect } = await handleRegistrationErrors(body, (clientError, isFinalError) => {
652
+ if (isFinalError) {
559
653
  this.lineEmitter(LINE_EVENTS.ERROR, undefined, clientError);
560
654
  }
561
655
  else {
562
656
  this.lineEmitter(LINE_EVENTS.UNREGISTERED);
563
657
  }
564
658
  this.metricManager.submitRegistrationMetric(METRIC_EVENT.REGISTRATION_ERROR, REG_ACTION.REGISTER, METRIC_TYPE.BEHAVIORAL, caller, serverType, body.headers?.trackingid ?? '', undefined, clientError);
565
- }, { method: caller, file: REGISTRATION_FILE }, (retryAfter, retryCaller) => this.handle429Retry(retryAfter, retryCaller), this.restoreRegistrationCallBack());
659
+ }, { method: caller, file: REGISTRATION_FILE }, (retryAfter, retryCaller) => this.handle429Retry(retryAfter, retryCaller), this.restoreRegistrationCallBack(), servers.length);
660
+ abort = finalError;
566
661
  if (this.registrationStatus === RegistrationStatus.ACTIVE) {
567
- log.info(`[${caller}] : Device is already restored, active mobius url: ${this.activeMobiusUrl}`, {
568
- file: REGISTRATION_FILE,
569
- method: this.attemptRegistrationWithServers.name,
570
- });
662
+ log.info(`[${caller}] : Device is already restored, active mobius url: ${this.activeMobiusUrl}`, loggerContext);
571
663
  break;
572
664
  }
665
+ if (shouldDisconnect && this.apiRequest.isSocketEnabled()) {
666
+ connectedWebSocketUrl = undefined;
667
+ log.info(`[${caller}] : Tearing down Mobius WebSocket after registration error - serverType: ${serverType}`, loggerContext);
668
+ await this.apiRequest.disconnectFromMobiusSocket({
669
+ code: 3050,
670
+ reason: 'done (permanent)',
671
+ });
672
+ log.log(`[${caller}] : Mobius WebSocket disconnect complete after registration error - serverType: ${serverType}`, loggerContext);
673
+ }
573
674
  if (abort) {
574
675
  this.setStatus(RegistrationStatus.INACTIVE);
575
676
  await uploadLogs();
@@ -584,7 +685,6 @@ export class Registration {
584
685
  const RETRY_COUNT_THRESHOLD = this.isCCFlow ? 4 : 5;
585
686
  await this.mutex.runExclusive(async () => {
586
687
  if (this.isDeviceRegistered()) {
587
- const accessToken = await this.webex.credentials.getUserToken();
588
688
  if (!this.webWorker) {
589
689
  const blob = new Blob([webWorkerStr], { type: 'application/javascript' });
590
690
  const blobUrl = URL.createObjectURL(blob);
@@ -592,17 +692,38 @@ export class Registration {
592
692
  URL.revokeObjectURL(blobUrl);
593
693
  this.webWorker.postMessage({
594
694
  type: WorkerMessageType.START_KEEPALIVE,
595
- accessToken: String(accessToken),
596
- deviceUrl: String(this.webex.internal.device.url),
597
695
  interval,
598
696
  retryCountThreshold: RETRY_COUNT_THRESHOLD,
599
- url,
600
697
  });
601
698
  this.webWorker.onmessage = async (event) => {
602
699
  const logContext = {
603
700
  file: REGISTRATION_FILE,
604
701
  method: KEEPALIVE_UTIL,
605
702
  };
703
+ if (event.data.type === WorkerMessageType.SEND_KEEPALIVE) {
704
+ try {
705
+ const res = await this.postKeepAlive(String(this.webex.internal.device.url), url);
706
+ this.webWorker?.postMessage({
707
+ type: WorkerMessageType.KEEPALIVE_RESULT,
708
+ statusCode: res.statusCode,
709
+ });
710
+ }
711
+ catch (err) {
712
+ const error = {
713
+ headers: {
714
+ trackingid: err.headers?.trackingid,
715
+ 'retry-after': err.headers['retry-after'],
716
+ },
717
+ statusCode: err.statusCode,
718
+ statusText: err.statusText,
719
+ type: err.type,
720
+ };
721
+ this.webWorker?.postMessage({
722
+ type: WorkerMessageType.KEEPALIVE_RESULT,
723
+ err: error,
724
+ });
725
+ }
726
+ }
606
727
  if (event.data.type === WorkerMessageType.KEEPALIVE_SUCCESS) {
607
728
  log.info(`Sent Keepalive, status: ${event.data.statusCode}`, logContext);
608
729
  this.lineEmitter(LINE_EVENTS.RECONNECTED);
@@ -610,7 +731,7 @@ export class Registration {
610
731
  if (event.data.type === WorkerMessageType.KEEPALIVE_FAILURE) {
611
732
  const error = event.data.err;
612
733
  log.warn(`Keep-alive missed ${event.data.keepAliveRetryCount} times. Status -> ${error.statusCode} `, logContext);
613
- const abort = await handleRegistrationErrors(error, (clientError, finalError) => {
734
+ const { finalError: abort } = await handleRegistrationErrors(error, (clientError, finalError) => {
614
735
  if (finalError) {
615
736
  this.lineEmitter(LINE_EVENTS.ERROR, undefined, clientError);
616
737
  }
@@ -650,18 +771,17 @@ export class Registration {
650
771
  return this.reconnectPending;
651
772
  }
652
773
  async deregister() {
774
+ const loggerContext = {
775
+ file: REGISTRATION_FILE,
776
+ method: METHODS.DEREGISTER,
777
+ };
778
+ log.info(METHOD_START_MESSAGE, loggerContext);
653
779
  try {
654
780
  await this.deleteRegistration(this.activeMobiusUrl, this.deviceInfo.device?.deviceId, this.deviceInfo.device?.clientDeviceUri);
655
- log.log('Registration successfully deregistered', {
656
- file: REGISTRATION_FILE,
657
- method: METHODS.DEREGISTER,
658
- });
781
+ log.log('Registration successfully deregistered', loggerContext);
659
782
  }
660
783
  catch (err) {
661
- log.warn(`Delete failed with Mobius: ${JSON.stringify(err)}`, {
662
- file: REGISTRATION_FILE,
663
- method: METHODS.DEREGISTER,
664
- });
784
+ log.warn(`Delete failed with Mobius: ${JSON.stringify(err)}`, loggerContext);
665
785
  }
666
786
  this.clearKeepaliveTimer();
667
787
  this.setStatus(RegistrationStatus.INACTIVE);
@@ -683,7 +803,10 @@ export class Registration {
683
803
  rehomingIntervalMin: DEFAULT_REHOMING_INTERVAL_MIN,
684
804
  };
685
805
  const stringToReplace = `${DEVICES_ENDPOINT_RESOURCE}/${restoreData.devices[0].deviceId}`;
686
- const uri = restoreData.devices[0].uri.replace(stringToReplace, '');
806
+ let uri = restoreData.devices[0].uri.replace(stringToReplace, '');
807
+ if (this.apiRequest.isSocketEnabled()) {
808
+ uri = uri.replace('https://', 'wss://');
809
+ }
687
810
  this.setActiveMobiusUrl(uri);
688
811
  this.registrationStatus = RegistrationStatus.ACTIVE;
689
812
  return true;
@@ -709,5 +832,46 @@ export class Registration {
709
832
  }
710
833
  }
711
834
  }
835
+ async handleRegistrationDownEvent(event) {
836
+ const loggerContext = {
837
+ file: REGISTRATION_FILE,
838
+ method: METHODS.HANDLE_REGISTRATION_DOWN_EVENT,
839
+ };
840
+ log.info(`Registration down received - trackingId: ${event?.trackingId ?? 'unknown'}, eventId: ${event?.eventId ?? 'unknown'}`, loggerContext);
841
+ const [activeCall] = Object.values(this.callManager.getActiveCalls());
842
+ activeCall?.end();
843
+ await this.performRegistrationDownCleanup(METHODS.HANDLE_REGISTRATION_DOWN_EVENT);
844
+ }
845
+ async performRegistrationDownCleanup(caller) {
846
+ const loggerContext = {
847
+ file: REGISTRATION_FILE,
848
+ method: METHODS.HANDLE_REGISTRATION_DOWN_EVENT,
849
+ };
850
+ log.info(`[${caller}] : Running registration-down cleanup`, loggerContext);
851
+ await this.mutex.runExclusive(async () => {
852
+ this.clearFailbackTimer();
853
+ this.clearKeepaliveTimer();
854
+ this.reconnectPending = false;
855
+ this.scheduled429Retry = false;
856
+ this.failoverImmediately = false;
857
+ this.retryAfter = undefined;
858
+ this.registerRetry = false;
859
+ this.clearFailoverState();
860
+ this.setStatus(RegistrationStatus.INACTIVE);
861
+ if (this.apiRequest.isSocketEnabled()) {
862
+ try {
863
+ await this.apiRequest.disconnectFromMobiusSocket({
864
+ code: 3050,
865
+ reason: 'done (permanent)',
866
+ });
867
+ log.log('Mobius socket disconnect complete after registration-down', loggerContext);
868
+ }
869
+ catch (err) {
870
+ log.warn(`Mobius socket disconnect failed after registration-down: ${String(err)}`, loggerContext);
871
+ }
872
+ }
873
+ this.lineEmitter(LINE_EVENTS.UNREGISTERED);
874
+ });
875
+ }
712
876
  }
713
877
  export const createRegistration = (webex, serviceData, mutex, lineEmitter, logLevel, jwe) => new Registration(webex, serviceData, mutex, lineEmitter, logLevel, jwe);
@@ -1,73 +1,54 @@
1
- import { v4 as uuid } from 'uuid';
2
- import { HTTP_METHODS, WorkerMessageType } from '../../common/types';
1
+ import { WorkerMessageType } from '../../common/types';
3
2
  let keepaliveTimer;
3
+ let keepAliveRetryCount = 0;
4
+ let keepaliveInFlight = false;
5
+ const clearKeepaliveTimer = () => {
6
+ if (keepaliveTimer) {
7
+ clearInterval(keepaliveTimer);
8
+ keepaliveTimer = undefined;
9
+ }
10
+ };
4
11
  const messageHandler = (event) => {
5
12
  const { type } = event.data;
6
- const postKeepAlive = async (accessToken, deviceUrl, url) => {
7
- const response = await fetch(`${url}/status`, {
8
- method: HTTP_METHODS.POST,
9
- headers: {
10
- 'cisco-device-url': deviceUrl,
11
- 'spark-user-agent': 'webex-calling/beta',
12
- Authorization: `${accessToken}`,
13
- trackingId: `web_worker_${uuid()}`,
14
- },
15
- });
16
- if (!response.ok) {
17
- throw response;
18
- }
19
- return response;
20
- };
21
13
  if (type === WorkerMessageType.START_KEEPALIVE) {
22
- let keepAliveRetryCount = 0;
23
- const { accessToken, deviceUrl, interval, retryCountThreshold, url } = event.data;
24
- if (keepaliveTimer) {
25
- clearInterval(keepaliveTimer);
26
- keepaliveTimer = undefined;
27
- }
28
- keepaliveTimer = setInterval(async () => {
29
- if (keepAliveRetryCount < retryCountThreshold) {
30
- try {
31
- const res = await postKeepAlive(accessToken, deviceUrl, url);
32
- const statusCode = res.status;
33
- if (keepAliveRetryCount > 0) {
34
- postMessage({
35
- type: WorkerMessageType.KEEPALIVE_SUCCESS,
36
- statusCode,
37
- });
38
- }
39
- keepAliveRetryCount = 0;
40
- }
41
- catch (err) {
42
- const headers = {};
43
- if (err.headers?.has('Retry-After')) {
44
- headers['retry-after'] = err.headers.get('Retry-After');
45
- }
46
- if (err.headers?.has('Trackingid')) {
47
- headers['trackingid'] = err.headers.get('Trackingid');
48
- }
49
- const error = {
50
- headers,
51
- statusCode: err.status,
52
- statusText: err.statusText,
53
- type: err.type,
54
- };
55
- keepAliveRetryCount += 1;
56
- postMessage({
57
- type: WorkerMessageType.KEEPALIVE_FAILURE,
58
- err: error,
59
- keepAliveRetryCount,
60
- });
61
- }
14
+ const { interval, retryCountThreshold } = event.data;
15
+ clearKeepaliveTimer();
16
+ keepAliveRetryCount = 0;
17
+ keepaliveInFlight = false;
18
+ keepaliveTimer = setInterval(() => {
19
+ if (keepAliveRetryCount < retryCountThreshold && !keepaliveInFlight) {
20
+ keepaliveInFlight = true;
21
+ postMessage({
22
+ type: WorkerMessageType.SEND_KEEPALIVE,
23
+ });
62
24
  }
63
25
  }, interval * 1000);
64
26
  }
65
- if (type === WorkerMessageType.CLEAR_KEEPALIVE) {
66
- if (keepaliveTimer) {
67
- clearInterval(keepaliveTimer);
68
- keepaliveTimer = undefined;
27
+ if (type === WorkerMessageType.KEEPALIVE_RESULT) {
28
+ keepaliveInFlight = false;
29
+ if (event.data.err === undefined) {
30
+ if (keepAliveRetryCount > 0) {
31
+ postMessage({
32
+ type: WorkerMessageType.KEEPALIVE_SUCCESS,
33
+ statusCode: event.data.statusCode,
34
+ });
35
+ }
36
+ keepAliveRetryCount = 0;
37
+ }
38
+ else {
39
+ keepAliveRetryCount += 1;
40
+ postMessage({
41
+ type: WorkerMessageType.KEEPALIVE_FAILURE,
42
+ err: event.data.err,
43
+ keepAliveRetryCount,
44
+ });
69
45
  }
70
46
  }
47
+ if (type === WorkerMessageType.CLEAR_KEEPALIVE) {
48
+ clearKeepaliveTimer();
49
+ keepAliveRetryCount = 0;
50
+ keepaliveInFlight = false;
51
+ }
71
52
  };
72
53
  self.addEventListener('message', messageHandler);
73
54
  export default messageHandler;