@webex/internal-plugin-mercury 3.12.0-next.9 → 3.12.0-task-refactor.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -54
- package/dist/mercury.js +198 -395
- package/dist/mercury.js.map +1 -1
- package/dist/socket/socket-base.js +3 -36
- package/dist/socket/socket-base.js.map +1 -1
- package/package.json +17 -17
- package/src/mercury.js +171 -398
- package/src/socket/socket-base.js +3 -40
- package/test/unit/spec/mercury-events.js +2 -20
- package/test/unit/spec/mercury.js +139 -307
- package/test/unit/spec/socket.js +0 -61
- package/dist/socket/constants.js +0 -16
- package/dist/socket/constants.js.map +0 -1
- package/src/socket/constants.js +0 -6
package/src/mercury.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import url from 'url';
|
|
7
7
|
|
|
8
8
|
import {WebexPlugin} from '@webex/webex-core';
|
|
9
|
-
import {deprecated} from '@webex/common';
|
|
9
|
+
import {deprecated, oneFlight} from '@webex/common';
|
|
10
10
|
import {camelCase, get, set} from 'lodash';
|
|
11
11
|
import backoff from 'backoff';
|
|
12
12
|
|
|
@@ -25,7 +25,6 @@ const normalReconnectReasons = ['idle', 'done (forced)', 'pong not received', 'p
|
|
|
25
25
|
const Mercury = WebexPlugin.extend({
|
|
26
26
|
namespace: 'Mercury',
|
|
27
27
|
lastError: undefined,
|
|
28
|
-
defaultSessionId: 'mercury-default-session',
|
|
29
28
|
|
|
30
29
|
session: {
|
|
31
30
|
connected: {
|
|
@@ -40,18 +39,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
40
39
|
default: false,
|
|
41
40
|
type: 'boolean',
|
|
42
41
|
},
|
|
43
|
-
|
|
44
|
-
default: () => new Map(),
|
|
45
|
-
type: 'object',
|
|
46
|
-
},
|
|
47
|
-
backoffCalls: {
|
|
48
|
-
default: () => new Map(),
|
|
49
|
-
type: 'object',
|
|
50
|
-
},
|
|
51
|
-
_shutdownSwitchoverBackoffCalls: {
|
|
52
|
-
default: () => new Map(),
|
|
53
|
-
type: 'object',
|
|
54
|
-
},
|
|
42
|
+
socket: 'object',
|
|
55
43
|
localClusterServiceUrls: 'object',
|
|
56
44
|
mercuryTimeOffset: {
|
|
57
45
|
default: undefined,
|
|
@@ -111,63 +99,50 @@ const Mercury = WebexPlugin.extend({
|
|
|
111
99
|
/**
|
|
112
100
|
* Attach event listeners to a socket.
|
|
113
101
|
* @param {Socket} socket - The socket to attach listeners to
|
|
114
|
-
* @param {sessionId} sessionId - The socket related session ID
|
|
115
102
|
* @returns {void}
|
|
116
103
|
*/
|
|
117
|
-
_attachSocketEventListeners(socket
|
|
118
|
-
socket.on('close', (event) => this._onclose(
|
|
119
|
-
socket.on('message', (...args) => this._onmessage(
|
|
120
|
-
socket.on('pong', (...args) => this._setTimeOffset(
|
|
121
|
-
socket.on('sequence-mismatch', (...args) =>
|
|
122
|
-
|
|
123
|
-
);
|
|
124
|
-
socket.on('ping-pong-latency', (...args) =>
|
|
125
|
-
this._emit(sessionId, 'ping-pong-latency', ...args)
|
|
126
|
-
);
|
|
104
|
+
_attachSocketEventListeners(socket) {
|
|
105
|
+
socket.on('close', (event) => this._onclose(event, socket));
|
|
106
|
+
socket.on('message', (...args) => this._onmessage(...args));
|
|
107
|
+
socket.on('pong', (...args) => this._setTimeOffset(...args));
|
|
108
|
+
socket.on('sequence-mismatch', (...args) => this._emit('sequence-mismatch', ...args));
|
|
109
|
+
socket.on('ping-pong-latency', (...args) => this._emit('ping-pong-latency', ...args));
|
|
127
110
|
},
|
|
128
111
|
|
|
129
112
|
/**
|
|
130
113
|
* Handle imminent shutdown by establishing a new connection while keeping
|
|
131
114
|
* the current one alive (make-before-break).
|
|
132
115
|
* Idempotent: will no-op if already in progress.
|
|
133
|
-
* @param {string} sessionId - The session ID for which the shutdown is imminent
|
|
134
116
|
* @returns {void}
|
|
135
117
|
*/
|
|
136
|
-
_handleImminentShutdown(
|
|
137
|
-
const oldSocket = this.sockets.get(sessionId);
|
|
138
|
-
|
|
118
|
+
_handleImminentShutdown() {
|
|
139
119
|
try {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (this._shutdownSwitchoverBackoffCalls.get(sessionId)) {
|
|
143
|
-
this.logger.info(
|
|
144
|
-
`${this.namespace}: [shutdown] switchover already in progress for ${sessionId}`
|
|
145
|
-
);
|
|
120
|
+
if (this._shutdownSwitchoverInProgress) {
|
|
121
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover already in progress`);
|
|
146
122
|
|
|
147
123
|
return;
|
|
148
124
|
}
|
|
149
|
-
|
|
125
|
+
this._shutdownSwitchoverInProgress = true;
|
|
150
126
|
this._shutdownSwitchoverId = `${Date.now()}`;
|
|
151
127
|
this.logger.info(
|
|
152
|
-
`${this.namespace}: [shutdown] switchover start, id=${this._shutdownSwitchoverId}
|
|
128
|
+
`${this.namespace}: [shutdown] switchover start, id=${this._shutdownSwitchoverId}`
|
|
153
129
|
);
|
|
154
130
|
|
|
155
|
-
this._connectWithBackoff(undefined,
|
|
131
|
+
this._connectWithBackoff(undefined, {
|
|
156
132
|
isShutdownSwitchover: true,
|
|
157
133
|
attemptOptions: {
|
|
158
134
|
isShutdownSwitchover: true,
|
|
159
135
|
onSuccess: (newSocket, webSocketUrl) => {
|
|
160
136
|
this.logger.info(
|
|
161
|
-
`${this.namespace}: [shutdown] switchover connected, url: ${webSocketUrl}
|
|
137
|
+
`${this.namespace}: [shutdown] switchover connected, url: ${webSocketUrl}`
|
|
162
138
|
);
|
|
163
139
|
|
|
140
|
+
const oldSocket = this.socket;
|
|
164
141
|
// Atomically switch active socket reference
|
|
165
|
-
this.socket =
|
|
166
|
-
this.connected =
|
|
142
|
+
this.socket = newSocket;
|
|
143
|
+
this.connected = true; // remain connected throughout
|
|
167
144
|
|
|
168
|
-
this._emit(
|
|
169
|
-
url: webSocketUrl,
|
|
170
|
-
});
|
|
145
|
+
this._emit('event:mercury_shutdown_switchover_complete', {url: webSocketUrl});
|
|
171
146
|
|
|
172
147
|
if (oldSocket) {
|
|
173
148
|
this.logger.info(
|
|
@@ -178,25 +153,20 @@ const Mercury = WebexPlugin.extend({
|
|
|
178
153
|
},
|
|
179
154
|
})
|
|
180
155
|
.then(() => {
|
|
181
|
-
this.logger.info(
|
|
182
|
-
`${this.namespace}: [shutdown] switchover completed successfully for ${sessionId}`
|
|
183
|
-
);
|
|
156
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover completed successfully`);
|
|
184
157
|
})
|
|
185
158
|
.catch((err) => {
|
|
186
159
|
this.logger.info(
|
|
187
|
-
`${this.namespace}: [shutdown] switchover exhausted retries; will fall back to normal reconnection
|
|
160
|
+
`${this.namespace}: [shutdown] switchover exhausted retries; will fall back to normal reconnection`,
|
|
188
161
|
err
|
|
189
162
|
);
|
|
190
|
-
this._emit(
|
|
163
|
+
this._emit('event:mercury_shutdown_switchover_failed', {reason: err});
|
|
191
164
|
// Old socket will eventually close with 4001, triggering normal reconnection
|
|
192
165
|
});
|
|
193
166
|
} catch (e) {
|
|
194
|
-
this.logger.error(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
);
|
|
198
|
-
this._shutdownSwitchoverBackoffCalls.delete(sessionId);
|
|
199
|
-
this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {reason: e});
|
|
167
|
+
this.logger.error(`${this.namespace}: [shutdown] error during switchover`, e);
|
|
168
|
+
this._shutdownSwitchoverInProgress = false;
|
|
169
|
+
this._emit('event:mercury_shutdown_switchover_failed', {reason: e});
|
|
200
170
|
}
|
|
201
171
|
},
|
|
202
172
|
|
|
@@ -208,95 +178,29 @@ const Mercury = WebexPlugin.extend({
|
|
|
208
178
|
return this.lastError;
|
|
209
179
|
},
|
|
210
180
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
getSockets() {
|
|
216
|
-
return this.sockets;
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Get a specific socket by connection ID
|
|
221
|
-
* @param {string} sessionId - The connection identifier
|
|
222
|
-
* @returns {Socket|undefined} The socket instance or undefined if not found
|
|
223
|
-
*/
|
|
224
|
-
getSocket(sessionId = this.defaultSessionId) {
|
|
225
|
-
return this.sockets.get(sessionId);
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Check if a socket is connected
|
|
230
|
-
* @param {string} [sessionId=this.defaultSessionId] - The session identifier
|
|
231
|
-
* @returns {boolean|undefined} True if the socket is connected
|
|
232
|
-
*/
|
|
233
|
-
hasConnectedSockets(sessionId = this.defaultSessionId) {
|
|
234
|
-
const socket = this.sockets.get(sessionId || this.defaultSessionId);
|
|
235
|
-
|
|
236
|
-
return socket?.connected;
|
|
237
|
-
},
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Check if any sockets are connecting
|
|
241
|
-
* @param {string} [sessionId=this.defaultSessionId] - The session identifier
|
|
242
|
-
* @returns {boolean|undefined} True if the socket is connecting
|
|
243
|
-
*/
|
|
244
|
-
hasConnectingSockets(sessionId = this.defaultSessionId) {
|
|
245
|
-
const socket = this.sockets.get(sessionId || this.defaultSessionId);
|
|
246
|
-
|
|
247
|
-
return socket?.connecting;
|
|
248
|
-
},
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Connect to Mercury for a specific session.
|
|
252
|
-
* @param {string} [webSocketUrl] - Optional websocket URL override. Falls back to the device websocket URL.
|
|
253
|
-
* @param {string} [sessionId=this.defaultSessionId] - The session identifier for this connection.
|
|
254
|
-
* @returns {Promise<void>} Resolves when connection flow completes for the session.
|
|
255
|
-
*/
|
|
256
|
-
connect(webSocketUrl, sessionId = this.defaultSessionId) {
|
|
257
|
-
if (!this._connectPromises) this._connectPromises = new Map();
|
|
258
|
-
|
|
259
|
-
// First check if there's already a connection promise for this session
|
|
260
|
-
if (this._connectPromises.has(sessionId)) {
|
|
261
|
-
this.logger.info(
|
|
262
|
-
`${this.namespace}: connection ${sessionId} already in progress, returning existing promise`
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
return this._connectPromises.get(sessionId);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const sessionSocket = this.sockets.get(sessionId);
|
|
269
|
-
if (sessionSocket?.connected || sessionSocket?.connecting) {
|
|
270
|
-
this.logger.info(
|
|
271
|
-
`${this.namespace}: connection ${sessionId} already connected, will not connect again`
|
|
272
|
-
);
|
|
181
|
+
@oneFlight
|
|
182
|
+
connect(webSocketUrl) {
|
|
183
|
+
if (this.connected) {
|
|
184
|
+
this.logger.info(`${this.namespace}: already connected, will not connect again`);
|
|
273
185
|
|
|
274
186
|
return Promise.resolve();
|
|
275
187
|
}
|
|
276
188
|
|
|
277
189
|
this.connecting = true;
|
|
278
190
|
|
|
279
|
-
this.logger.info(`${this.namespace}: starting connection attempt
|
|
191
|
+
this.logger.info(`${this.namespace}: starting connection attempt`);
|
|
280
192
|
this.logger.info(
|
|
281
193
|
`${this.namespace}: debug_mercury_logging stack: `,
|
|
282
194
|
new Error('debug_mercury_logging').stack
|
|
283
195
|
);
|
|
284
196
|
|
|
285
|
-
|
|
197
|
+
return Promise.resolve(
|
|
286
198
|
this.webex.internal.device.registered || this.webex.internal.device.register()
|
|
287
|
-
)
|
|
288
|
-
.
|
|
289
|
-
this.logger.info(`${this.namespace}: connecting ${sessionId}`);
|
|
199
|
+
).then(() => {
|
|
200
|
+
this.logger.info(`${this.namespace}: connecting`);
|
|
290
201
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
.finally(() => {
|
|
294
|
-
this._connectPromises.delete(sessionId);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
this._connectPromises.set(sessionId, connectPromise);
|
|
298
|
-
|
|
299
|
-
return connectPromise;
|
|
202
|
+
return this._connectWithBackoff(webSocketUrl);
|
|
203
|
+
});
|
|
300
204
|
},
|
|
301
205
|
|
|
302
206
|
logout() {
|
|
@@ -306,7 +210,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
306
210
|
new Error('debug_mercury_logging').stack
|
|
307
211
|
);
|
|
308
212
|
|
|
309
|
-
return this.
|
|
213
|
+
return this.disconnect(
|
|
310
214
|
this.config.beforeLogoutOptionsCloseReason &&
|
|
311
215
|
!normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason)
|
|
312
216
|
? {code: 3050, reason: this.config.beforeLogoutOptionsCloseReason}
|
|
@@ -314,74 +218,26 @@ const Mercury = WebexPlugin.extend({
|
|
|
314
218
|
);
|
|
315
219
|
},
|
|
316
220
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
* @param {object} [options] - Optional websocket close options (for example: `{code, reason}`).
|
|
320
|
-
* @param {string} [sessionId=this.defaultSessionId] - The session identifier to disconnect.
|
|
321
|
-
* @returns {Promise<void>} Resolves after disconnect cleanup and close handling are initiated/completed.
|
|
322
|
-
*/
|
|
323
|
-
disconnect(options, sessionId = this.defaultSessionId) {
|
|
324
|
-
this.logger.info(
|
|
325
|
-
`${this.namespace}#disconnect: connecting state: ${this.connecting}, connected state: ${
|
|
326
|
-
this.connected
|
|
327
|
-
}, socket exists: ${!!this.socket}, options: ${JSON.stringify(options)}`
|
|
328
|
-
);
|
|
329
|
-
|
|
221
|
+
@oneFlight
|
|
222
|
+
disconnect(options) {
|
|
330
223
|
return new Promise((resolve) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
this.
|
|
334
|
-
backoffCall.abort();
|
|
335
|
-
this.backoffCalls.delete(sessionId);
|
|
336
|
-
}
|
|
337
|
-
const shutdownSwitchoverBackoffCall = this._shutdownSwitchoverBackoffCalls.get(sessionId);
|
|
338
|
-
if (shutdownSwitchoverBackoffCall) {
|
|
339
|
-
this.logger.info(`${this.namespace}: aborting shutdown switchover connection ${sessionId}`);
|
|
340
|
-
shutdownSwitchoverBackoffCall.abort();
|
|
341
|
-
this._shutdownSwitchoverBackoffCalls.delete(sessionId);
|
|
342
|
-
}
|
|
343
|
-
// Clean up any pending connection promises
|
|
344
|
-
if (this._connectPromises) {
|
|
345
|
-
this._connectPromises.delete(sessionId);
|
|
224
|
+
if (this.backoffCall) {
|
|
225
|
+
this.logger.info(`${this.namespace}: aborting connection`);
|
|
226
|
+
this.backoffCall.abort();
|
|
346
227
|
}
|
|
347
228
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (sessionSocket) {
|
|
352
|
-
sessionSocket.removeAllListeners('message');
|
|
353
|
-
sessionSocket.connecting = false;
|
|
354
|
-
sessionSocket.connected = false;
|
|
355
|
-
this.once(sessionId === this.defaultSessionId ? 'offline' : `offline${suffix}`, resolve);
|
|
356
|
-
resolve(sessionSocket.close(options || undefined));
|
|
229
|
+
if (this._shutdownSwitchoverBackoffCall) {
|
|
230
|
+
this.logger.info(`${this.namespace}: aborting shutdown switchover`);
|
|
231
|
+
this._shutdownSwitchoverBackoffCall.abort();
|
|
357
232
|
}
|
|
358
|
-
resolve();
|
|
359
233
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Disconnect all socket connections
|
|
367
|
-
* @param {object} options - Close options
|
|
368
|
-
* @returns {Promise} Promise that resolves when all connections are closed
|
|
369
|
-
*/
|
|
370
|
-
disconnectAll(options) {
|
|
371
|
-
const disconnectPromises = [];
|
|
372
|
-
|
|
373
|
-
for (const sessionId of this.sockets.keys()) {
|
|
374
|
-
disconnectPromises.push(this.disconnect(options, sessionId));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return Promise.all(disconnectPromises).then(() => {
|
|
378
|
-
this.connected = false;
|
|
379
|
-
this.sockets.clear();
|
|
380
|
-
this.backoffCalls.clear();
|
|
381
|
-
// Clear connection promises to prevent stale promises
|
|
382
|
-
if (this._connectPromises) {
|
|
383
|
-
this._connectPromises.clear();
|
|
234
|
+
if (this.socket) {
|
|
235
|
+
this.socket.removeAllListeners('message');
|
|
236
|
+
this.once('offline', resolve);
|
|
237
|
+
resolve(this.socket.close(options || undefined));
|
|
384
238
|
}
|
|
239
|
+
|
|
240
|
+
resolve();
|
|
385
241
|
});
|
|
386
242
|
},
|
|
387
243
|
|
|
@@ -473,29 +329,34 @@ const Mercury = WebexPlugin.extend({
|
|
|
473
329
|
}
|
|
474
330
|
|
|
475
331
|
webSocketUrl.query.clientTimestamp = Date.now();
|
|
476
|
-
delete webSocketUrl.search;
|
|
477
332
|
|
|
478
333
|
return url.format(webSocketUrl);
|
|
479
334
|
});
|
|
480
335
|
},
|
|
481
336
|
|
|
482
|
-
_attemptConnection(socketUrl,
|
|
337
|
+
_attemptConnection(socketUrl, callback, options = {}) {
|
|
483
338
|
const {isShutdownSwitchover = false, onSuccess = null} = options;
|
|
484
339
|
|
|
485
340
|
const socket = new Socket();
|
|
486
|
-
socket.connecting = true;
|
|
487
341
|
let newWSUrl;
|
|
488
342
|
|
|
489
|
-
this._attachSocketEventListeners(socket
|
|
490
|
-
|
|
491
|
-
const backoffCall = isShutdownSwitchover
|
|
492
|
-
? this._shutdownSwitchoverBackoffCalls.get(sessionId)
|
|
493
|
-
: this.backoffCalls.get(sessionId);
|
|
343
|
+
this._attachSocketEventListeners(socket);
|
|
494
344
|
|
|
495
345
|
// Check appropriate backoff call based on connection type
|
|
496
|
-
if (!
|
|
497
|
-
const
|
|
498
|
-
const
|
|
346
|
+
if (isShutdownSwitchover && !this._shutdownSwitchoverBackoffCall) {
|
|
347
|
+
const msg = `${this.namespace}: prevent socket open when switchover backoff call no longer defined`;
|
|
348
|
+
const err = new Error(msg);
|
|
349
|
+
|
|
350
|
+
this.logger.info(msg);
|
|
351
|
+
|
|
352
|
+
// Call the callback with the error before rejecting
|
|
353
|
+
callback(err);
|
|
354
|
+
|
|
355
|
+
return Promise.reject(err);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!isShutdownSwitchover && !this.backoffCall) {
|
|
359
|
+
const msg = `${this.namespace}: prevent socket open when backoffCall no longer defined`;
|
|
499
360
|
const err = new Error(msg);
|
|
500
361
|
|
|
501
362
|
this.logger.info(msg);
|
|
@@ -509,17 +370,16 @@ const Mercury = WebexPlugin.extend({
|
|
|
509
370
|
// For shutdown switchover, don't set socket yet (make-before-break)
|
|
510
371
|
// For normal connection, set socket before opening to allow disconnect() to close it
|
|
511
372
|
if (!isShutdownSwitchover) {
|
|
512
|
-
this.
|
|
373
|
+
this.socket = socket;
|
|
513
374
|
}
|
|
514
375
|
|
|
515
|
-
return this._prepareAndOpenSocket(socket, socketUrl,
|
|
376
|
+
return this._prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover)
|
|
516
377
|
.then((webSocketUrl) => {
|
|
517
378
|
newWSUrl = webSocketUrl;
|
|
518
|
-
|
|
519
379
|
this.logger.info(
|
|
520
380
|
`${this.namespace}: ${
|
|
521
381
|
isShutdownSwitchover ? '[shutdown] switchover' : ''
|
|
522
|
-
} connected to mercury, success, action: connected
|
|
382
|
+
} connected to mercury, success, action: connected, url: ${newWSUrl}`
|
|
523
383
|
);
|
|
524
384
|
|
|
525
385
|
// Custom success handler for shutdown switchover
|
|
@@ -546,10 +406,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
546
406
|
.catch((reason) => {
|
|
547
407
|
// For shutdown, simpler error handling - just callback for retry
|
|
548
408
|
if (isShutdownSwitchover) {
|
|
549
|
-
this.logger.info(
|
|
550
|
-
`${this.namespace}: [shutdown] switchover attempt failed for ${sessionId}`,
|
|
551
|
-
reason
|
|
552
|
-
);
|
|
409
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover attempt failed`, reason);
|
|
553
410
|
|
|
554
411
|
return callback(reason);
|
|
555
412
|
}
|
|
@@ -557,36 +414,30 @@ const Mercury = WebexPlugin.extend({
|
|
|
557
414
|
// Normal connection error handling (existing complex logic)
|
|
558
415
|
this.lastError = reason; // remember the last error
|
|
559
416
|
|
|
560
|
-
const backoffCallNormal = this.backoffCalls.get(sessionId);
|
|
561
417
|
// Suppress connection errors that appear to be network related. This
|
|
562
418
|
// may end up suppressing metrics during outages, but we might not care
|
|
563
419
|
// (especially since many of our outages happen in a way that client
|
|
564
420
|
// metrics can't be trusted).
|
|
565
|
-
if (reason.code !== 1006 &&
|
|
566
|
-
this._emit(
|
|
567
|
-
sessionId,
|
|
568
|
-
retries: backoffCallNormal?.getNumRetries(),
|
|
569
|
-
});
|
|
421
|
+
if (reason.code !== 1006 && this.backoffCall && this.backoffCall?.getNumRetries() > 0) {
|
|
422
|
+
this._emit('connection_failed', reason, {retries: this.backoffCall?.getNumRetries()});
|
|
570
423
|
}
|
|
571
424
|
this.logger.info(
|
|
572
|
-
`${this.namespace}: connection attempt failed
|
|
425
|
+
`${this.namespace}: connection attempt failed`,
|
|
573
426
|
reason,
|
|
574
|
-
|
|
427
|
+
this.backoffCall?.getNumRetries() === 0 ? reason.stack : ''
|
|
575
428
|
);
|
|
576
429
|
// UnknownResponse is produced by IE for any 4XXX; treated it like a bad
|
|
577
430
|
// web socket url and let WDM handle the token checking
|
|
578
431
|
if (reason instanceof UnknownResponse) {
|
|
579
432
|
this.logger.info(
|
|
580
|
-
`${this.namespace}: received unknown response code
|
|
433
|
+
`${this.namespace}: received unknown response code, refreshing device registration`
|
|
581
434
|
);
|
|
582
435
|
|
|
583
436
|
return this.webex.internal.device.refresh().then(() => callback(reason));
|
|
584
437
|
}
|
|
585
438
|
// NotAuthorized implies expired token
|
|
586
439
|
if (reason instanceof NotAuthorized) {
|
|
587
|
-
this.logger.info(
|
|
588
|
-
`${this.namespace}: received authorization error for ${sessionId}, reauthorizing`
|
|
589
|
-
);
|
|
440
|
+
this.logger.info(`${this.namespace}: received authorization error, reauthorizing`);
|
|
590
441
|
|
|
591
442
|
return this.webex.credentials.refresh({force: true}).then(() => callback(reason));
|
|
592
443
|
}
|
|
@@ -599,10 +450,8 @@ const Mercury = WebexPlugin.extend({
|
|
|
599
450
|
// BadRequest implies current credentials are for a Service Account
|
|
600
451
|
// Forbidden implies current user is not entitle for Webex
|
|
601
452
|
if (reason instanceof BadRequest || reason instanceof Forbidden) {
|
|
602
|
-
this.logger.warn(
|
|
603
|
-
|
|
604
|
-
);
|
|
605
|
-
backoffCallNormal?.abort();
|
|
453
|
+
this.logger.warn(`${this.namespace}: received unrecoverable response from mercury`);
|
|
454
|
+
this.backoffCall.abort();
|
|
606
455
|
|
|
607
456
|
return callback(reason);
|
|
608
457
|
}
|
|
@@ -612,7 +461,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
612
461
|
.then((haMessagingEnabled) => {
|
|
613
462
|
if (haMessagingEnabled) {
|
|
614
463
|
this.logger.info(
|
|
615
|
-
`${this.namespace}: received a generic connection error
|
|
464
|
+
`${this.namespace}: received a generic connection error, will try to connect to another datacenter. failed, action: 'failed', url: ${newWSUrl} error: ${reason.message}`
|
|
616
465
|
);
|
|
617
466
|
|
|
618
467
|
return this.webex.internal.services.markFailedUrl(newWSUrl);
|
|
@@ -626,15 +475,12 @@ const Mercury = WebexPlugin.extend({
|
|
|
626
475
|
return callback(reason);
|
|
627
476
|
})
|
|
628
477
|
.catch((reason) => {
|
|
629
|
-
this.logger.error(
|
|
630
|
-
`${this.namespace}: failed to handle connection failure for ${sessionId}`,
|
|
631
|
-
reason
|
|
632
|
-
);
|
|
478
|
+
this.logger.error(`${this.namespace}: failed to handle connection failure`, reason);
|
|
633
479
|
callback(reason);
|
|
634
480
|
});
|
|
635
481
|
},
|
|
636
482
|
|
|
637
|
-
_prepareAndOpenSocket(socket, socketUrl,
|
|
483
|
+
_prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover = false) {
|
|
638
484
|
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
639
485
|
|
|
640
486
|
return Promise.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(
|
|
@@ -657,32 +503,30 @@ const Mercury = WebexPlugin.extend({
|
|
|
657
503
|
options = {...options, ...this.webex.config.defaultMercuryOptions};
|
|
658
504
|
}
|
|
659
505
|
|
|
660
|
-
|
|
661
|
-
// the socket if it is in the process of being opened.
|
|
662
|
-
this.sockets.set(sessionId, socket);
|
|
663
|
-
this.socket = this.sockets.get(this.defaultSessionId);
|
|
664
|
-
|
|
665
|
-
this.logger.info(`${this.namespace} ${logPrefix} url for ${sessionId}: ${webSocketUrl}`);
|
|
506
|
+
this.logger.info(`${this.namespace}: ${logPrefix} url: ${webSocketUrl}`);
|
|
666
507
|
|
|
667
508
|
return socket.open(webSocketUrl, options).then(() => webSocketUrl);
|
|
668
509
|
}
|
|
669
510
|
);
|
|
670
511
|
},
|
|
671
512
|
|
|
672
|
-
_connectWithBackoff(webSocketUrl,
|
|
513
|
+
_connectWithBackoff(webSocketUrl, context = {}) {
|
|
673
514
|
const {isShutdownSwitchover = false, attemptOptions = {}} = context;
|
|
674
515
|
|
|
675
516
|
return new Promise((resolve, reject) => {
|
|
676
|
-
// eslint gets confused about whether call is actually used
|
|
517
|
+
// eslint gets confused about whether or not call is actually used
|
|
677
518
|
// eslint-disable-next-line prefer-const
|
|
678
519
|
let call;
|
|
679
|
-
const onComplete = (err
|
|
520
|
+
const onComplete = (err) => {
|
|
521
|
+
// Clear state flags based on connection type
|
|
680
522
|
if (isShutdownSwitchover) {
|
|
681
|
-
this.
|
|
523
|
+
this._shutdownSwitchoverInProgress = false;
|
|
524
|
+
this._shutdownSwitchoverBackoffCall = undefined;
|
|
682
525
|
} else {
|
|
683
|
-
this.
|
|
526
|
+
this.connecting = false;
|
|
527
|
+
this.backoffCall = undefined;
|
|
684
528
|
}
|
|
685
|
-
|
|
529
|
+
|
|
686
530
|
if (err) {
|
|
687
531
|
const msg = isShutdownSwitchover
|
|
688
532
|
? `[shutdown] switchover failed after ${call.getNumRetries()} retries`
|
|
@@ -691,45 +535,29 @@ const Mercury = WebexPlugin.extend({
|
|
|
691
535
|
this.logger.info(
|
|
692
536
|
`${this.namespace}: ${msg}; log statement about next retry was inaccurate; ${err}`
|
|
693
537
|
);
|
|
694
|
-
if (sessionSocket) {
|
|
695
|
-
sessionSocket.connecting = false;
|
|
696
|
-
sessionSocket.connected = false;
|
|
697
|
-
}
|
|
698
538
|
|
|
699
539
|
return reject(err);
|
|
700
540
|
}
|
|
701
541
|
|
|
702
|
-
// Update overall connected status
|
|
703
|
-
if (sessionSocket) {
|
|
704
|
-
sessionSocket.connecting = false;
|
|
705
|
-
sessionSocket.connected = true;
|
|
706
|
-
}
|
|
707
542
|
// Default success handling for normal connections
|
|
708
543
|
if (!isShutdownSwitchover) {
|
|
709
|
-
this.
|
|
710
|
-
this.connected = this.hasConnectedSockets();
|
|
544
|
+
this.connected = true;
|
|
711
545
|
this.hasEverConnected = true;
|
|
712
|
-
this._emit(
|
|
713
|
-
|
|
714
|
-
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
|
|
715
|
-
}
|
|
546
|
+
this._emit('online');
|
|
547
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
|
|
716
548
|
}
|
|
717
549
|
|
|
718
550
|
return resolve();
|
|
719
551
|
};
|
|
552
|
+
|
|
720
553
|
// eslint-disable-next-line prefer-reflect
|
|
721
|
-
call = backoff.call(
|
|
722
|
-
(
|
|
723
|
-
|
|
724
|
-
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
554
|
+
call = backoff.call((callback) => {
|
|
555
|
+
const attemptNum = call.getNumRetries();
|
|
556
|
+
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
725
557
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
this._attemptConnection(webSocketUrl, sessionId, callback, attemptOptions);
|
|
730
|
-
},
|
|
731
|
-
(err) => onComplete(err, sessionId)
|
|
732
|
-
);
|
|
558
|
+
this.logger.info(`${this.namespace}: executing ${logPrefix} attempt ${attemptNum}`);
|
|
559
|
+
this._attemptConnection(webSocketUrl, callback, attemptOptions);
|
|
560
|
+
}, onComplete);
|
|
733
561
|
|
|
734
562
|
call.setStrategy(
|
|
735
563
|
new backoff.ExponentialStrategy({
|
|
@@ -748,32 +576,23 @@ const Mercury = WebexPlugin.extend({
|
|
|
748
576
|
call.failAfter(this.config.maxRetries);
|
|
749
577
|
}
|
|
750
578
|
|
|
751
|
-
// Store the call BEFORE setting up event handlers to prevent race conditions
|
|
752
|
-
// Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
|
|
753
|
-
if (isShutdownSwitchover) {
|
|
754
|
-
this._shutdownSwitchoverBackoffCalls.set(sessionId, call);
|
|
755
|
-
} else {
|
|
756
|
-
this.backoffCalls.set(sessionId, call);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
579
|
call.on('abort', () => {
|
|
760
580
|
const msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
|
|
761
581
|
|
|
762
|
-
this.logger.info(`${this.namespace}: ${msg} aborted
|
|
763
|
-
reject(new Error(`Mercury ${msg} Aborted
|
|
582
|
+
this.logger.info(`${this.namespace}: ${msg} aborted`);
|
|
583
|
+
reject(new Error(`Mercury ${msg} Aborted`));
|
|
764
584
|
});
|
|
765
585
|
|
|
766
586
|
call.on('callback', (err) => {
|
|
767
587
|
if (err) {
|
|
768
588
|
const number = call.getNumRetries();
|
|
769
589
|
const delay = Math.min(call.strategy_.nextBackoffDelay_, this.config.backoffTimeMax);
|
|
770
|
-
|
|
771
590
|
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
|
|
772
591
|
|
|
773
592
|
this.logger.info(
|
|
774
593
|
`${this.namespace}: ${logPrefix} failed to connect; attempting retry ${
|
|
775
594
|
number + 1
|
|
776
|
-
} in ${delay} ms
|
|
595
|
+
} in ${delay} ms`
|
|
777
596
|
);
|
|
778
597
|
/* istanbul ignore if */
|
|
779
598
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -782,55 +601,34 @@ const Mercury = WebexPlugin.extend({
|
|
|
782
601
|
|
|
783
602
|
return;
|
|
784
603
|
}
|
|
785
|
-
this.logger.info(`${this.namespace}: connected
|
|
604
|
+
this.logger.info(`${this.namespace}: connected`);
|
|
786
605
|
});
|
|
787
606
|
|
|
607
|
+
// Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
|
|
608
|
+
if (isShutdownSwitchover) {
|
|
609
|
+
this._shutdownSwitchoverBackoffCall = call;
|
|
610
|
+
} else {
|
|
611
|
+
this.backoffCall = call;
|
|
612
|
+
}
|
|
613
|
+
|
|
788
614
|
call.start();
|
|
789
615
|
});
|
|
790
616
|
},
|
|
791
617
|
|
|
792
618
|
_emit(...args) {
|
|
793
619
|
try {
|
|
794
|
-
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// New signature: _emit(sessionId, eventName, ...rest)
|
|
799
|
-
// Backwards compatibility: if the first arg isn't a known sessionId (or defaultSessionId),
|
|
800
|
-
// treat the call as the old signature and forward directly to trigger(...)
|
|
801
|
-
const [first, second, ...rest] = args;
|
|
802
|
-
|
|
803
|
-
if (typeof first === 'string' && typeof second === 'string') {
|
|
804
|
-
const sessionId = first;
|
|
805
|
-
const eventName = second;
|
|
806
|
-
const suffix = sessionId === this.defaultSessionId ? '' : `:${sessionId}`;
|
|
807
|
-
|
|
808
|
-
this.trigger(`${eventName}${suffix}`, ...rest);
|
|
809
|
-
} else {
|
|
810
|
-
// Old usage: _emit(eventName, ...args)
|
|
811
|
-
this.trigger(...args);
|
|
812
|
-
}
|
|
620
|
+
this.trigger(...args);
|
|
813
621
|
} catch (error) {
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
args
|
|
821
|
-
);
|
|
822
|
-
} catch (logError) {
|
|
823
|
-
// If even logging fails, just ignore to prevent cascading errors during cleanup
|
|
824
|
-
// eslint-disable-next-line no-console
|
|
825
|
-
console.error('Mercury _emit error handling failed:', logError);
|
|
826
|
-
}
|
|
622
|
+
this.logger.error(
|
|
623
|
+
`${this.namespace}: error occurred in event handler:`,
|
|
624
|
+
error,
|
|
625
|
+
' with args: ',
|
|
626
|
+
args
|
|
627
|
+
);
|
|
827
628
|
}
|
|
828
629
|
},
|
|
829
630
|
|
|
830
631
|
_getEventHandlers(eventType) {
|
|
831
|
-
if (!eventType) {
|
|
832
|
-
return [];
|
|
833
|
-
}
|
|
834
632
|
const [namespace, name] = eventType.split('.');
|
|
835
633
|
const handlers = [];
|
|
836
634
|
|
|
@@ -850,40 +648,36 @@ const Mercury = WebexPlugin.extend({
|
|
|
850
648
|
return handlers;
|
|
851
649
|
},
|
|
852
650
|
|
|
853
|
-
_onclose(
|
|
651
|
+
_onclose(event, sourceSocket) {
|
|
854
652
|
// I don't see any way to avoid the complexity or statement count in here.
|
|
855
653
|
/* eslint complexity: [0] */
|
|
856
654
|
|
|
857
655
|
try {
|
|
656
|
+
const isActiveSocket = sourceSocket === this.socket;
|
|
858
657
|
const reason = event.reason && event.reason.toLowerCase();
|
|
859
|
-
const sessionSocket = this.sockets.get(sessionId);
|
|
860
|
-
let socketUrl;
|
|
861
|
-
event.sessionId = sessionId;
|
|
862
658
|
|
|
863
|
-
|
|
864
|
-
if (
|
|
659
|
+
let socketUrl;
|
|
660
|
+
if (isActiveSocket && this.socket) {
|
|
661
|
+
// Active socket closed - get URL from current socket reference
|
|
662
|
+
socketUrl = this.socket.url;
|
|
663
|
+
} else if (sourceSocket) {
|
|
664
|
+
// Old socket closed - get URL from the closed socket
|
|
865
665
|
socketUrl = sourceSocket.url;
|
|
866
666
|
}
|
|
867
|
-
this.sockets.delete(sessionId);
|
|
868
667
|
|
|
869
668
|
if (isActiveSocket) {
|
|
870
669
|
// Only tear down state if the currently active socket closed
|
|
871
|
-
if (
|
|
872
|
-
|
|
873
|
-
if (sessionId === this.defaultSessionId) this.unset('socket');
|
|
874
|
-
this._emit(sessionId, 'offline', event);
|
|
875
|
-
}
|
|
876
|
-
// Update overall connected status
|
|
877
|
-
this.connecting = this.hasConnectingSockets();
|
|
878
|
-
this.connected = this.hasConnectedSockets();
|
|
879
|
-
|
|
880
|
-
if (!this.connected) {
|
|
881
|
-
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
|
|
670
|
+
if (this.socket) {
|
|
671
|
+
this.socket.removeAllListeners();
|
|
882
672
|
}
|
|
673
|
+
this.unset('socket');
|
|
674
|
+
this.connected = false;
|
|
675
|
+
this._emit('offline', event);
|
|
676
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
|
|
883
677
|
} else {
|
|
884
678
|
// Old socket closed; do not flip connection state
|
|
885
679
|
this.logger.info(
|
|
886
|
-
`${this.namespace}: [shutdown] non-active socket closed, code=${event.code}
|
|
680
|
+
`${this.namespace}: [shutdown] non-active socket closed, code=${event.code}`
|
|
887
681
|
);
|
|
888
682
|
// Clean up listeners from old socket now that it's closed
|
|
889
683
|
if (sourceSocket) {
|
|
@@ -895,14 +689,14 @@ const Mercury = WebexPlugin.extend({
|
|
|
895
689
|
case 1003:
|
|
896
690
|
// metric: disconnect
|
|
897
691
|
this.logger.info(
|
|
898
|
-
`${this.namespace}: Mercury service rejected last message
|
|
692
|
+
`${this.namespace}: Mercury service rejected last message; will not reconnect: ${event.reason}`
|
|
899
693
|
);
|
|
900
|
-
if (isActiveSocket) this._emit(
|
|
694
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
901
695
|
break;
|
|
902
696
|
case 4000:
|
|
903
697
|
// metric: disconnect
|
|
904
|
-
this.logger.info(`${this.namespace}: socket
|
|
905
|
-
if (isActiveSocket) this._emit(
|
|
698
|
+
this.logger.info(`${this.namespace}: socket replaced; will not reconnect`);
|
|
699
|
+
if (isActiveSocket) this._emit('offline.replaced', event);
|
|
906
700
|
// If not active, nothing to do
|
|
907
701
|
break;
|
|
908
702
|
case 4001:
|
|
@@ -912,28 +706,26 @@ const Mercury = WebexPlugin.extend({
|
|
|
912
706
|
// to be replaced, but the switchover in _handleImminentShutdown failed.
|
|
913
707
|
// This is a permanent failure - do not reconnect.
|
|
914
708
|
this.logger.warn(
|
|
915
|
-
`${this.namespace}: active socket closed with 4001; shutdown switchover failed
|
|
709
|
+
`${this.namespace}: active socket closed with 4001; shutdown switchover failed`
|
|
916
710
|
);
|
|
917
|
-
this._emit(
|
|
711
|
+
this._emit('offline.permanent', event);
|
|
918
712
|
} else {
|
|
919
713
|
// Expected: old socket closed after successful switchover
|
|
920
714
|
this.logger.info(
|
|
921
|
-
`${this.namespace}: old socket closed with 4001 (replaced during shutdown); no reconnect needed
|
|
715
|
+
`${this.namespace}: old socket closed with 4001 (replaced during shutdown); no reconnect needed`
|
|
922
716
|
);
|
|
923
|
-
this._emit(
|
|
717
|
+
this._emit('offline.replaced', event);
|
|
924
718
|
}
|
|
925
719
|
break;
|
|
926
720
|
case 1001:
|
|
927
721
|
case 1005:
|
|
928
722
|
case 1006:
|
|
929
723
|
case 1011:
|
|
930
|
-
this.logger.info(`${this.namespace}: socket
|
|
724
|
+
this.logger.info(`${this.namespace}: socket disconnected; reconnecting`);
|
|
931
725
|
if (isActiveSocket) {
|
|
932
|
-
this._emit(
|
|
933
|
-
this.logger.info(
|
|
934
|
-
|
|
935
|
-
);
|
|
936
|
-
this._reconnect(socketUrl, sessionId);
|
|
726
|
+
this._emit('offline.transient', event);
|
|
727
|
+
this.logger.info(`${this.namespace}: [shutdown] reconnecting active socket to recover`);
|
|
728
|
+
this._reconnect(socketUrl);
|
|
937
729
|
}
|
|
938
730
|
// metric: disconnect
|
|
939
731
|
// if (code == 1011 && reason !== ping error) metric: unexpected disconnect
|
|
@@ -941,71 +733,55 @@ const Mercury = WebexPlugin.extend({
|
|
|
941
733
|
case 1000:
|
|
942
734
|
case 3050: // 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
|
|
943
735
|
if (normalReconnectReasons.includes(reason)) {
|
|
944
|
-
this.logger.info(`${this.namespace}: socket
|
|
736
|
+
this.logger.info(`${this.namespace}: socket disconnected; reconnecting`);
|
|
945
737
|
if (isActiveSocket) {
|
|
946
|
-
this._emit(
|
|
947
|
-
this.logger.info(
|
|
948
|
-
|
|
949
|
-
);
|
|
950
|
-
this._reconnect(socketUrl, sessionId);
|
|
738
|
+
this._emit('offline.transient', event);
|
|
739
|
+
this.logger.info(`${this.namespace}: [shutdown] reconnecting due to normal close`);
|
|
740
|
+
this._reconnect(socketUrl);
|
|
951
741
|
}
|
|
952
742
|
// metric: disconnect
|
|
953
743
|
// if (reason === done forced) metric: force closure
|
|
954
744
|
} else {
|
|
955
745
|
this.logger.info(
|
|
956
|
-
`${this.namespace}: socket
|
|
746
|
+
`${this.namespace}: socket disconnected; will not reconnect: ${event.reason}`
|
|
957
747
|
);
|
|
958
|
-
if (isActiveSocket) this._emit(
|
|
748
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
959
749
|
}
|
|
960
750
|
break;
|
|
961
751
|
default:
|
|
962
752
|
this.logger.info(
|
|
963
|
-
`${this.namespace}: socket
|
|
753
|
+
`${this.namespace}: socket disconnected unexpectedly; will not reconnect`
|
|
964
754
|
);
|
|
965
755
|
// unexpected disconnect
|
|
966
|
-
if (isActiveSocket) this._emit(
|
|
756
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
967
757
|
}
|
|
968
758
|
} catch (error) {
|
|
969
|
-
this.logger.error(
|
|
970
|
-
`${this.namespace}: error occurred in close handler for ${sessionId}`,
|
|
971
|
-
error
|
|
972
|
-
);
|
|
759
|
+
this.logger.error(`${this.namespace}: error occurred in close handler`, error);
|
|
973
760
|
}
|
|
974
761
|
},
|
|
975
762
|
|
|
976
|
-
_onmessage(
|
|
977
|
-
this._setTimeOffset(
|
|
763
|
+
_onmessage(event) {
|
|
764
|
+
this._setTimeOffset(event);
|
|
978
765
|
const envelope = event.data;
|
|
979
766
|
|
|
980
767
|
if (process.env.ENABLE_MERCURY_LOGGING) {
|
|
981
|
-
this.logger.debug(`${this.namespace}: message envelope
|
|
768
|
+
this.logger.debug(`${this.namespace}: message envelope: `, envelope);
|
|
982
769
|
}
|
|
983
770
|
|
|
984
|
-
envelope.sessionId = sessionId;
|
|
985
|
-
|
|
986
771
|
// Handle shutdown message shape: { type: 'shutdown' }
|
|
987
772
|
if (envelope && envelope.type === 'shutdown') {
|
|
988
|
-
this.logger.info(
|
|
989
|
-
|
|
990
|
-
);
|
|
991
|
-
this._emit(sessionId, 'event:mercury_shutdown_imminent', envelope);
|
|
773
|
+
this.logger.info(`${this.namespace}: [shutdown] imminent shutdown message received`);
|
|
774
|
+
this._emit('event:mercury_shutdown_imminent', envelope);
|
|
992
775
|
|
|
993
|
-
this._handleImminentShutdown(
|
|
776
|
+
this._handleImminentShutdown();
|
|
994
777
|
|
|
995
778
|
return Promise.resolve();
|
|
996
779
|
}
|
|
997
780
|
|
|
998
|
-
envelope.sessionId = sessionId;
|
|
999
781
|
const {data} = envelope;
|
|
1000
782
|
|
|
1001
783
|
this._applyOverrides(data);
|
|
1002
784
|
|
|
1003
|
-
if (!data || !data.eventType) {
|
|
1004
|
-
this._emit(sessionId, 'event', envelope);
|
|
1005
|
-
|
|
1006
|
-
return Promise.resolve();
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
785
|
return this._getEventHandlers(data.eventType)
|
|
1010
786
|
.reduce(
|
|
1011
787
|
(promise, handler) =>
|
|
@@ -1016,7 +792,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
1016
792
|
resolve((this.webex[namespace] || this.webex.internal[namespace])[name](data))
|
|
1017
793
|
).catch((reason) =>
|
|
1018
794
|
this.logger.error(
|
|
1019
|
-
`${this.namespace}: error occurred in autowired event handler for ${data.eventType}
|
|
795
|
+
`${this.namespace}: error occurred in autowired event handler for ${data.eventType}`,
|
|
1020
796
|
reason
|
|
1021
797
|
)
|
|
1022
798
|
);
|
|
@@ -1024,35 +800,32 @@ const Mercury = WebexPlugin.extend({
|
|
|
1024
800
|
Promise.resolve()
|
|
1025
801
|
)
|
|
1026
802
|
.then(() => {
|
|
1027
|
-
this._emit(
|
|
803
|
+
this._emit('event', event.data);
|
|
1028
804
|
const [namespace] = data.eventType.split('.');
|
|
1029
805
|
|
|
1030
806
|
if (namespace === data.eventType) {
|
|
1031
|
-
this._emit(
|
|
807
|
+
this._emit(`event:${namespace}`, envelope);
|
|
1032
808
|
} else {
|
|
1033
|
-
this._emit(
|
|
1034
|
-
this._emit(
|
|
809
|
+
this._emit(`event:${namespace}`, envelope);
|
|
810
|
+
this._emit(`event:${data.eventType}`, envelope);
|
|
1035
811
|
}
|
|
1036
812
|
})
|
|
1037
813
|
.catch((reason) => {
|
|
1038
|
-
this.logger.error(
|
|
1039
|
-
`${this.namespace}: error occurred processing socket message from ${sessionId}`,
|
|
1040
|
-
reason
|
|
1041
|
-
);
|
|
814
|
+
this.logger.error(`${this.namespace}: error occurred processing socket message`, reason);
|
|
1042
815
|
});
|
|
1043
816
|
},
|
|
1044
817
|
|
|
1045
|
-
_setTimeOffset(
|
|
818
|
+
_setTimeOffset(event) {
|
|
1046
819
|
const {wsWriteTimestamp} = event.data;
|
|
1047
820
|
if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
|
|
1048
821
|
this.mercuryTimeOffset = Date.now() - wsWriteTimestamp;
|
|
1049
822
|
}
|
|
1050
823
|
},
|
|
1051
824
|
|
|
1052
|
-
_reconnect(webSocketUrl
|
|
1053
|
-
this.logger.info(`${this.namespace}: reconnecting
|
|
825
|
+
_reconnect(webSocketUrl) {
|
|
826
|
+
this.logger.info(`${this.namespace}: reconnecting`);
|
|
1054
827
|
|
|
1055
|
-
return this.connect(webSocketUrl
|
|
828
|
+
return this.connect(webSocketUrl);
|
|
1056
829
|
},
|
|
1057
830
|
});
|
|
1058
831
|
|