@webex/calling 3.12.0-mobius-socket.18 → 3.12.0-mobius-socket.20

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 (49) hide show
  1. package/dist/CallingClient/utils/request.js +6 -3
  2. package/dist/CallingClient/utils/request.js.map +1 -1
  3. package/dist/CallingClient/utils/request.test.js +2 -2
  4. package/dist/CallingClient/utils/request.test.js.map +1 -1
  5. package/dist/CallingClient/utils/types.js.map +1 -1
  6. package/dist/mobius-socket/config.js +7 -44
  7. package/dist/mobius-socket/config.js.map +1 -1
  8. package/dist/mobius-socket/errors.js +71 -26
  9. package/dist/mobius-socket/errors.js.map +1 -1
  10. package/dist/mobius-socket/index.js +4 -54
  11. package/dist/mobius-socket/index.js.map +1 -1
  12. package/dist/mobius-socket/mobius-socket-events.test.js +20 -48
  13. package/dist/mobius-socket/mobius-socket-events.test.js.map +1 -1
  14. package/dist/mobius-socket/mobius-socket.js +359 -748
  15. package/dist/mobius-socket/mobius-socket.js.map +1 -1
  16. package/dist/mobius-socket/mobius-socket.test.js +452 -728
  17. package/dist/mobius-socket/mobius-socket.test.js.map +1 -1
  18. package/dist/mobius-socket/socket/constants.js +14 -0
  19. package/dist/mobius-socket/socket/constants.js.map +1 -1
  20. package/dist/mobius-socket/socket/socket-base.js +152 -205
  21. package/dist/mobius-socket/socket/socket-base.js.map +1 -1
  22. package/dist/mobius-socket/socket/types.js.map +1 -1
  23. package/dist/mobius-socket/socket.test.js +38 -63
  24. package/dist/mobius-socket/socket.test.js.map +1 -1
  25. package/dist/mobius-socket/types.js.map +1 -1
  26. package/dist/module/CallingClient/utils/request.js +3 -2
  27. package/dist/module/mobius-socket/config.js +7 -10
  28. package/dist/module/mobius-socket/errors.js +34 -0
  29. package/dist/module/mobius-socket/index.js +0 -3
  30. package/dist/module/mobius-socket/mobius-socket.js +237 -426
  31. package/dist/module/mobius-socket/socket/socket-base.js +79 -116
  32. package/dist/types/CallingClient/utils/request.d.ts.map +1 -1
  33. package/dist/types/CallingClient/utils/types.d.ts +1 -1
  34. package/dist/types/CallingClient/utils/types.d.ts.map +1 -1
  35. package/dist/types/mobius-socket/config.d.ts +7 -8
  36. package/dist/types/mobius-socket/config.d.ts.map +1 -1
  37. package/dist/types/mobius-socket/errors.d.ts +11 -1
  38. package/dist/types/mobius-socket/errors.d.ts.map +1 -1
  39. package/dist/types/mobius-socket/index.d.ts +1 -5
  40. package/dist/types/mobius-socket/index.d.ts.map +1 -1
  41. package/dist/types/mobius-socket/mobius-socket.d.ts +33 -35
  42. package/dist/types/mobius-socket/mobius-socket.d.ts.map +1 -1
  43. package/dist/types/mobius-socket/socket/constants.d.ts.map +1 -1
  44. package/dist/types/mobius-socket/socket/socket-base.d.ts +9 -10
  45. package/dist/types/mobius-socket/socket/socket-base.d.ts.map +1 -1
  46. package/dist/types/mobius-socket/socket/types.d.ts +0 -8
  47. package/dist/types/mobius-socket/socket/types.d.ts.map +1 -1
  48. package/dist/types/mobius-socket/types.d.ts.map +1 -1
  49. package/package.json +1 -1
@@ -2,18 +2,30 @@
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file
3
3
  */
4
4
  import { EventEmitter } from 'events';
5
- import { camelCase, set } from 'lodash';
6
5
  import backoff from 'backoff';
7
6
  import Socket from './socket';
8
- import { BadRequest, Forbidden, NotAuthorized, UnknownResponse, } from './errors';
7
+ import { BadRequest, Forbidden, NotAuthorized, UnknownResponse } from './errors';
9
8
  const normalReconnectReasons = ['idle', 'done (forced)'];
10
- const DEFAULT_MOBIUS_WEBSOCKET_SESSION = 'mobius-websocket-session';
11
9
  const MOBIUS_SOCKET_NAMESPACE = 'MobiusSocket';
12
10
  const TOKEN_REFRESH_INTERVAL_MS = 1 * 60 * 60 * 1000;
13
11
  function normalizeMobiusAuthToken(token) {
14
12
  return token.replace(/^Bearer\s+/i, '');
15
13
  }
