@webex/internal-plugin-mercury 3.9.0-next.5 → 3.9.0-next.7
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/dist/mercury.js +319 -134
- package/dist/mercury.js.map +1 -1
- package/package.json +5 -5
- package/src/mercury.js +285 -71
- package/test/unit/spec/mercury.js +622 -1
- package/test/unit/spec/socket.js +6 -6
package/dist/mercury.js
CHANGED
|
@@ -11,11 +11,11 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
11
11
|
value: true
|
|
12
12
|
});
|
|
13
13
|
exports.default = void 0;
|
|
14
|
+
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
|
|
14
15
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
15
16
|
var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
|
|
16
17
|
var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
|
|
17
18
|
var _deleteProperty = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/reflect/delete-property"));
|
|
18
|
-
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
|
|
19
19
|
var _getOwnPropertyDescriptor = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor"));
|
|
20
20
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
21
21
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
|
|
@@ -102,6 +102,87 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
},
|
|
105
|
+
/**
|
|
106
|
+
* Attach event listeners to a socket.
|
|
107
|
+
* @param {Socket} socket - The socket to attach listeners to
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
_attachSocketEventListeners: function _attachSocketEventListeners(socket) {
|
|
111
|
+
var _this2 = this;
|
|
112
|
+
socket.on('close', function (event) {
|
|
113
|
+
return _this2._onclose(event, socket);
|
|
114
|
+
});
|
|
115
|
+
socket.on('message', function () {
|
|
116
|
+
return _this2._onmessage.apply(_this2, arguments);
|
|
117
|
+
});
|
|
118
|
+
socket.on('pong', function () {
|
|
119
|
+
return _this2._setTimeOffset.apply(_this2, arguments);
|
|
120
|
+
});
|
|
121
|
+
socket.on('sequence-mismatch', function () {
|
|
122
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
123
|
+
args[_key] = arguments[_key];
|
|
124
|
+
}
|
|
125
|
+
return _this2._emit.apply(_this2, ['sequence-mismatch'].concat(args));
|
|
126
|
+
});
|
|
127
|
+
socket.on('ping-pong-latency', function () {
|
|
128
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
129
|
+
args[_key2] = arguments[_key2];
|
|
130
|
+
}
|
|
131
|
+
return _this2._emit.apply(_this2, ['ping-pong-latency'].concat(args));
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Handle imminent shutdown by establishing a new connection while keeping
|
|
136
|
+
* the current one alive (make-before-break).
|
|
137
|
+
* Idempotent: will no-op if already in progress.
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*/
|
|
140
|
+
_handleImminentShutdown: function _handleImminentShutdown() {
|
|
141
|
+
var _this3 = this;
|
|
142
|
+
try {
|
|
143
|
+
if (this._shutdownSwitchoverInProgress) {
|
|
144
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] switchover already in progress"));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
this._shutdownSwitchoverInProgress = true;
|
|
148
|
+
this._shutdownSwitchoverId = "".concat((0, _now.default)());
|
|
149
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] switchover start, id=").concat(this._shutdownSwitchoverId));
|
|
150
|
+
this._connectWithBackoff(undefined, {
|
|
151
|
+
isShutdownSwitchover: true,
|
|
152
|
+
attemptOptions: {
|
|
153
|
+
isShutdownSwitchover: true,
|
|
154
|
+
onSuccess: function onSuccess(newSocket, webSocketUrl) {
|
|
155
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover connected, url: ").concat(webSocketUrl));
|
|
156
|
+
var oldSocket = _this3.socket;
|
|
157
|
+
// Atomically switch active socket reference
|
|
158
|
+
_this3.socket = newSocket;
|
|
159
|
+
_this3.connected = true; // remain connected throughout
|
|
160
|
+
|
|
161
|
+
_this3._emit('event:mercury_shutdown_switchover_complete', {
|
|
162
|
+
url: webSocketUrl
|
|
163
|
+
});
|
|
164
|
+
if (oldSocket) {
|
|
165
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] old socket retained; server will close with 4001"));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}).then(function () {
|
|
170
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover completed successfully"));
|
|
171
|
+
}).catch(function (err) {
|
|
172
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover exhausted retries; will fall back to normal reconnection"), err);
|
|
173
|
+
_this3._emit('event:mercury_shutdown_switchover_failed', {
|
|
174
|
+
reason: err
|
|
175
|
+
});
|
|
176
|
+
// Old socket will eventually close with 4001, triggering normal reconnection
|
|
177
|
+
});
|
|
178
|
+
} catch (e) {
|
|
179
|
+
this.logger.error("".concat(this.namespace, ": [shutdown] error during switchover"), e);
|
|
180
|
+
this._shutdownSwitchoverInProgress = false;
|
|
181
|
+
this._emit('event:mercury_shutdown_switchover_failed', {
|
|
182
|
+
reason: e
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
},
|
|
105
186
|
/**
|
|
106
187
|
* Get the last error.
|
|
107
188
|
* @returns {any} The last error.
|
|
@@ -110,7 +191,7 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
110
191
|
return this.lastError;
|
|
111
192
|
},
|
|
112
193
|
connect: function connect(webSocketUrl) {
|
|
113
|
-
var
|
|
194
|
+
var _this4 = this;
|
|
114
195
|
if (this.connected) {
|
|
115
196
|
this.logger.info("".concat(this.namespace, ": already connected, will not connect again"));
|
|
116
197
|
return _promise.default.resolve();
|
|
@@ -119,8 +200,8 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
119
200
|
this.logger.info("".concat(this.namespace, ": starting connection attempt"));
|
|
120
201
|
this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
|
|
121
202
|
return _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
|
|
122
|
-
|
|
123
|
-
return
|
|
203
|
+
_this4.logger.info("".concat(_this4.namespace, ": connecting"));
|
|
204
|
+
return _this4._connectWithBackoff(webSocketUrl);
|
|
124
205
|
});
|
|
125
206
|
},
|
|
126
207
|
logout: function logout() {
|
|
@@ -132,16 +213,20 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
132
213
|
} : undefined);
|
|
133
214
|
},
|
|
134
215
|
disconnect: function disconnect(options) {
|
|
135
|
-
var
|
|
216
|
+
var _this5 = this;
|
|
136
217
|
return new _promise.default(function (resolve) {
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
218
|
+
if (_this5.backoffCall) {
|
|
219
|
+
_this5.logger.info("".concat(_this5.namespace, ": aborting connection"));
|
|
220
|
+
_this5.backoffCall.abort();
|
|
140
221
|
}
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
222
|
+
if (_this5._shutdownSwitchoverBackoffCall) {
|
|
223
|
+
_this5.logger.info("".concat(_this5.namespace, ": aborting shutdown switchover"));
|
|
224
|
+
_this5._shutdownSwitchoverBackoffCall.abort();
|
|
225
|
+
}
|
|
226
|
+
if (_this5.socket) {
|
|
227
|
+
_this5.socket.removeAllListeners('message');
|
|
228
|
+
_this5.once('offline', resolve);
|
|
229
|
+
resolve(_this5.socket.close(options || undefined));
|
|
145
230
|
}
|
|
146
231
|
resolve();
|
|
147
232
|
});
|
|
@@ -167,19 +252,19 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
167
252
|
});
|
|
168
253
|
},
|
|
169
254
|
_prepareUrl: function _prepareUrl(webSocketUrl) {
|
|
170
|
-
var
|
|
255
|
+
var _this6 = this;
|
|
171
256
|
if (!webSocketUrl) {
|
|
172
257
|
webSocketUrl = this.webex.internal.device.webSocketUrl;
|
|
173
258
|
}
|
|
174
259
|
return this.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
175
260
|
if (haMessagingEnabled) {
|
|
176
|
-
return
|
|
261
|
+
return _this6.webex.internal.services.convertUrlToPriorityHostUrl(webSocketUrl);
|
|
177
262
|
}
|
|
178
263
|
return webSocketUrl;
|
|
179
264
|
}).then(function (wsUrl) {
|
|
180
265
|
webSocketUrl = wsUrl;
|
|
181
266
|
}).then(function () {
|
|
182
|
-
return
|
|
267
|
+
return _this6.webex.internal.feature.getFeature('developer', 'web-shared-mercury');
|
|
183
268
|
}).then(function (webSharedMercury) {
|
|
184
269
|
webSocketUrl = _url.default.parse(webSocketUrl, true);
|
|
185
270
|
(0, _assign.default)(webSocketUrl.query, {
|
|
@@ -194,7 +279,7 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
194
279
|
});
|
|
195
280
|
(0, _deleteProperty.default)(webSocketUrl.query, 'bufferStates');
|
|
196
281
|
}
|
|
197
|
-
if ((0, _lodash.get)(
|
|
282
|
+
if ((0, _lodash.get)(_this6, 'webex.config.device.ephemeral', false)) {
|
|
198
283
|
webSocketUrl.query.multipleConnections = true;
|
|
199
284
|
}
|
|
200
285
|
webSocketUrl.query.clientTimestamp = (0, _now.default)();
|
|
@@ -202,96 +287,94 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
202
287
|
});
|
|
203
288
|
},
|
|
204
289
|
_attemptConnection: function _attemptConnection(socketUrl, callback) {
|
|
205
|
-
var
|
|
290
|
+
var _this7 = this;
|
|
291
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
292
|
+
var _options$isShutdownSw = options.isShutdownSwitchover,
|
|
293
|
+
isShutdownSwitchover = _options$isShutdownSw === void 0 ? false : _options$isShutdownSw,
|
|
294
|
+
_options$onSuccess = options.onSuccess,
|
|
295
|
+
onSuccess = _options$onSuccess === void 0 ? null : _options$onSuccess;
|
|
206
296
|
var socket = new _socket.default();
|
|
207
|
-
var
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
attemptWSUrl = webSocketUrl;
|
|
239
|
-
var options = {
|
|
240
|
-
forceCloseDelay: _this5.config.forceCloseDelay,
|
|
241
|
-
pingInterval: _this5.config.pingInterval,
|
|
242
|
-
pongTimeout: _this5.config.pongTimeout,
|
|
243
|
-
token: token.toString(),
|
|
244
|
-
trackingId: "".concat(_this5.webex.sessionId, "_").concat((0, _now.default)()),
|
|
245
|
-
logger: _this5.logger
|
|
246
|
-
};
|
|
297
|
+
var newWSUrl;
|
|
298
|
+
this._attachSocketEventListeners(socket);
|
|
299
|
+
|
|
300
|
+
// Check appropriate backoff call based on connection type
|
|
301
|
+
if (isShutdownSwitchover && !this._shutdownSwitchoverBackoffCall) {
|
|
302
|
+
var msg = "".concat(this.namespace, ": prevent socket open when switchover backoff call no longer defined");
|
|
303
|
+
var err = new Error(msg);
|
|
304
|
+
this.logger.info(msg);
|
|
305
|
+
|
|
306
|
+
// Call the callback with the error before rejecting
|
|
307
|
+
callback(err);
|
|
308
|
+
return _promise.default.reject(err);
|
|
309
|
+
}
|
|
310
|
+
if (!isShutdownSwitchover && !this.backoffCall) {
|
|
311
|
+
var _msg = "".concat(this.namespace, ": prevent socket open when backoffCall no longer defined");
|
|
312
|
+
var _err = new Error(_msg);
|
|
313
|
+
this.logger.info(_msg);
|
|
314
|
+
|
|
315
|
+
// Call the callback with the error before rejecting
|
|
316
|
+
callback(_err);
|
|
317
|
+
return _promise.default.reject(_err);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// For shutdown switchover, don't set socket yet (make-before-break)
|
|
321
|
+
// For normal connection, set socket before opening to allow disconnect() to close it
|
|
322
|
+
if (!isShutdownSwitchover) {
|
|
323
|
+
this.socket = socket;
|
|
324
|
+
}
|
|
325
|
+
return this._prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover).then(function (webSocketUrl) {
|
|
326
|
+
newWSUrl = webSocketUrl;
|
|
327
|
+
_this7.logger.info("".concat(_this7.namespace, ": ").concat(isShutdownSwitchover ? '[shutdown] switchover' : '', " connected to mercury, success, action: connected, url: ").concat(newWSUrl));
|
|
247
328
|
|
|
248
|
-
//
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
|
|
329
|
+
// Custom success handler for shutdown switchover
|
|
330
|
+
if (onSuccess) {
|
|
331
|
+
onSuccess(socket, webSocketUrl);
|
|
332
|
+
callback();
|
|
333
|
+
return _promise.default.resolve();
|
|
252
334
|
}
|
|
253
335
|
|
|
254
|
-
//
|
|
255
|
-
// the socket if it is in the process of being opened.
|
|
256
|
-
_this5.socket = socket;
|
|
257
|
-
_this5.logger.info("".concat(_this5.namespace, " connection url: ").concat(webSocketUrl));
|
|
258
|
-
return socket.open(webSocketUrl, options);
|
|
259
|
-
}).then(function () {
|
|
260
|
-
_this5.logger.info("".concat(_this5.namespace, ": connected to mercury, success, action: connected, url: ").concat(attemptWSUrl));
|
|
336
|
+
// Default behavior for normal connection
|
|
261
337
|
callback();
|
|
262
|
-
return
|
|
338
|
+
return _this7.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
263
339
|
if (haMessagingEnabled) {
|
|
264
|
-
return
|
|
340
|
+
return _this7.webex.internal.device.refresh();
|
|
265
341
|
}
|
|
266
342
|
return _promise.default.resolve();
|
|
267
343
|
});
|
|
268
344
|
}).catch(function (reason) {
|
|
269
|
-
var
|
|
270
|
-
|
|
345
|
+
var _this7$backoffCall, _this7$backoffCall3;
|
|
346
|
+
// For shutdown, simpler error handling - just callback for retry
|
|
347
|
+
if (isShutdownSwitchover) {
|
|
348
|
+
_this7.logger.info("".concat(_this7.namespace, ": [shutdown] switchover attempt failed"), reason);
|
|
349
|
+
return callback(reason);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Normal connection error handling (existing complex logic)
|
|
353
|
+
_this7.lastError = reason; // remember the last error
|
|
271
354
|
|
|
272
355
|
// Suppress connection errors that appear to be network related. This
|
|
273
356
|
// may end up suppressing metrics during outages, but we might not care
|
|
274
357
|
// (especially since many of our outages happen in a way that client
|
|
275
358
|
// metrics can't be trusted).
|
|
276
|
-
if (reason.code !== 1006 &&
|
|
277
|
-
var
|
|
278
|
-
|
|
279
|
-
retries: (
|
|
359
|
+
if (reason.code !== 1006 && _this7.backoffCall && ((_this7$backoffCall = _this7.backoffCall) === null || _this7$backoffCall === void 0 ? void 0 : _this7$backoffCall.getNumRetries()) > 0) {
|
|
360
|
+
var _this7$backoffCall2;
|
|
361
|
+
_this7._emit('connection_failed', reason, {
|
|
362
|
+
retries: (_this7$backoffCall2 = _this7.backoffCall) === null || _this7$backoffCall2 === void 0 ? void 0 : _this7$backoffCall2.getNumRetries()
|
|
280
363
|
});
|
|
281
364
|
}
|
|
282
|
-
|
|
365
|
+
_this7.logger.info("".concat(_this7.namespace, ": connection attempt failed"), reason, ((_this7$backoffCall3 = _this7.backoffCall) === null || _this7$backoffCall3 === void 0 ? void 0 : _this7$backoffCall3.getNumRetries()) === 0 ? reason.stack : '');
|
|
283
366
|
// UnknownResponse is produced by IE for any 4XXX; treated it like a bad
|
|
284
367
|
// web socket url and let WDM handle the token checking
|
|
285
368
|
if (reason instanceof _errors.UnknownResponse) {
|
|
286
|
-
|
|
287
|
-
return
|
|
369
|
+
_this7.logger.info("".concat(_this7.namespace, ": received unknown response code, refreshing device registration"));
|
|
370
|
+
return _this7.webex.internal.device.refresh().then(function () {
|
|
288
371
|
return callback(reason);
|
|
289
372
|
});
|
|
290
373
|
}
|
|
291
374
|
// NotAuthorized implies expired token
|
|
292
375
|
if (reason instanceof _errors.NotAuthorized) {
|
|
293
|
-
|
|
294
|
-
return
|
|
376
|
+
_this7.logger.info("".concat(_this7.namespace, ": received authorization error, reauthorizing"));
|
|
377
|
+
return _this7.webex.credentials.refresh({
|
|
295
378
|
force: true
|
|
296
379
|
}).then(function () {
|
|
297
380
|
return callback(reason);
|
|
@@ -306,15 +389,15 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
306
389
|
// BadRequest implies current credentials are for a Service Account
|
|
307
390
|
// Forbidden implies current user is not entitle for Webex
|
|
308
391
|
if (reason instanceof _errors.BadRequest || reason instanceof _errors.Forbidden) {
|
|
309
|
-
|
|
310
|
-
|
|
392
|
+
_this7.logger.warn("".concat(_this7.namespace, ": received unrecoverable response from mercury"));
|
|
393
|
+
_this7.backoffCall.abort();
|
|
311
394
|
return callback(reason);
|
|
312
395
|
}
|
|
313
396
|
if (reason instanceof _errors.ConnectionError) {
|
|
314
|
-
return
|
|
397
|
+
return _this7.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
315
398
|
if (haMessagingEnabled) {
|
|
316
|
-
|
|
317
|
-
return
|
|
399
|
+
_this7.logger.info("".concat(_this7.namespace, ": received a generic connection error, will try to connect to another datacenter. failed, action: 'failed', url: ").concat(newWSUrl, " error: ").concat(reason.message));
|
|
400
|
+
return _this7.webex.internal.services.markFailedUrl(newWSUrl);
|
|
318
401
|
}
|
|
319
402
|
return null;
|
|
320
403
|
}).then(function () {
|
|
@@ -323,63 +406,116 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
323
406
|
}
|
|
324
407
|
return callback(reason);
|
|
325
408
|
}).catch(function (reason) {
|
|
326
|
-
|
|
409
|
+
_this7.logger.error("".concat(_this7.namespace, ": failed to handle connection failure"), reason);
|
|
327
410
|
callback(reason);
|
|
328
411
|
});
|
|
329
412
|
},
|
|
413
|
+
_prepareAndOpenSocket: function _prepareAndOpenSocket(socket, socketUrl) {
|
|
414
|
+
var _this8 = this;
|
|
415
|
+
var isShutdownSwitchover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
416
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
417
|
+
return _promise.default.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
|
|
418
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
419
|
+
webSocketUrl = _ref2[0],
|
|
420
|
+
token = _ref2[1];
|
|
421
|
+
var options = {
|
|
422
|
+
forceCloseDelay: _this8.config.forceCloseDelay,
|
|
423
|
+
pingInterval: _this8.config.pingInterval,
|
|
424
|
+
pongTimeout: _this8.config.pongTimeout,
|
|
425
|
+
token: token.toString(),
|
|
426
|
+
trackingId: "".concat(_this8.webex.sessionId, "_").concat((0, _now.default)()),
|
|
427
|
+
logger: _this8.logger
|
|
428
|
+
};
|
|
429
|
+
if (_this8.webex.config.defaultMercuryOptions) {
|
|
430
|
+
var customOptionsMsg = isShutdownSwitchover ? 'setting custom options for switchover' : 'setting custom options';
|
|
431
|
+
_this8.logger.info("".concat(_this8.namespace, ": ").concat(customOptionsMsg));
|
|
432
|
+
options = _objectSpread(_objectSpread({}, options), _this8.webex.config.defaultMercuryOptions);
|
|
433
|
+
}
|
|
434
|
+
_this8.logger.info("".concat(_this8.namespace, ": ").concat(logPrefix, " url: ").concat(webSocketUrl));
|
|
435
|
+
return socket.open(webSocketUrl, options).then(function () {
|
|
436
|
+
return webSocketUrl;
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
},
|
|
330
440
|
_connectWithBackoff: function _connectWithBackoff(webSocketUrl) {
|
|
331
|
-
var
|
|
441
|
+
var _this9 = this;
|
|
442
|
+
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
443
|
+
var _context$isShutdownSw = context.isShutdownSwitchover,
|
|
444
|
+
isShutdownSwitchover = _context$isShutdownSw === void 0 ? false : _context$isShutdownSw,
|
|
445
|
+
_context$attemptOptio = context.attemptOptions,
|
|
446
|
+
attemptOptions = _context$attemptOptio === void 0 ? {} : _context$attemptOptio;
|
|
332
447
|
return new _promise.default(function (resolve, reject) {
|
|
333
448
|
// eslint gets confused about whether or not call is actually used
|
|
334
449
|
// eslint-disable-next-line prefer-const
|
|
335
450
|
var call;
|
|
336
451
|
var onComplete = function onComplete(err) {
|
|
337
|
-
|
|
338
|
-
|
|
452
|
+
// Clear state flags based on connection type
|
|
453
|
+
if (isShutdownSwitchover) {
|
|
454
|
+
_this9._shutdownSwitchoverInProgress = false;
|
|
455
|
+
_this9._shutdownSwitchoverBackoffCall = undefined;
|
|
456
|
+
} else {
|
|
457
|
+
_this9.connecting = false;
|
|
458
|
+
_this9.backoffCall = undefined;
|
|
459
|
+
}
|
|
339
460
|
if (err) {
|
|
340
|
-
|
|
461
|
+
var msg = isShutdownSwitchover ? "[shutdown] switchover failed after ".concat(call.getNumRetries(), " retries") : "failed to connect after ".concat(call.getNumRetries(), " retries");
|
|
462
|
+
_this9.logger.info("".concat(_this9.namespace, ": ").concat(msg, "; log statement about next retry was inaccurate; ").concat(err));
|
|
341
463
|
return reject(err);
|
|
342
464
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
465
|
+
|
|
466
|
+
// Default success handling for normal connections
|
|
467
|
+
if (!isShutdownSwitchover) {
|
|
468
|
+
_this9.connected = true;
|
|
469
|
+
_this9.hasEverConnected = true;
|
|
470
|
+
_this9._emit('online');
|
|
471
|
+
_this9.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
|
|
472
|
+
}
|
|
347
473
|
return resolve();
|
|
348
474
|
};
|
|
349
475
|
|
|
350
476
|
// eslint-disable-next-line prefer-reflect
|
|
351
477
|
call = _backoff.default.call(function (callback) {
|
|
352
|
-
|
|
353
|
-
|
|
478
|
+
var attemptNum = call.getNumRetries();
|
|
479
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
480
|
+
_this9.logger.info("".concat(_this9.namespace, ": executing ").concat(logPrefix, " attempt ").concat(attemptNum));
|
|
481
|
+
_this9._attemptConnection(webSocketUrl, callback, attemptOptions);
|
|
354
482
|
}, onComplete);
|
|
355
483
|
call.setStrategy(new _backoff.default.ExponentialStrategy({
|
|
356
|
-
initialDelay:
|
|
357
|
-
maxDelay:
|
|
484
|
+
initialDelay: _this9.config.backoffTimeReset,
|
|
485
|
+
maxDelay: _this9.config.backoffTimeMax
|
|
358
486
|
}));
|
|
359
|
-
if (
|
|
360
|
-
call.failAfter(
|
|
361
|
-
} else if (
|
|
362
|
-
call.failAfter(
|
|
487
|
+
if (_this9.config.initialConnectionMaxRetries && !_this9.hasEverConnected && !isShutdownSwitchover) {
|
|
488
|
+
call.failAfter(_this9.config.initialConnectionMaxRetries);
|
|
489
|
+
} else if (_this9.config.maxRetries) {
|
|
490
|
+
call.failAfter(_this9.config.maxRetries);
|
|
363
491
|
}
|
|
364
492
|
call.on('abort', function () {
|
|
365
|
-
|
|
366
|
-
|
|
493
|
+
var msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
|
|
494
|
+
_this9.logger.info("".concat(_this9.namespace, ": ").concat(msg, " aborted"));
|
|
495
|
+
reject(new Error("Mercury ".concat(msg, " Aborted")));
|
|
367
496
|
});
|
|
368
497
|
call.on('callback', function (err) {
|
|
369
498
|
if (err) {
|
|
370
499
|
var number = call.getNumRetries();
|
|
371
|
-
var delay = Math.min(call.strategy_.nextBackoffDelay_,
|
|
372
|
-
|
|
500
|
+
var delay = Math.min(call.strategy_.nextBackoffDelay_, _this9.config.backoffTimeMax);
|
|
501
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
|
|
502
|
+
_this9.logger.info("".concat(_this9.namespace, ": ").concat(logPrefix, " failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms"));
|
|
373
503
|
/* istanbul ignore if */
|
|
374
504
|
if (process.env.NODE_ENV === 'development') {
|
|
375
|
-
|
|
505
|
+
_this9.logger.debug("".concat(_this9.namespace, ": "), err, err.stack);
|
|
376
506
|
}
|
|
377
507
|
return;
|
|
378
508
|
}
|
|
379
|
-
|
|
509
|
+
_this9.logger.info("".concat(_this9.namespace, ": connected"));
|
|
380
510
|
});
|
|
511
|
+
|
|
512
|
+
// Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
|
|
513
|
+
if (isShutdownSwitchover) {
|
|
514
|
+
_this9._shutdownSwitchoverBackoffCall = call;
|
|
515
|
+
} else {
|
|
516
|
+
_this9.backoffCall = call;
|
|
517
|
+
}
|
|
381
518
|
call.start();
|
|
382
|
-
_this6.backoffCall = call;
|
|
383
519
|
});
|
|
384
520
|
},
|
|
385
521
|
_emit: function _emit() {
|
|
@@ -410,36 +546,74 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
410
546
|
}
|
|
411
547
|
return handlers;
|
|
412
548
|
},
|
|
413
|
-
_onclose: function _onclose(event) {
|
|
549
|
+
_onclose: function _onclose(event, sourceSocket) {
|
|
414
550
|
// I don't see any way to avoid the complexity or statement count in here.
|
|
415
551
|
/* eslint complexity: [0] */
|
|
416
552
|
|
|
417
553
|
try {
|
|
554
|
+
var isActiveSocket = sourceSocket === this.socket;
|
|
418
555
|
var reason = event.reason && event.reason.toLowerCase();
|
|
419
|
-
var socketUrl
|
|
420
|
-
this.socket
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
556
|
+
var socketUrl;
|
|
557
|
+
if (isActiveSocket && this.socket) {
|
|
558
|
+
// Active socket closed - get URL from current socket reference
|
|
559
|
+
socketUrl = this.socket.url;
|
|
560
|
+
} else if (sourceSocket) {
|
|
561
|
+
// Old socket closed - get URL from the closed socket
|
|
562
|
+
socketUrl = sourceSocket.url;
|
|
563
|
+
}
|
|
564
|
+
if (isActiveSocket) {
|
|
565
|
+
// Only tear down state if the currently active socket closed
|
|
566
|
+
if (this.socket) {
|
|
567
|
+
this.socket.removeAllListeners();
|
|
568
|
+
}
|
|
569
|
+
this.unset('socket');
|
|
570
|
+
this.connected = false;
|
|
571
|
+
this._emit('offline', event);
|
|
572
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
|
|
573
|
+
} else {
|
|
574
|
+
// Old socket closed; do not flip connection state
|
|
575
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] non-active socket closed, code=").concat(event.code));
|
|
576
|
+
// Clean up listeners from old socket now that it's closed
|
|
577
|
+
if (sourceSocket) {
|
|
578
|
+
sourceSocket.removeAllListeners();
|
|
579
|
+
}
|
|
580
|
+
}
|
|
425
581
|
switch (event.code) {
|
|
426
582
|
case 1003:
|
|
427
583
|
// metric: disconnect
|
|
428
584
|
this.logger.info("".concat(this.namespace, ": Mercury service rejected last message; will not reconnect: ").concat(event.reason));
|
|
429
|
-
this._emit('offline.permanent', event);
|
|
585
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
430
586
|
break;
|
|
431
587
|
case 4000:
|
|
432
588
|
// metric: disconnect
|
|
433
589
|
this.logger.info("".concat(this.namespace, ": socket replaced; will not reconnect"));
|
|
434
|
-
this._emit('offline.replaced', event);
|
|
590
|
+
if (isActiveSocket) this._emit('offline.replaced', event);
|
|
591
|
+
// If not active, nothing to do
|
|
592
|
+
break;
|
|
593
|
+
case 4001:
|
|
594
|
+
// replaced during shutdown
|
|
595
|
+
if (isActiveSocket) {
|
|
596
|
+
// Server closed active socket with 4001, meaning it expected this connection
|
|
597
|
+
// to be replaced, but the switchover in _handleImminentShutdown failed.
|
|
598
|
+
// This is a permanent failure - do not reconnect.
|
|
599
|
+
this.logger.warn("".concat(this.namespace, ": active socket closed with 4001; shutdown switchover failed"));
|
|
600
|
+
this._emit('offline.permanent', event);
|
|
601
|
+
} else {
|
|
602
|
+
// Expected: old socket closed after successful switchover
|
|
603
|
+
this.logger.info("".concat(this.namespace, ": old socket closed with 4001 (replaced during shutdown); no reconnect needed"));
|
|
604
|
+
this._emit('offline.replaced', event);
|
|
605
|
+
}
|
|
435
606
|
break;
|
|
436
607
|
case 1001:
|
|
437
608
|
case 1005:
|
|
438
609
|
case 1006:
|
|
439
610
|
case 1011:
|
|
440
611
|
this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
|
|
441
|
-
|
|
442
|
-
|
|
612
|
+
if (isActiveSocket) {
|
|
613
|
+
this._emit('offline.transient', event);
|
|
614
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting active socket to recover"));
|
|
615
|
+
this._reconnect(socketUrl);
|
|
616
|
+
}
|
|
443
617
|
// metric: disconnect
|
|
444
618
|
// if (code == 1011 && reason !== ping error) metric: unexpected disconnect
|
|
445
619
|
break;
|
|
@@ -448,31 +622,42 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
448
622
|
// 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
|
|
449
623
|
if (normalReconnectReasons.includes(reason)) {
|
|
450
624
|
this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
|
|
451
|
-
|
|
452
|
-
|
|
625
|
+
if (isActiveSocket) {
|
|
626
|
+
this._emit('offline.transient', event);
|
|
627
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting due to normal close"));
|
|
628
|
+
this._reconnect(socketUrl);
|
|
629
|
+
}
|
|
453
630
|
// metric: disconnect
|
|
454
631
|
// if (reason === done forced) metric: force closure
|
|
455
632
|
} else {
|
|
456
633
|
this.logger.info("".concat(this.namespace, ": socket disconnected; will not reconnect: ").concat(event.reason));
|
|
457
|
-
this._emit('offline.permanent', event);
|
|
634
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
458
635
|
}
|
|
459
636
|
break;
|
|
460
637
|
default:
|
|
461
638
|
this.logger.info("".concat(this.namespace, ": socket disconnected unexpectedly; will not reconnect"));
|
|
462
639
|
// unexpected disconnect
|
|
463
|
-
this._emit('offline.permanent', event);
|
|
640
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
464
641
|
}
|
|
465
642
|
} catch (error) {
|
|
466
643
|
this.logger.error("".concat(this.namespace, ": error occurred in close handler"), error);
|
|
467
644
|
}
|
|
468
645
|
},
|
|
469
646
|
_onmessage: function _onmessage(event) {
|
|
470
|
-
var
|
|
647
|
+
var _this10 = this;
|
|
471
648
|
this._setTimeOffset(event);
|
|
472
649
|
var envelope = event.data;
|
|
473
650
|
if (process.env.ENABLE_MERCURY_LOGGING) {
|
|
474
651
|
this.logger.debug("".concat(this.namespace, ": message envelope: "), envelope);
|
|
475
652
|
}
|
|
653
|
+
|
|
654
|
+
// Handle shutdown message shape: { type: 'shutdown' }
|
|
655
|
+
if (envelope && envelope.type === 'shutdown') {
|
|
656
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] imminent shutdown message received"));
|
|
657
|
+
this._emit('event:mercury_shutdown_imminent', envelope);
|
|
658
|
+
this._handleImminentShutdown();
|
|
659
|
+
return _promise.default.resolve();
|
|
660
|
+
}
|
|
476
661
|
var data = envelope.data;
|
|
477
662
|
this._applyOverrides(data);
|
|
478
663
|
return this._getEventHandlers(data.eventType).reduce(function (promise, handler) {
|
|
@@ -480,24 +665,24 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
480
665
|
var namespace = handler.namespace,
|
|
481
666
|
name = handler.name;
|
|
482
667
|
return new _promise.default(function (resolve) {
|
|
483
|
-
return resolve((
|
|
668
|
+
return resolve((_this10.webex[namespace] || _this10.webex.internal[namespace])[name](data));
|
|
484
669
|
}).catch(function (reason) {
|
|
485
|
-
return
|
|
670
|
+
return _this10.logger.error("".concat(_this10.namespace, ": error occurred in autowired event handler for ").concat(data.eventType), reason);
|
|
486
671
|
});
|
|
487
672
|
});
|
|
488
673
|
}, _promise.default.resolve()).then(function () {
|
|
489
|
-
|
|
674
|
+
_this10._emit('event', event.data);
|
|
490
675
|
var _data$eventType$split = data.eventType.split('.'),
|
|
491
676
|
_data$eventType$split2 = (0, _slicedToArray2.default)(_data$eventType$split, 1),
|
|
492
677
|
namespace = _data$eventType$split2[0];
|
|
493
678
|
if (namespace === data.eventType) {
|
|
494
|
-
|
|
679
|
+
_this10._emit("event:".concat(namespace), envelope);
|
|
495
680
|
} else {
|
|
496
|
-
|
|
497
|
-
|
|
681
|
+
_this10._emit("event:".concat(namespace), envelope);
|
|
682
|
+
_this10._emit("event:".concat(data.eventType), envelope);
|
|
498
683
|
}
|
|
499
684
|
}).catch(function (reason) {
|
|
500
|
-
|
|
685
|
+
_this10.logger.error("".concat(_this10.namespace, ": error occurred processing socket message"), reason);
|
|
501
686
|
});
|
|
502
687
|
},
|
|
503
688
|
_setTimeOffset: function _setTimeOffset(event) {
|
|
@@ -510,7 +695,7 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
510
695
|
this.logger.info("".concat(this.namespace, ": reconnecting"));
|
|
511
696
|
return this.connect(webSocketUrl);
|
|
512
697
|
},
|
|
513
|
-
version: "3.9.0-next.
|
|
698
|
+
version: "3.9.0-next.7"
|
|
514
699
|
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "connect", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "connect"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "disconnect", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "disconnect"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "listen", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "listen"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "stopListening", [_dec2], (0, _getOwnPropertyDescriptor.default)(_obj, "stopListening"), _obj)), _obj)));
|
|
515
700
|
var _default = exports.default = Mercury;
|
|
516
701
|
//# sourceMappingURL=mercury.js.map
|