16
14
  class MobiusSocket extends EventEmitter {
15
+ webex;
16
+ config;
17
+ logger;
18
+ connected;
19
+ connecting;
20
+ hasEverConnected;
21
+ socket;
22
+ backoffCall;
23
+ shutdownSwitchoverBackoffCall;
24
+ seenAsyncEventIds;
25
+ connectPromise;
26
+ socketUrl;
27
+ tokenRefreshTimer;
28
+ tokenRefreshInFlight;
17
29
  constructor(webex, config = {}) {
18
30
  super();
19
31
  if (!webex) {
@@ -22,20 +34,16 @@ class MobiusSocket extends EventEmitter {
22
34
  this.webex = webex;
23
35
  this.config = config;
24
36
  this.logger = webex.logger || console;
25
- this.defaultSessionId = DEFAULT_MOBIUS_WEBSOCKET_SESSION;
26
37
  this.connected = false;
27
38
  this.connecting = false;
28
39
  this.hasEverConnected = false;
29
40
  this.socket = undefined;
30
- this.sockets = new Map();
31
- this.backoffCalls = new Map();
32
- this._shutdownSwitchoverBackoffCalls = new Map();
33
- this._seenAsyncEventIdsBySession = new Map();
34
- this._connectPromises = new Map();
35
- this.mercuryTimeOffset = undefined;
36
- this._tokenRefreshTimer = undefined;
37
- this._tokenRefreshInFlight = undefined;
38
- this._bindInternalEvents();
41
+ this.backoffCall = undefined;
42
+ this.shutdownSwitchoverBackoffCall = undefined;
43
+ this.seenAsyncEventIds = new Map();
44
+ this.connectPromise = undefined;
45
+ this.tokenRefreshTimer = undefined;
46
+ this.tokenRefreshInFlight = undefined;
39
47
  }
40
48
  off(eventName, listener) {
41
49
  if (listener) {
@@ -44,88 +52,50 @@ class MobiusSocket extends EventEmitter {
44
52
  this.removeAllListeners(eventName);
45
53
  return this;
46
54
  }
47
- _bindInternalEvents() {
48
- this.on('event:featureToggle_update', (envelope) => {
49
- if (envelope && envelope.data) {
50
- this.webex.internal.feature.updateFeature(envelope.data.featureToggle);
51
- }
52
- });
53
- this.on('event:ActiveClusterStatusEvent', (envelope) => {
54
- if (typeof this.webex.internal.services?.switchActiveClusterIds === 'function' &&
55
- envelope &&
56
- envelope.data) {
57
- this.webex.internal.services.switchActiveClusterIds(envelope.data?.activeClusters);
58
- }
59
- });
60
- this.on('event:u2c.cache-invalidation', (envelope) => {
61
- if (typeof this.webex.internal.services?.invalidateCache === 'function' &&
62
- envelope &&
63
- envelope.data) {
64
- this.webex.internal.services.invalidateCache(envelope.data?.timestamp);
65
- }
66
- });
67
- }
68
- _attachSocketEventListeners(socket, sessionId) {
69
- socket.on('close', (event) => this._onclose(sessionId, event, socket));
70
- socket.on('message', (...args) => this._onmessage(sessionId, ...args));
71
- socket.on('pong', (...args) => this._setTimeOffset(sessionId, ...args));
72
- socket.on('sequence-mismatch', (...args) => this._emit(sessionId, 'sequence-mismatch', ...args));
73
- socket.on('ping-pong-latency', (...args) => this._emit(sessionId, 'ping-pong-latency', ...args));
55
+ attachSocketEventListeners(socket) {
56
+ socket.on('close', (event) => this.onclose(event, socket));
57
+ socket.on('message', (event) => this.onmessage(event));
74
58
  }
75
- _getSeenAsyncEventIds(sessionId) {
76
- let seenAsyncEventIds = this._seenAsyncEventIdsBySession.get(sessionId);
77
- if (!seenAsyncEventIds) {
78
- seenAsyncEventIds = new Map();
79
- this._seenAsyncEventIdsBySession.set(sessionId, seenAsyncEventIds);
80
- }
81
- return seenAsyncEventIds;
82
- }
83
- _clearSeenAsyncEventIds(sessionId) {
84
- if (sessionId) {
85
- this._seenAsyncEventIdsBySession.delete(sessionId);
86
- return;
87
- }
88
- this._seenAsyncEventIdsBySession.clear();
89
- }
90
- _trackAsyncEventAndShouldSuppressDuplicate(sessionId, envelope) {
59
+ trackAsyncEventAndShouldSuppressDuplicate(envelope) {
91
60
  if (envelope?.type !== 'async_event' || !envelope.eventId) {
92
61
  return false;
93
62
  }
94
- const seenAsyncEventIds = this._getSeenAsyncEventIds(sessionId);
95
- if (seenAsyncEventIds.has(envelope.eventId)) {
96
- const previousValue = seenAsyncEventIds.get(envelope.eventId);
97
- seenAsyncEventIds.delete(envelope.eventId);
98
- seenAsyncEventIds.set(envelope.eventId, previousValue);
99
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: duplicate async_event suppressed for ${sessionId}, eventId=${envelope.eventId}`);
63
+ if (this.seenAsyncEventIds.has(envelope.eventId)) {
64
+ const previousValue = this.seenAsyncEventIds.get(envelope.eventId) || true;
65
+ this.seenAsyncEventIds.delete(envelope.eventId);
66
+ this.seenAsyncEventIds.set(envelope.eventId, previousValue);
67
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: duplicate async_event suppressed, eventId=${envelope.eventId}`);
100
68
  return true;
101
69
  }
102
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: tracking async_event for ${sessionId}, eventId=${envelope.eventId}`);
103
- seenAsyncEventIds.set(envelope.eventId, true);
104
- if (seenAsyncEventIds.size > this.config.dedupCacheMaxSize) {
105
- const oldestEventId = seenAsyncEventIds.keys().next().value;
106
- seenAsyncEventIds.delete(oldestEventId);
107
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: evicted oldest async_event from dedup cache for ${sessionId}, eventId=${oldestEventId}`);
70
+ this.logger.log(`${MOBIUS_SOCKET_NAMESPACE}: tracking async_event, eventId=${envelope.eventId}`);
71
+ this.seenAsyncEventIds.set(envelope.eventId, true);
72
+ if (this.config.dedupCacheMaxSize &&
73
+ this.seenAsyncEventIds.size > this.config.dedupCacheMaxSize) {
74
+ const oldestEventId = this.seenAsyncEventIds.keys().next().value || '';
75
+ this.seenAsyncEventIds.delete(oldestEventId);
76
+ this.logger.log(`${MOBIUS_SOCKET_NAMESPACE}: evicted oldest async_event from dedup cache, eventId=${oldestEventId}`);
108
77
  }
109
78
  return false;
110
79
  }
111
- _handleImminentShutdown(sessionId) {
112
- const oldSocket = this.sockets.get(sessionId);
80
+ handleImminentShutdown() {
81
+ const oldSocket = this.socket;
113
82
  try {
114
- if (this._shutdownSwitchoverBackoffCalls.get(sessionId)) {
115
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover already in progress for ${sessionId}`);
83
+ if (this.shutdownSwitchoverBackoffCall) {
84
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover already in progress`);
116
85
  return;
117
86
  }
118
- const switchoverId = `${Date.now()}`;
119
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover start, id=${switchoverId} for ${sessionId}`);
120
- this._connectWithBackoff(undefined, sessionId, {
87
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover start`);
88
+ this.connectWithBackoff(undefined, {
121
89
  isShutdownSwitchover: true,
122
90
  attemptOptions: {
123
91
  isShutdownSwitchover: true,
124
92
  onSuccess: (newSocket, webSocketUrl) => {
125
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover connected, url: ${webSocketUrl} for ${sessionId}`);
126
- this.socket = this.sockets.get(this.defaultSessionId);
127
- this.connected = this.hasConnectedSockets();
128
- this._emit(sessionId, 'event:mercury_shutdown_switchover_complete', {
93
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover connected, url: ${webSocketUrl}`);
94
+ newSocket.connecting = false;
95
+ newSocket.connected = true;
96
+ this.socket = newSocket;
97
+ this.connected = true;
98
+ this.emitEvent('event:mobius_shutdown_switchover_complete', {
129
99
  url: webSocketUrl,
130
100
  });
131
101
  if (oldSocket) {
@@ -135,232 +105,127 @@ class MobiusSocket extends EventEmitter {
135
105
  },
136
106
  })
137
107
  .then(() => {
138
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover completed successfully for ${sessionId}`);
108
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover completed successfully`);
139
109
  })
140
110
  .catch((err) => {
141
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover exhausted retries; will fall back to normal reconnection for ${sessionId}: `, err);
142
- this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', { reason: err });
111
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover exhausted retries; will fall back to normal reconnection: `, err);
112
+ this.emitEvent('event:mobius_shutdown_switchover_failed', { reason: err });
143
113
  });
144
114
  }
145
115
  catch (e) {
146
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] error during switchover for ${sessionId}`, e);
147
- this._shutdownSwitchoverBackoffCalls.delete(sessionId);
148
- this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', { reason: e });
116
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] error during switchover`, e);
117
+ this.shutdownSwitchoverBackoffCall = undefined;
118
+ this.emitEvent('event:mobius_shutdown_switchover_failed', { reason: e });
149
119
  }
150
120
  }
151
- getLastError() {
152
- return this.lastError;
153
- }
154
- getSockets() {
155
- return this.sockets;
156
- }
157
- getSocket(sessionId = this.defaultSessionId) {
158
- return this.sockets.get(sessionId);
159
- }
160
- getConnectedWebSocketUrl(sessionId = this.defaultSessionId) {
161
- const socket = this.getSocket(sessionId);
162
- if (!socket?.connected) {
121
+ getConnectedWebSocketUrl() {
122
+ if (!this.socket?.connected) {
163
123
  return undefined;
164
124
  }
165
- return socket.url;
166
- }
167
- send(payload, sessionId = this.defaultSessionId) {
168
- const socket = this.getSocket(sessionId);
169
- if (!socket || !socket.connected) {
170
- return Promise.reject(new Error(`Mobius socket is not connected for session ${sessionId}`));
171
- }
172
- return socket.send(payload);
125
+ return this.socket.url;
173
126
  }
174
- sendWssRequest(payload, sessionIdOrRequestOptions = this.defaultSessionId, options = {}) {
127
+ sendWssRequest(payload, options = {}) {
175
128
  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
176
129
  return Promise.reject(new Error('`payload` is required'));
177
130
  }
178
- let sessionId = this.defaultSessionId;
179
- let requestOptions = options;
180
- if (typeof sessionIdOrRequestOptions === 'string') {
181
- sessionId = sessionIdOrRequestOptions;
182
- }
183
- else if (sessionIdOrRequestOptions && typeof sessionIdOrRequestOptions === 'object') {
184
- requestOptions = sessionIdOrRequestOptions;
185
- }
186
- const socket = this.getSocket(sessionId);
187
- if (!socket || !socket.connected) {
188
- return Promise.reject(new Error(`Mobius socket is not connected for session ${sessionId}`));
189
- }
190
- return socket.sendRequest(payload, {
191
- timeout: requestOptions.timeout,
192
- matchesResponse: (response, request) => response?.type === 'response_event' &&
193
- response?.subtype === request.type &&
194
- response?.trackingId === request.trackingId,
195
- getStatusCode: (response) => response?.statusCode,
196
- getStatusMessage: (response) => response?.statusMessage,
197
- createError: (response, statusCode, statusMessage) => this._createWssResponseError(response, statusCode, statusMessage),
198
- createTimeoutError: (request) => this._createWssResponseError({
199
- type: 'response_event',
200
- subtype: request.type,
201
- trackingId: request.trackingId,
202
- }, 408, 'Mobius websocket response timed out'),
203
- });
131
+ if (!this.socket || !this.socket.connected) {
132
+ return Promise.reject(new Error('Mobius socket is not connected'));
133
+ }
134
+ return this.socket.sendRequest(payload, { timeout: options.timeout });
204
135
  }
205
136
  isConnected() {
206
137
  return this.connected;
207
138
  }
208
- hasConnectedSockets(sessionId) {
209
- if (sessionId) {
210
- return Boolean(this.sockets.get(sessionId)?.connected);
211
- }
212
- for (const socket of this.sockets.values()) {
213
- if (socket?.connected) {
214
- return true;
215
- }
139
+ connect(webSocketUrl) {
140
+ if (this.connectPromise) {
141
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connection already in progress, returning existing promise`);
142
+ return this.connectPromise;
216
143
  }
217
- return false;
218
- }
219
- hasConnectingSockets(sessionId = this.defaultSessionId) {
220
- const socket = this.sockets.get(sessionId || this.defaultSessionId);
221
- return Boolean(socket?.connecting);
222
- }
223
- connect(webSocketUrl, sessionId = this.defaultSessionId) {
224
- if (this._connectPromises.has(sessionId)) {
225
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connection ${sessionId} already in progress, returning existing promise`);
226
- return this._connectPromises.get(sessionId);
227
- }
228
- const sessionSocket = this.sockets.get(sessionId);
229
- if (sessionSocket?.connected || sessionSocket?.connecting) {
230
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connection ${sessionId} already connected, will not connect again`);
144
+ if (this.socket?.connected || this.socket?.connecting) {
145
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: already connected, will not connect again`);
231
146
  return Promise.resolve();
232
147
  }
233
148
  if (webSocketUrl && this.socketUrl && webSocketUrl !== this.socketUrl) {
234
149
  this.hasEverConnected = false;
235
150
  }
236
- const resolvedUrl = webSocketUrl || this.socketUrl;
237
151
  if (webSocketUrl) {
238
152
  this.socketUrl = webSocketUrl;
239
153
  }
240
154
  this.connecting = true;
241
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: starting connection attempt for ${sessionId}${Number(this.config.initialConnectionMaxRetries) === 0 && !this.hasEverConnected
155
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: starting connection attempt${Number(this.config.initialConnectionMaxRetries) === 0 && !this.hasEverConnected
242
156
  ? ' (initial retries disabled)'
243
157
  : ''}`);
244
- const connectPromise = Promise.resolve(this.webex.internal.device.registered || this.webex.internal.device.register())
158
+ const connectPromise = Promise.resolve(this.webex.internal.device.registered || this.webex.internal.device.register?.())
245
159
  .then(() => {
246
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connecting ${sessionId}`);
247
- return this._connectWithBackoff(resolvedUrl, sessionId);
160
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connecting`);
161
+ return this.connectWithBackoff(this.socketUrl);
248
162
  })
249
163
  .finally(() => {
250
- this._connectPromises.delete(sessionId);
164
+ this.connectPromise = undefined;
251
165
  });
252
- this._connectPromises.set(sessionId, connectPromise);
166
+ this.connectPromise = connectPromise;
253
167
  return connectPromise;
254
168
  }
255
- logout() {
256
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: logout() called`);
257
- return this.disconnectAll(this.config.beforeLogoutOptionsCloseReason &&
258
- !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason)
259
- ? { code: 3050, reason: this.config.beforeLogoutOptionsCloseReason }
260
- : undefined);
261
- }
262
- disconnect(options, sessionId = this.defaultSessionId) {
263
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}#disconnect: connecting state: ${this.connecting}, connected state: ${this.connected}, socket exists: ${!!this
264
- .socket}, options: ${JSON.stringify(options)}`);
265
- const backoffCall = this.backoffCalls.get(sessionId);
266
- if (backoffCall) {
267
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: aborting connection ${sessionId}`);
268
- backoffCall.abort();
269
- this.backoffCalls.delete(sessionId);
270
- }
271
- const shutdownSwitchoverBackoffCall = this._shutdownSwitchoverBackoffCalls.get(sessionId);
272
- if (shutdownSwitchoverBackoffCall) {
273
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: aborting shutdown switchover connection ${sessionId}`);
274
- shutdownSwitchoverBackoffCall.abort();
275
- this._shutdownSwitchoverBackoffCalls.delete(sessionId);
276
- }
277
- this._connectPromises.delete(sessionId);
278
- const sessionSocket = this.sockets.get(sessionId);
279
- this._clearSeenAsyncEventIds(sessionId);
280
- if (!sessionSocket) {
281
- this.connected = this.hasConnectedSockets();
282
- if (!this.hasConnectedSockets()) {
283
- this._stopTokenRefreshTimer();
284
- }
169
+ disconnect(options) {
170
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}#disconnect: connecting state: ${this.connecting},
171
+ connected state: ${this.connected}, socket exists: ${!!this.socket},
172
+ options: ${JSON.stringify(options)}`);
173
+ if (this.backoffCall) {
174
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: aborting connection`);
175
+ this.backoffCall.abort();
176
+ this.backoffCall = undefined;
177
+ }
178
+ if (this.shutdownSwitchoverBackoffCall) {
179
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: aborting shutdown switchover connection`);
180
+ this.shutdownSwitchoverBackoffCall.abort();
181
+ this.shutdownSwitchoverBackoffCall = undefined;
182
+ }
183
+ this.connectPromise = undefined;
184
+ this.seenAsyncEventIds.clear();
185
+ if (!this.socket) {
186
+ this.connected = false;
187
+ this.stopTokenRefreshTimer();
285
188
  return Promise.resolve();
286
189
  }
287
- sessionSocket.removeAllListeners('message');
288
- sessionSocket.connecting = false;
289
- sessionSocket.connected = false;
290
- return Promise.resolve(sessionSocket.close(options || undefined)).finally(() => {
291
- this.connected = this.hasConnectedSockets();
292
- if (!this.hasConnectedSockets()) {
293
- this._stopTokenRefreshTimer();
294
- }
295
- });
296
- }
297
- disconnectAll(options) {
298
- const disconnectPromises = [];
299
- for (const sessionId of this.sockets.keys()) {
300
- disconnectPromises.push(this.disconnect(options, sessionId));
301
- }
302
- return Promise.all(disconnectPromises).then(() => {
190
+ this.socket.removeAllListeners('message');
191
+ this.socket.connecting = false;
192
+ this.socket.connected = false;
193
+ return Promise.resolve(this.socket.close(options || undefined)).finally(() => {
303
194
  this.connected = false;
304
- this.socket = undefined;
305
- this.sockets.clear();
306
- this.backoffCalls.clear();
307
- this._shutdownSwitchoverBackoffCalls.clear();
308
- this._clearSeenAsyncEventIds();
309
- this._stopTokenRefreshTimer();
310
- this._connectPromises.clear();
311
- });
312
- }
313
- processRegistrationStatusEvent(message) {
314
- this.localClusterServiceUrls = message.localClusterServiceUrls;
315
- }
316
- _createWssResponseError(response, statusCode, statusMessage) {
317
- const error = new Error(statusMessage || `Mobius websocket request failed with status ${statusCode || 'unknown'}`);
318
- error.name = 'MobiusSocketResponseError';
319
- error.statusCode = statusCode;
320
- error.statusMessage = statusMessage;
321
- error.response = response;
322
- error.trackingId = response?.trackingId;
323
- return error;
324
- }
325
- _applyOverrides(event) {
326
- if (!event || !event.headers) {
327
- return;
328
- }
329
- const headerKeys = Object.keys(event.headers);
330
- headerKeys.forEach((keyPath) => {
331
- set(event, keyPath, event.headers[keyPath]);
195
+ this.stopTokenRefreshTimer();
332
196
  });
333
197
  }
334
- _prepareUrl(webSocketUrl) {
198
+ prepareUrl(webSocketUrl) {
335
199
  if (!webSocketUrl) {
336
- webSocketUrl = this.webex.internal.device.webSocketUrl;
200
+ webSocketUrl = this.webex.internal.device.webSocketUrl || '';
337
201
  }
338
202
  return Promise.resolve(webSocketUrl);
339
203
  }
340
- _attemptConnection(socketUrl, sessionId, callback, options = {}) {
341
- const { isShutdownSwitchover = false, onSuccess = null } = options;
204
+ attemptConnection(socketUrl, callback, options = {}) {
205
+ const { isShutdownSwitchover = false, attemptOptions = {} } = options;
206
+ const { onSuccess = null } = attemptOptions;
342
207
  const socket = new Socket();
343
208
  socket.connecting = true;
344
209
  let newWSUrl;
345
- this._attachSocketEventListeners(socket, sessionId);
210
+ this.attachSocketEventListeners(socket);
346
211
  const backoffCall = isShutdownSwitchover
347
- ? this._shutdownSwitchoverBackoffCalls.get(sessionId)
348
- : this.backoffCalls.get(sessionId);
212
+ ? this.shutdownSwitchoverBackoffCall
213
+ : this.backoffCall;
349
214
  if (!backoffCall) {
350
215
  const mode = isShutdownSwitchover ? 'switchover backoff call' : 'backoffCall';
351
- const msg = `${MOBIUS_SOCKET_NAMESPACE}: prevent socket open when ${mode} no longer defined for ${sessionId}`;
216
+ const msg = `${MOBIUS_SOCKET_NAMESPACE}: prevent socket open when ${mode} no longer defined`;
352
217
  const err = new Error(msg);
353
218
  this.logger.info(msg);
354
219
  callback(err);
355
220
  return Promise.reject(err);
356
221
  }
357
222
  if (!isShutdownSwitchover) {
358
- this.sockets.set(sessionId, socket);
223
+ this.socket = socket;
359
224
  }
360
- return this._prepareAndOpenSocket(socket, socketUrl, sessionId, isShutdownSwitchover)
225
+ return this.prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover)
361
226
  .then((webSocketUrl) => {
362
227
  newWSUrl = webSocketUrl;
363
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${isShutdownSwitchover ? '[shutdown] switchover' : ''} connected to mobius socket, success, action: connected for ${sessionId}, url: ${newWSUrl}`);
228
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${isShutdownSwitchover ? '[shutdown] switchover' : ''} connected to mobius socket, success, url: ${newWSUrl}`);
364
229
  if (onSuccess) {
365
230
  onSuccess(socket, webSocketUrl);
366
231
  callback();
@@ -371,48 +236,48 @@ class MobiusSocket extends EventEmitter {
371
236
  })
372
237
  .catch((reason) => {
373
238
  if (isShutdownSwitchover) {
374
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover attempt failed for ${sessionId}`, reason);
239
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] switchover attempt failed`, reason);
375
240
  return callback(reason);
376
241
  }
377
- this.lastError = reason;
378
- const backoffCallNormal = this.backoffCalls.get(sessionId);
242
+ const backoffCallNormal = this.backoffCall;
379
243
  if (reason.code !== 1006 && backoffCallNormal && backoffCallNormal?.getNumRetries() > 0) {
380
- this._emit(sessionId, 'connection_failed', reason, {
381
- sessionId,
244
+ this.emitEvent('connection_failed', reason, {
382
245
  retries: backoffCallNormal?.getNumRetries(),
383
246
  });
384
247
  }
385
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connection attempt failed for ${sessionId}`, reason, backoffCallNormal?.getNumRetries() === 0 ? reason.stack : '');
248
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connection attempt failed`, reason, backoffCallNormal?.getNumRetries() === 0 ? reason.stack : '');
386
249
  if (reason instanceof UnknownResponse) {
387
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: received unknown response code for ${sessionId}, refreshing device registration`);
388
- return this.webex.internal.device.refresh().then(() => callback(reason));
250
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: received unknown response code, refreshing device registration`);
251
+ return this.webex.internal.device
252
+ .refresh?.()
253
+ .then(() => callback(reason));
389
254
  }
390
255
  if (reason instanceof NotAuthorized) {
391
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: received authorization error for ${sessionId}, reauthorizing`);
392
- return this.webex.credentials.refresh({ force: true }).then(() => callback(reason));
256
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: received authorization error, reauthorizing`);
257
+ return this.webex.credentials
258
+ .refresh?.({ force: true })
259
+ .then(() => callback(reason));
393
260
  }
394
261
  if (reason instanceof BadRequest || reason instanceof Forbidden) {
395
- this.logger.warn(`${MOBIUS_SOCKET_NAMESPACE}: received unrecoverable response from ${MOBIUS_SOCKET_NAMESPACE} for ${sessionId}`);
262
+ this.logger.warn(`${MOBIUS_SOCKET_NAMESPACE}: received unrecoverable response from ${MOBIUS_SOCKET_NAMESPACE}`);
396
263
  backoffCallNormal?.abort();
397
264
  return callback(reason);
398
265
  }
399
266
  return callback(reason);
400
267
  })
401
268
  .catch((reason) => {
402
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: failed to handle connection failure for ${sessionId}`, reason);
269
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: failed to handle connection failure`, reason);
403
270
  callback(reason);
404
271
  });
405
272
  }
406
- _prepareAndOpenSocket(socket, socketUrl, sessionId, isShutdownSwitchover = false) {
273
+ prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover = false) {
407
274
  const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
408
- return Promise.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(([webSocketUrl, token]) => {
275
+ return Promise.all([this.prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(([webSocketUrl, token]) => {
409
276
  let options = {
410
277
  forceCloseDelay: this.config.forceCloseDelay,
411
278
  wssResponseTimeout: this.config.wssResponseTimeout,
412
- skipAckEventId: this.config.skipAckEventId,
413
- skipAckEventType: this.config.skipAckEventType,
414
279
  token: normalizeMobiusAuthToken(token.toString()),
415
- refreshToken: () => this._refreshToken(),
280
+ refreshToken: () => this.refreshToken(),
416
281
  trackingId: `${this.webex.sessionId}_${Date.now()}`,
417
282
  logger: this.logger,
418
283
  };
@@ -423,13 +288,14 @@ class MobiusSocket extends EventEmitter {
423
288
  this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${customOptionsMsg}`);
424
289
  options = { ...options, ...this.webex.config.defaultMobiusSocketOptions };
425
290
  }
426
- this.sockets.set(sessionId, socket);
427
- this.socket = this.sockets.get(this.defaultSessionId);
428
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE} ${logPrefix} url for ${sessionId}: ${webSocketUrl}`);
291
+ if (!isShutdownSwitchover) {
292
+ this.socket = socket;
293
+ }
294
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE} ${logPrefix} url: ${webSocketUrl}`);
429
295
  return socket.open(webSocketUrl, options).then(() => webSocketUrl);
430
296
  });
431
297
  }
432
- _connectWithBackoff(webSocketUrl, sessionId, context = {}) {
298
+ connectWithBackoff(webSocketUrl, context = {}) {
433
299
  const { isShutdownSwitchover = false, attemptOptions = {} } = context;
434
300
  return new Promise((resolve, reject) => {
435
301
  let call;
@@ -438,44 +304,43 @@ class MobiusSocket extends EventEmitter {
438
304
  ? null
439
305
  : Number(this.config.initialConnectionMaxRetries);
440
306
  const isInitialConnectWithoutRetries = isInitialConnect && initialRetryLimit === 0;
441
- const onComplete = (err, sid = sessionId) => {
307
+ const onComplete = (err) => {
442
308
  if (isShutdownSwitchover) {
443
- this._shutdownSwitchoverBackoffCalls.delete(sid);
309
+ this.shutdownSwitchoverBackoffCall = undefined;
444
310
  }
445
311
  else {
446
- this.backoffCalls.delete(sid);
312
+ this.backoffCall = undefined;
447
313
  }
448
- const sessionSocket = this.sockets.get(sid);
449
314
  if (err) {
450
315
  const msg = isShutdownSwitchover
451
316
  ? `[shutdown] switchover failed after ${call.getNumRetries()} retries`
452
317
  : `failed to connect after ${call.getNumRetries()} retries`;
453
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${msg}; log statement about next retry was inaccurate; ${err}`);
454
- if (sessionSocket) {
455
- sessionSocket.connecting = false;
456
- sessionSocket.connected = false;
318
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${msg}; ${err}`);
319
+ if (!isShutdownSwitchover && this.socket) {
320
+ this.socket.connecting = false;
321
+ this.socket.connected = false;
457
322
  }
458
323
  return reject(err);
459
324
  }
460
- if (sessionSocket) {
461
- sessionSocket.connecting = false;
462
- sessionSocket.connected = true;
325
+ if (!isShutdownSwitchover && this.socket) {
326
+ this.socket.connecting = false;
327
+ this.socket.connected = true;
463
328
  }
464
329
  if (!isShutdownSwitchover) {
465
- this.connecting = this.hasConnectingSockets();
466
- this.connected = this.hasConnectedSockets();
330
+ this.connecting = false;
331
+ this.connected = true;
467
332
  this.hasEverConnected = true;
468
- this._startTokenRefreshTimer();
469
- this._emit(sid, 'online');
333
+ this.startTokenRefreshTimer();
334
+ this.emitEvent('online');
470
335
  }
471
336
  return resolve();
472
337
  };
473
338
  call = backoff.call((callback) => {
474
339
  const attemptNum = call.getNumRetries();
475
340
  const attemptLogPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
476
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: executing ${attemptLogPrefix} attempt ${attemptNum} for ${sessionId}`);
477
- this._attemptConnection(webSocketUrl, sessionId, callback, attemptOptions);
478
- }, (err) => onComplete(err, sessionId));
341
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: executing ${attemptLogPrefix} attempt ${attemptNum}`);
342
+ this.attemptConnection(webSocketUrl, callback, attemptOptions);
343
+ }, (err) => onComplete(err));
479
344
  call.setStrategy(new backoff.ExponentialStrategy({
480
345
  initialDelay: this.config.backoffTimeReset,
481
346
  maxDelay: this.config.backoffTimeMax,
@@ -483,278 +348,224 @@ class MobiusSocket extends EventEmitter {
483
348
  if (isInitialConnectWithoutRetries) {
484
349
  call.retryIf(() => false);
485
350
  }
486
- else if (isInitialConnect && initialRetryLimit > 0) {
351
+ else if (isInitialConnect && initialRetryLimit !== null && initialRetryLimit > 0) {
487
352
  call.failAfter(initialRetryLimit);
488
353
  }
489
354
  else if (this.config.maxRetries) {
490
355
  call.failAfter(this.config.maxRetries);
491
356
  }
492
357
  if (isShutdownSwitchover) {
493
- this._shutdownSwitchoverBackoffCalls.set(sessionId, call);
358
+ this.shutdownSwitchoverBackoffCall = call;
494
359
  }
495
360
  else {
496
- this.backoffCalls.set(sessionId, call);
361
+ this.backoffCall = call;
497
362
  }
498
363
  call.on('abort', () => {
499
364
  const msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
500
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${msg} aborted for ${sessionId}`);
501
- reject(new Error(`MobiusSocket ${msg} Aborted for ${sessionId}`));
365
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${msg} aborted`);
366
+ reject(new Error(`MobiusSocket ${msg} Aborted`));
502
367
  });
503
368
  call.on('callback', (err) => {
504
369
  if (err) {
505
370
  if (isInitialConnectWithoutRetries) {
506
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: initial connect failed for ${sessionId}; retries already disabled`);
371
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: initial connect failed; retries already disabled`);
507
372
  return;
508
373
  }
509
374
  const number = call.getNumRetries();
510
- const delay = Math.min(call.strategy_.nextBackoffDelay_, this.config.backoffTimeMax);
375
+ const delay = Math.min(call.strategy_.nextBackoffDelay_, this.config.backoffTimeMax || Infinity);
511
376
  const callbackLogPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
512
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${callbackLogPrefix} failed to connect; attempting retry ${number + 1} in ${delay} ms for ${sessionId}`);
377
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: ${callbackLogPrefix} failed to connect; attempting retry ${number + 1} in ${delay} ms`);
513
378
  if (process.env.NODE_ENV === 'development') {
514
379
  this.logger.debug(`${MOBIUS_SOCKET_NAMESPACE}: `, err, err.stack);
515
380
  }
516
381
  return;
517
382
  }
518
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connected ${sessionId}`);
383
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: connected`);
519
384
  });
520
385
  call.start();
521
386
  });
522
387
  }
523
- _emit(sessionId, eventName, ...args) {
388
+ emitEvent(eventName, ...args) {
524
389
  try {
525
- if (!sessionId || !eventName) {
390
+ if (!eventName) {
526
391
  return;
527
392
  }
528
- const suffix = sessionId === this.defaultSessionId ? '' : `:${sessionId}`;
529
- this.emit(`${eventName}${suffix}`, ...args);
393
+ this.emit(eventName, ...args);
530
394
  }
531
395
  catch (error) {
532
- try {
533
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred in event handler:`, error, ' with args: ', [sessionId, eventName, ...args]);
534
- }
535
- catch (logError) {
536
- console.error('MobiusSocket _emit error handling failed:', logError);
537
- }
538
- }
539
- }
540
- _getEventHandlers(eventType) {
541
- if (!eventType) {
542
- return [];
543
- }
544
- const [namespace, name] = eventType.split('.');
545
- const handlers = [];
546
- if (!this.webex[namespace] && !this.webex.internal[namespace]) {
547
- return handlers;
548
- }
549
- const handlerName = camelCase(`process_${name}_event`);
550
- if ((this.webex[namespace] || this.webex.internal[namespace])[handlerName]) {
551
- handlers.push({
552
- name: handlerName,
553
- namespace,
554
- });
396
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred in event handler:`, error, ' with args: ', [eventName, ...args]);
555
397
  }
556
- return handlers;
557
398
  }
558
- _startTokenRefreshTimer() {
559
- if (this._tokenRefreshTimer || !this.hasConnectedSockets()) {
399
+ startTokenRefreshTimer() {
400
+ if (this.tokenRefreshTimer || !this.connected) {
560
401
  return;
561
402
  }
562
- this._tokenRefreshTimer = setInterval(() => {
563
- this._refreshToken().catch((error) => {
403
+ this.tokenRefreshTimer = setInterval(() => {
404
+ this.refreshToken().catch((error) => {
564
405
  this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: periodic token refresh failed`, error);
565
406
  });
566
407
  }, TOKEN_REFRESH_INTERVAL_MS);
567
408
  }
568
- _stopTokenRefreshTimer() {
569
- if (!this._tokenRefreshTimer) {
409
+ stopTokenRefreshTimer() {
410
+ if (!this.tokenRefreshTimer) {
570
411
  return;
571
412
  }
572
- clearInterval(this._tokenRefreshTimer);
573
- this._tokenRefreshTimer = undefined;
413
+ clearInterval(this.tokenRefreshTimer);
414
+ this.tokenRefreshTimer = undefined;
574
415
  }
575
- _refreshToken() {
576
- if (this._tokenRefreshInFlight) {
577
- return this._tokenRefreshInFlight;
416
+ refreshToken() {
417
+ if (this.tokenRefreshInFlight) {
418
+ return this.tokenRefreshInFlight;
578
419
  }
579
- if (!this.hasConnectedSockets()) {
580
- this._stopTokenRefreshTimer();
420
+ if (!this.connected) {
421
+ this.stopTokenRefreshTimer();
581
422
  return Promise.resolve();
582
423
  }
583
424
  const tokenPromise = this.webex.credentials.canRefresh
584
425
  ? this.webex.credentials
585
- .refresh({ force: true })
586
- .then(() => this.webex.credentials.getUserToken())
426
+ .refresh?.({ force: true })
427
+ ?.then(() => this.webex.credentials.getUserToken())
587
428
  : this.webex.credentials.getUserToken();
588
- this._tokenRefreshInFlight = tokenPromise
429
+ this.tokenRefreshInFlight = tokenPromise
589
430
  .then((token) => {
590
431
  if (!token) {
591
432
  throw new Error('Mobius token refresh did not return a token');
592
433
  }
593
434
  const refreshedToken = normalizeMobiusAuthToken(token.toString());
594
- const authPayloadPromises = [];
595
- for (const socket of this.sockets.values()) {
596
- if (socket?.connected) {
597
- authPayloadPromises.push(socket.refresh(refreshedToken));
598
- }
435
+ if (!this.socket?.connected) {
436
+ this.logger.warn(`${MOBIUS_SOCKET_NAMESPACE}: socket is not connected, skipping token refresh`);
437
+ return undefined;
599
438
  }
600
- return Promise.all(authPayloadPromises);
439
+ return this.socket.refresh(refreshedToken);
601
440
  })
602
441
  .catch((error) => {
603
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: failed to refresh/re-auth Mobius sockets`, error);
442
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: failed to refresh/re-auth Mobius socket`, error);
604
443
  throw error;
605
444
  })
606
445
  .finally(() => {
607
- this._tokenRefreshInFlight = undefined;
446
+ this.tokenRefreshInFlight = undefined;
608
447
  });
609
- return this._tokenRefreshInFlight;
448
+ return this.tokenRefreshInFlight;
610
449
  }
611
- _onclose(sessionId, event, sourceSocket) {
450
+ onclose(event, sourceSocket) {
612
451
  try {
613
452
  const reason = event.reason && event.reason.toLowerCase();
614
- const sessionSocket = this.sockets.get(sessionId);
615
453
  let socketUrl;
616
- event.sessionId = sessionId;
617
- const isActiveSocket = sourceSocket === sessionSocket;
454
+ const isActiveSocket = sourceSocket === this.socket;
618
455
  if (sourceSocket) {
619
456
  socketUrl = sourceSocket.url;
620
457
  }
621
- this.sockets.delete(sessionId);
622
458
  if (isActiveSocket) {
623
- if (sessionSocket) {
624
- sessionSocket.removeAllListeners();
625
- if (sessionId === this.defaultSessionId) {
626
- this.socket = undefined;
627
- }
628
- this._emit(sessionId, 'offline', event);
629
- }
630
- this.connecting = this.hasConnectingSockets();
631
- this.connected = this.hasConnectedSockets();
632
- if (!this.hasConnectedSockets()) {
633
- this._stopTokenRefreshTimer();
459
+ if (this.socket) {
460
+ this.socket.removeAllListeners();
461
+ this.socket = undefined;
462
+ this.emitEvent('offline', event);
634
463
  }
464
+ this.connecting = false;
465
+ this.connected = false;
466
+ this.stopTokenRefreshTimer();
635
467
  }
636
468
  else {
637
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] non-active socket closed, code=${event.code} for ${sessionId}`);
469
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] non-active socket closed, code=${event.code}`);
638
470
  if (sourceSocket) {
639
471
  sourceSocket.removeAllListeners();
640
472
  }
641
473
  }
642
474
  switch (event.code) {
643
475
  case 1003:
644
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: service rejected last message for ${sessionId}; will not reconnect: ${event.reason}`);
476
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: service rejected last message; will not reconnect: ${event.reason}`);
645
477
  if (isActiveSocket)
646
- this._emit(sessionId, 'offline.permanent', event);
478
+ this.emitEvent('offline.permanent', event);
647
479
  break;
648
480
  case 4000:
649
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket ${sessionId} replaced; will not reconnect`);
481
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket replaced; will not reconnect`);
650
482
  if (isActiveSocket)
651
- this._emit(sessionId, 'offline.replaced', event);
483
+ this.emitEvent('offline.replaced', event);
652
484
  break;
653
485
  case 4001:
654
486
  if (isActiveSocket) {
655
- this.logger.warn(`${MOBIUS_SOCKET_NAMESPACE}: active socket closed with 4001; shutdown switchover failed for ${sessionId}`);
656
- this._emit(sessionId, 'offline.permanent', event);
487
+ this.logger.warn(`${MOBIUS_SOCKET_NAMESPACE}: active socket closed with 4001; shutdown switchover failed`);
488
+ this.emitEvent('offline.permanent', event);
657
489
  }
658
490
  else {
659
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: old socket closed with 4001 (replaced during shutdown); no reconnect needed for ${sessionId}`);
660
- this._emit(sessionId, 'offline.replaced', event);
491
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: old socket closed with 4001 (replaced during shutdown); no reconnect needed`);
492
+ this.emitEvent('offline.replaced', event);
661
493
  }
662
494
  break;
663
495
  case 1001:
664
496
  case 1005:
665
497
  case 1006:
666
498
  case 1011:
667
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket ${sessionId} disconnected; reconnecting`);
499
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket disconnected; reconnecting`);
668
500
  if (isActiveSocket) {
669
- this._emit(sessionId, 'offline.transient', event);
670
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] reconnecting active socket to recover for ${sessionId}`);
671
- this._reconnect(socketUrl, sessionId);
501
+ this.emitEvent('offline.transient', event);
502
+ this.reconnect(socketUrl);
672
503
  }
673
504
  break;
674
505
  case 1000:
675
506
  case 3050:
676
- if (normalReconnectReasons.includes(reason)) {
677
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket ${sessionId} disconnected; reconnecting`);
507
+ if (reason && normalReconnectReasons.includes(reason)) {
508
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket disconnected; reconnecting`);
678
509
  if (isActiveSocket) {
679
- this._emit(sessionId, 'offline.transient', event);
680
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] reconnecting due to normal close for ${sessionId}`);
681
- this._reconnect(socketUrl, sessionId);
510
+ this.emitEvent('offline.transient', event);
511
+ this.reconnect(socketUrl);
682
512
  }
683
513
  }
684
514
  else {
685
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket ${sessionId} disconnected; will not reconnect: ${event.reason}`);
515
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket disconnected; will not reconnect: ${event.reason}`);
686
516
  if (isActiveSocket)
687
- this._emit(sessionId, 'offline.permanent', event);
517
+ this.emitEvent('offline.permanent', event);
688
518
  }
689
519
  break;
690
520
  default:
691
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket ${sessionId} disconnected unexpectedly; will not reconnect`);
521
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: socket disconnected unexpectedly; will not reconnect`);
692
522
  if (isActiveSocket)
693
- this._emit(sessionId, 'offline.permanent', event);
523
+ this.emitEvent('offline.permanent', event);
694
524
  }
695
525
  }
696
526
  catch (error) {
697
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred in close handler for ${sessionId}`, error);
527
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred in close handler`, error);
698
528
  }
699
529
  }
700
- _onmessage(sessionId, event) {
701
- this._setTimeOffset(sessionId, event);
530
+ onmessage(event) {
702
531
  const envelope = event.data;
703
- if (process.env.ENABLE_MERCURY_LOGGING) {
704
- this.logger.debug(`${MOBIUS_SOCKET_NAMESPACE}: message envelope from ${sessionId}: `, envelope);
532
+ if (process.env.ENABLE_MOBIUS_LOGGING) {
533
+ this.logger.debug(`${MOBIUS_SOCKET_NAMESPACE}: message envelope: `, envelope);
705
534
  }
706
- envelope.sessionId = sessionId;
707
535
  if (envelope && envelope.type === 'shutdown') {
708
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] imminent shutdown message received for ${sessionId}`);
709
- this._emit(sessionId, 'event:mercury_shutdown_imminent', envelope);
710
- this._handleImminentShutdown(sessionId);
536
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: [shutdown] imminent shutdown message received`);
537
+ this.emitEvent('event:mobius_shutdown_imminent', envelope);
538
+ this.handleImminentShutdown();
711
539
  return Promise.resolve();
712
540
  }
713
- if (this._trackAsyncEventAndShouldSuppressDuplicate(sessionId, envelope)) {
541
+ if (this.trackAsyncEventAndShouldSuppressDuplicate(envelope)) {
714
542
  return Promise.resolve();
715
543
  }
716
544
  if (envelope.type) {
717
- this._emit(sessionId, `event:${envelope.type}`, envelope);
545
+ this.emitEvent(`event:${envelope.type}`, envelope);
718
546
  }
719
- envelope.sessionId = sessionId;
720
547
  const data = envelope.data || envelope;
721
- this._applyOverrides(data);
722
548
  const eventType = data?.eventType || envelope.eventType;
723
549
  if (!eventType) {
724
- this._emit(sessionId, 'event', envelope);
550
+ this.emitEvent('event', envelope);
725
551
  return Promise.resolve();
726
552
  }
727
- return this._getEventHandlers(eventType)
728
- .reduce((promise, handler) => promise.then(() => {
729
- const { namespace, name } = handler;
730
- return new Promise((resolve) => {
731
- resolve((this.webex[namespace] || this.webex.internal[namespace])[name](data));
732
- }).catch((reason) => this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred in autowired event handler for ${eventType} from ${sessionId}`, reason));
733
- }), Promise.resolve())
734
- .then(() => {
735
- this._emit(sessionId, 'event', envelope);
553
+ try {
554
+ this.emitEvent('event', envelope);
736
555
  const [namespace] = eventType.split('.');
737
- if (namespace === eventType) {
738
- this._emit(sessionId, `event:${namespace}`, envelope);
556
+ this.emitEvent(`event:${namespace}`, envelope);
557
+ if (namespace !== eventType) {
558
+ this.emitEvent(`event:${eventType}`, envelope);
739
559
  }
740
- else {
741
- this._emit(sessionId, `event:${namespace}`, envelope);
742
- this._emit(sessionId, `event:${eventType}`, envelope);
743
- }
744
- })
745
- .catch((reason) => {
746
- this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred processing socket message from ${sessionId}`, reason);
747
- });
748
- }
749
- _setTimeOffset(sessionId, event) {
750
- const { wsWriteTimestamp } = event.data;
751
- if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
752
- this.mercuryTimeOffset = Date.now() - wsWriteTimestamp;
753
560
  }
561
+ catch (reason) {
562
+ this.logger.error(`${MOBIUS_SOCKET_NAMESPACE}: error occurred processing socket message`, reason);
563
+ }
564
+ return Promise.resolve();
754
565
  }
755
- _reconnect(webSocketUrl, sessionId = this.defaultSessionId) {
756
- this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: reconnecting ${sessionId}`);
757
- return this.connect(webSocketUrl || this.socketUrl, sessionId);
566
+ reconnect(webSocketUrl) {
567
+ this.logger.info(`${MOBIUS_SOCKET_NAMESPACE}: reconnecting`);
568
+ return this.connect(webSocketUrl || this.socketUrl);
758
569
  }
759
570
  }
760
571
  export default MobiusSocket;