@webex/internal-plugin-mercury 3.9.0-webinar5k.1 → 3.10.0-multi-llms.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/dist/mercury.js +571 -164
- package/dist/mercury.js.map +1 -1
- package/dist/socket/socket-base.js +15 -0
- package/dist/socket/socket-base.js.map +1 -1
- package/package.json +18 -18
- package/src/mercury.js +589 -137
- package/src/socket/socket-base.js +13 -0
- package/test/unit/spec/mercury-events.js +20 -2
- package/test/unit/spec/mercury.js +737 -23
- package/test/unit/spec/socket.js +6 -6
package/dist/mercury.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
|
|
4
|
+
var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
|
|
5
|
+
var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
|
|
6
|
+
var _Array$isArray = require("@babel/runtime-corejs2/core-js/array/is-array");
|
|
3
7
|
var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
|
|
4
8
|
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
|
|
5
9
|
var _Object$getOwnPropertyDescriptor2 = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
|
|
@@ -11,12 +15,14 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
11
15
|
value: true
|
|
12
16
|
});
|
|
13
17
|
exports.default = void 0;
|
|
18
|
+
var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
|
|
19
|
+
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
|
|
14
20
|
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
15
21
|
var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
|
|
16
22
|
var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
|
|
17
23
|
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
24
|
var _getOwnPropertyDescriptor = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor"));
|
|
25
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/toConsumableArray"));
|
|
20
26
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
21
27
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
|
|
22
28
|
var _applyDecoratedDescriptor2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/applyDecoratedDescriptor"));
|
|
@@ -34,10 +40,14 @@ var _dec, _dec2, _obj;
|
|
|
34
40
|
*/
|
|
35
41
|
function ownKeys(e, r) { var t = _Object$keys2(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor2(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
36
42
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor2(t, r)); }); } return e; }
|
|
43
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && o[_Symbol$iterator] || o["@@iterator"]; if (!it) { if (_Array$isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
44
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
45
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
37
46
|
var normalReconnectReasons = ['idle', 'done (forced)', 'pong not received', 'pong mismatch'];
|
|
38
47
|
var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mercury#listen(): Use Mercury#connect() instead'), _dec2 = (0, _common.deprecated)('Mercury#stopListening(): Use Mercury#disconnect() instead'), (_obj = {
|
|
39
48
|
namespace: 'Mercury',
|
|
40
49
|
lastError: undefined,
|
|
50
|
+
defaultSessionId: 'mercury-default-session',
|
|
41
51
|
session: {
|
|
42
52
|
connected: {
|
|
43
53
|
default: false,
|
|
@@ -51,7 +61,24 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
51
61
|
default: false,
|
|
52
62
|
type: 'boolean'
|
|
53
63
|
},
|
|
54
|
-
|
|
64
|
+
sockets: {
|
|
65
|
+
default: function _default() {
|
|
66
|
+
return new _map.default();
|
|
67
|
+
},
|
|
68
|
+
type: 'object'
|
|
69
|
+
},
|
|
70
|
+
backoffCalls: {
|
|
71
|
+
default: function _default() {
|
|
72
|
+
return new _map.default();
|
|
73
|
+
},
|
|
74
|
+
type: 'object'
|
|
75
|
+
},
|
|
76
|
+
_shutdownSwitchoverBackoffCalls: {
|
|
77
|
+
default: function _default() {
|
|
78
|
+
return new _map.default();
|
|
79
|
+
},
|
|
80
|
+
type: 'object'
|
|
81
|
+
},
|
|
55
82
|
localClusterServiceUrls: 'object',
|
|
56
83
|
mercuryTimeOffset: {
|
|
57
84
|
default: undefined,
|
|
@@ -79,6 +106,117 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
79
106
|
_this.webex.internal.feature.updateFeature(envelope.data.featureToggle);
|
|
80
107
|
}
|
|
81
108
|
});
|
|
109
|
+
/*
|
|
110
|
+
* When Cluster Migrations, notify clients using ActiveClusterStatusEvent via mercury
|
|
111
|
+
* https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-002.html#wip-notifying-clients-of-cluster-migrations
|
|
112
|
+
* */
|
|
113
|
+
this.on('event:ActiveClusterStatusEvent', function (envelope) {
|
|
114
|
+
var _this$webex$internal$;
|
|
115
|
+
if (typeof ((_this$webex$internal$ = _this.webex.internal.services) === null || _this$webex$internal$ === void 0 ? void 0 : _this$webex$internal$.switchActiveClusterIds) === 'function' && envelope && envelope.data) {
|
|
116
|
+
var _envelope$data;
|
|
117
|
+
_this.webex.internal.services.switchActiveClusterIds((_envelope$data = envelope.data) === null || _envelope$data === void 0 ? void 0 : _envelope$data.activeClusters);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
/*
|
|
121
|
+
* Using cache-invalidation via mercury to instead the method of polling via the new /timestamp endpoint from u2c
|
|
122
|
+
* https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-005.html#websocket-notifications
|
|
123
|
+
* */
|
|
124
|
+
this.on('event:u2c.cache-invalidation', function (envelope) {
|
|
125
|
+
var _this$webex$internal$2;
|
|
126
|
+
if (typeof ((_this$webex$internal$2 = _this.webex.internal.services) === null || _this$webex$internal$2 === void 0 ? void 0 : _this$webex$internal$2.invalidateCache) === 'function' && envelope && envelope.data) {
|
|
127
|
+
var _envelope$data2;
|
|
128
|
+
_this.webex.internal.services.invalidateCache((_envelope$data2 = envelope.data) === null || _envelope$data2 === void 0 ? void 0 : _envelope$data2.timestamp);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
/**
|
|
133
|
+
* Attach event listeners to a socket.
|
|
134
|
+
* @param {Socket} socket - The socket to attach listeners to
|
|
135
|
+
* @param {sessionId} sessionId - The socket related session ID
|
|
136
|
+
* @returns {void}
|
|
137
|
+
*/
|
|
138
|
+
_attachSocketEventListeners: function _attachSocketEventListeners(socket, sessionId) {
|
|
139
|
+
var _this2 = this;
|
|
140
|
+
socket.on('close', function (event) {
|
|
141
|
+
return _this2._onclose(sessionId, event, socket);
|
|
142
|
+
});
|
|
143
|
+
socket.on('message', function () {
|
|
144
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
145
|
+
args[_key] = arguments[_key];
|
|
146
|
+
}
|
|
147
|
+
return _this2._onmessage.apply(_this2, [sessionId].concat(args));
|
|
148
|
+
});
|
|
149
|
+
socket.on('pong', function () {
|
|
150
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
151
|
+
args[_key2] = arguments[_key2];
|
|
152
|
+
}
|
|
153
|
+
return _this2._setTimeOffset.apply(_this2, [sessionId].concat(args));
|
|
154
|
+
});
|
|
155
|
+
socket.on('sequence-mismatch', function () {
|
|
156
|
+
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
157
|
+
args[_key3] = arguments[_key3];
|
|
158
|
+
}
|
|
159
|
+
return _this2._emit.apply(_this2, [sessionId, 'sequence-mismatch'].concat(args));
|
|
160
|
+
});
|
|
161
|
+
socket.on('ping-pong-latency', function () {
|
|
162
|
+
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
|
|
163
|
+
args[_key4] = arguments[_key4];
|
|
164
|
+
}
|
|
165
|
+
return _this2._emit.apply(_this2, [sessionId, 'ping-pong-latency'].concat(args));
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Handle imminent shutdown by establishing a new connection while keeping
|
|
170
|
+
* the current one alive (make-before-break).
|
|
171
|
+
* Idempotent: will no-op if already in progress.
|
|
172
|
+
* @param {string} sessionId - The session ID for which the shutdown is imminent
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
_handleImminentShutdown: function _handleImminentShutdown(sessionId) {
|
|
176
|
+
var _this3 = this;
|
|
177
|
+
var oldSocket = this.sockets.get(sessionId);
|
|
178
|
+
try {
|
|
179
|
+
if (this._shutdownSwitchoverBackoffCalls.get(sessionId)) {
|
|
180
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] switchover already in progress for ").concat(sessionId));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
this._shutdownSwitchoverId = "".concat((0, _now.default)());
|
|
184
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] switchover start, id=").concat(this._shutdownSwitchoverId, " for ").concat(sessionId));
|
|
185
|
+
this._connectWithBackoff(undefined, sessionId, {
|
|
186
|
+
isShutdownSwitchover: true,
|
|
187
|
+
attemptOptions: {
|
|
188
|
+
isShutdownSwitchover: true,
|
|
189
|
+
onSuccess: function onSuccess(newSocket, webSocketUrl) {
|
|
190
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover connected, url: ").concat(webSocketUrl, " for ").concat(sessionId));
|
|
191
|
+
|
|
192
|
+
// Atomically switch active socket reference
|
|
193
|
+
_this3.socket = _this3.sockets.get(_this3.defaultSessionId) || newSocket;
|
|
194
|
+
_this3.connected = _this3.hasConnectedSockets(); // remain connected throughout
|
|
195
|
+
|
|
196
|
+
_this3._emit(sessionId, 'event:mercury_shutdown_switchover_complete', {
|
|
197
|
+
url: webSocketUrl
|
|
198
|
+
});
|
|
199
|
+
if (oldSocket) {
|
|
200
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] old socket retained; server will close with 4001"));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}).then(function () {
|
|
205
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover completed successfully for ").concat(sessionId));
|
|
206
|
+
}).catch(function (err) {
|
|
207
|
+
_this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover exhausted retries; will fall back to normal reconnection for ").concat(sessionId, ": "), err);
|
|
208
|
+
_this3._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
|
|
209
|
+
reason: err
|
|
210
|
+
});
|
|
211
|
+
// Old socket will eventually close with 4001, triggering normal reconnection
|
|
212
|
+
});
|
|
213
|
+
} catch (e) {
|
|
214
|
+
this.logger.error("".concat(this.namespace, ": [shutdown] error during switchover for ").concat(sessionId), e);
|
|
215
|
+
this._shutdownSwitchoverBackoffCalls.delete(sessionId);
|
|
216
|
+
this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
|
|
217
|
+
reason: e
|
|
218
|
+
});
|
|
219
|
+
}
|
|
82
220
|
},
|
|
83
221
|
/**
|
|
84
222
|
* Get the last error.
|
|
@@ -87,41 +225,164 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
87
225
|
getLastError: function getLastError() {
|
|
88
226
|
return this.lastError;
|
|
89
227
|
},
|
|
228
|
+
/**
|
|
229
|
+
* Get all active socket connections
|
|
230
|
+
* @returns {Map} Map of sessionId to socket instances
|
|
231
|
+
*/
|
|
232
|
+
getSockets: function getSockets() {
|
|
233
|
+
return this.sockets;
|
|
234
|
+
},
|
|
235
|
+
/**
|
|
236
|
+
* Get a specific socket by connection ID
|
|
237
|
+
* @param {string} sessionId - The connection identifier
|
|
238
|
+
* @returns {Socket|undefined} The socket instance or undefined if not found
|
|
239
|
+
*/
|
|
240
|
+
getSocket: function getSocket() {
|
|
241
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
|
|
242
|
+
return this.sockets.get(sessionId);
|
|
243
|
+
},
|
|
244
|
+
/**
|
|
245
|
+
* Check if any sockets are connected
|
|
246
|
+
* @returns {boolean} True if at least one socket is connected
|
|
247
|
+
*/
|
|
248
|
+
hasConnectedSockets: function hasConnectedSockets() {
|
|
249
|
+
var _iterator = _createForOfIteratorHelper(this.sockets.values()),
|
|
250
|
+
_step;
|
|
251
|
+
try {
|
|
252
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
253
|
+
var socket = _step.value;
|
|
254
|
+
if (socket && socket.connected) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch (err) {
|
|
259
|
+
_iterator.e(err);
|
|
260
|
+
} finally {
|
|
261
|
+
_iterator.f();
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* Check if any sockets are connecting
|
|
267
|
+
* @returns {boolean} True if at least one socket is connected
|
|
268
|
+
*/
|
|
269
|
+
hasConnectingSockets: function hasConnectingSockets() {
|
|
270
|
+
var _iterator2 = _createForOfIteratorHelper(this.sockets.values()),
|
|
271
|
+
_step2;
|
|
272
|
+
try {
|
|
273
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
274
|
+
var socket = _step2.value;
|
|
275
|
+
if (socket && socket.connecting) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (err) {
|
|
280
|
+
_iterator2.e(err);
|
|
281
|
+
} finally {
|
|
282
|
+
_iterator2.f();
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
},
|
|
286
|
+
// @oneFlight
|
|
90
287
|
connect: function connect(webSocketUrl) {
|
|
91
|
-
var
|
|
92
|
-
|
|
93
|
-
|
|
288
|
+
var _this4 = this;
|
|
289
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
|
|
290
|
+
if (!this._connectPromises) this._connectPromises = new _map.default();
|
|
291
|
+
|
|
292
|
+
// First check if there's already a connection promise for this session
|
|
293
|
+
if (this._connectPromises.has(sessionId)) {
|
|
294
|
+
this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already in progress, returning existing promise"));
|
|
295
|
+
return this._connectPromises.get(sessionId);
|
|
296
|
+
}
|
|
297
|
+
var sessionSocket = this.sockets.get(sessionId);
|
|
298
|
+
if (sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connected || sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connecting) {
|
|
299
|
+
this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already connected, will not connect again"));
|
|
94
300
|
return _promise.default.resolve();
|
|
95
301
|
}
|
|
96
302
|
this.connecting = true;
|
|
97
|
-
this.logger.info("".concat(this.namespace, ": starting connection attempt"));
|
|
303
|
+
this.logger.info("".concat(this.namespace, ": starting connection attempt for ").concat(sessionId));
|
|
98
304
|
this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return
|
|
305
|
+
var connectPromise = _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
|
|
306
|
+
_this4.logger.info("".concat(_this4.namespace, ": connecting ").concat(sessionId));
|
|
307
|
+
return _this4._connectWithBackoff(webSocketUrl, sessionId);
|
|
308
|
+
}).finally(function () {
|
|
309
|
+
_this4._connectPromises.delete(sessionId);
|
|
102
310
|
});
|
|
311
|
+
this._connectPromises.set(sessionId, connectPromise);
|
|
312
|
+
return connectPromise;
|
|
103
313
|
},
|
|
104
314
|
logout: function logout() {
|
|
105
315
|
this.logger.info("".concat(this.namespace, ": logout() called"));
|
|
106
316
|
this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
|
|
107
|
-
return this.
|
|
317
|
+
return this.disconnectAll(this.config.beforeLogoutOptionsCloseReason && !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason) ? {
|
|
108
318
|
code: 3050,
|
|
109
319
|
reason: this.config.beforeLogoutOptionsCloseReason
|
|
110
320
|
} : undefined);
|
|
111
321
|
},
|
|
322
|
+
// @oneFlight
|
|
112
323
|
disconnect: function disconnect(options) {
|
|
113
|
-
var
|
|
324
|
+
var _this5 = this;
|
|
325
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
|
|
114
326
|
return new _promise.default(function (resolve) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
327
|
+
var backoffCall = _this5.backoffCalls.get(sessionId);
|
|
328
|
+
if (backoffCall) {
|
|
329
|
+
_this5.logger.info("".concat(_this5.namespace, ": aborting connection ").concat(sessionId));
|
|
330
|
+
backoffCall.abort();
|
|
331
|
+
_this5.backoffCalls.delete(sessionId);
|
|
118
332
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
333
|
+
var shutdownSwitchoverBackoffCalls = _this5._shutdownSwitchoverBackoffCalls.get(sessionId);
|
|
334
|
+
if (shutdownSwitchoverBackoffCalls) {
|
|
335
|
+
_this5.logger.info("".concat(_this5.namespace, ": aborting shutdown switchover connection ").concat(sessionId));
|
|
336
|
+
shutdownSwitchoverBackoffCalls.abort();
|
|
337
|
+
_this5._shutdownSwitchoverBackoffCalls.delete(sessionId);
|
|
338
|
+
}
|
|
339
|
+
// Clean up any pending connection promises
|
|
340
|
+
if (_this5._connectPromises) {
|
|
341
|
+
_this5._connectPromises.delete(sessionId);
|
|
342
|
+
}
|
|
343
|
+
var sessionSocket = _this5.sockets.get(sessionId);
|
|
344
|
+
var suffix = sessionId === _this5.defaultSessionId ? '' : ":".concat(sessionId);
|
|
345
|
+
if (sessionSocket) {
|
|
346
|
+
sessionSocket.removeAllListeners('message');
|
|
347
|
+
sessionSocket.connecting = false;
|
|
348
|
+
sessionSocket.connected = false;
|
|
349
|
+
_this5.once(sessionId === _this5.defaultSessionId ? 'offline' : "offline".concat(suffix), resolve);
|
|
350
|
+
resolve(sessionSocket.close(options || undefined));
|
|
123
351
|
}
|
|
124
352
|
resolve();
|
|
353
|
+
|
|
354
|
+
// Update overall connected status
|
|
355
|
+
_this5.connected = _this5.hasConnectedSockets();
|
|
356
|
+
});
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* Disconnect all socket connections
|
|
360
|
+
* @param {object} options - Close options
|
|
361
|
+
* @returns {Promise} Promise that resolves when all connections are closed
|
|
362
|
+
*/
|
|
363
|
+
disconnectAll: function disconnectAll(options) {
|
|
364
|
+
var _this6 = this;
|
|
365
|
+
var disconnectPromises = [];
|
|
366
|
+
var _iterator3 = _createForOfIteratorHelper(this.sockets.keys()),
|
|
367
|
+
_step3;
|
|
368
|
+
try {
|
|
369
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
370
|
+
var sessionId = _step3.value;
|
|
371
|
+
disconnectPromises.push(this.disconnect(options, sessionId));
|
|
372
|
+
}
|
|
373
|
+
} catch (err) {
|
|
374
|
+
_iterator3.e(err);
|
|
375
|
+
} finally {
|
|
376
|
+
_iterator3.f();
|
|
377
|
+
}
|
|
378
|
+
return _promise.default.all(disconnectPromises).then(function () {
|
|
379
|
+
_this6.connected = false;
|
|
380
|
+
_this6.sockets.clear();
|
|
381
|
+
_this6.backoffCalls.clear();
|
|
382
|
+
// Clear connection promises to prevent stale promises
|
|
383
|
+
if (_this6._connectPromises) {
|
|
384
|
+
_this6._connectPromises.clear();
|
|
385
|
+
}
|
|
125
386
|
});
|
|
126
387
|
},
|
|
127
388
|
listen: function listen() {
|
|
@@ -145,19 +406,19 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
145
406
|
});
|
|
146
407
|
},
|
|
147
408
|
_prepareUrl: function _prepareUrl(webSocketUrl) {
|
|
148
|
-
var
|
|
409
|
+
var _this7 = this;
|
|
149
410
|
if (!webSocketUrl) {
|
|
150
411
|
webSocketUrl = this.webex.internal.device.webSocketUrl;
|
|
151
412
|
}
|
|
152
413
|
return this.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
153
414
|
if (haMessagingEnabled) {
|
|
154
|
-
return
|
|
415
|
+
return _this7.webex.internal.services.convertUrlToPriorityHostUrl(webSocketUrl);
|
|
155
416
|
}
|
|
156
417
|
return webSocketUrl;
|
|
157
418
|
}).then(function (wsUrl) {
|
|
158
419
|
webSocketUrl = wsUrl;
|
|
159
420
|
}).then(function () {
|
|
160
|
-
return
|
|
421
|
+
return _this7.webex.internal.feature.getFeature('developer', 'web-shared-mercury');
|
|
161
422
|
}).then(function (webSharedMercury) {
|
|
162
423
|
webSocketUrl = _url.default.parse(webSocketUrl, true);
|
|
163
424
|
(0, _assign.default)(webSocketUrl.query, {
|
|
@@ -172,104 +433,104 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
172
433
|
});
|
|
173
434
|
(0, _deleteProperty.default)(webSocketUrl.query, 'bufferStates');
|
|
174
435
|
}
|
|
175
|
-
if ((0, _lodash.get)(
|
|
436
|
+
if ((0, _lodash.get)(_this7, 'webex.config.device.ephemeral', false)) {
|
|
176
437
|
webSocketUrl.query.multipleConnections = true;
|
|
177
438
|
}
|
|
178
439
|
webSocketUrl.query.clientTimestamp = (0, _now.default)();
|
|
179
440
|
return _url.default.format(webSocketUrl);
|
|
180
441
|
});
|
|
181
442
|
},
|
|
182
|
-
_attemptConnection: function _attemptConnection(socketUrl, callback) {
|
|
183
|
-
var
|
|
443
|
+
_attemptConnection: function _attemptConnection(socketUrl, sessionId, callback) {
|
|
444
|
+
var _this8 = this;
|
|
445
|
+
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
446
|
+
var _options$isShutdownSw = options.isShutdownSwitchover,
|
|
447
|
+
isShutdownSwitchover = _options$isShutdownSw === void 0 ? false : _options$isShutdownSw,
|
|
448
|
+
_options$onSuccess = options.onSuccess,
|
|
449
|
+
onSuccess = _options$onSuccess === void 0 ? null : _options$onSuccess;
|
|
184
450
|
var socket = new _socket.default();
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
forceCloseDelay: _this5.config.forceCloseDelay,
|
|
219
|
-
pingInterval: _this5.config.pingInterval,
|
|
220
|
-
pongTimeout: _this5.config.pongTimeout,
|
|
221
|
-
token: token.toString(),
|
|
222
|
-
trackingId: "".concat(_this5.webex.sessionId, "_").concat((0, _now.default)()),
|
|
223
|
-
logger: _this5.logger
|
|
224
|
-
};
|
|
451
|
+
socket.connecting = true;
|
|
452
|
+
var newWSUrl;
|
|
453
|
+
this._attachSocketEventListeners(socket, sessionId);
|
|
454
|
+
var backoffCall = isShutdownSwitchover ? this._shutdownSwitchoverBackoffCalls.get(sessionId) : this.backoffCalls.get(sessionId);
|
|
455
|
+
|
|
456
|
+
// Check appropriate backoff call based on connection type
|
|
457
|
+
if (isShutdownSwitchover && !backoffCall) {
|
|
458
|
+
var msg = "".concat(this.namespace, ": prevent socket open when switchover backoff call no longer defined for ").concat(sessionId);
|
|
459
|
+
var err = new Error(msg);
|
|
460
|
+
this.logger.info(msg);
|
|
461
|
+
|
|
462
|
+
// Call the callback with the error before rejecting
|
|
463
|
+
callback(err);
|
|
464
|
+
return _promise.default.reject(err);
|
|
465
|
+
}
|
|
466
|
+
if (!isShutdownSwitchover && !backoffCall) {
|
|
467
|
+
var _msg = "".concat(this.namespace, ": prevent socket open when backoffCall no longer defined for ").concat(sessionId);
|
|
468
|
+
var _err = new Error(_msg);
|
|
469
|
+
this.logger.info(_msg);
|
|
470
|
+
|
|
471
|
+
// Call the callback with the error before rejecting
|
|
472
|
+
callback(_err);
|
|
473
|
+
return _promise.default.reject(_err);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// For shutdown switchover, don't set socket yet (make-before-break)
|
|
477
|
+
// For normal connection, set socket before opening to allow disconnect() to close it
|
|
478
|
+
if (!isShutdownSwitchover) {
|
|
479
|
+
this.sockets.set(sessionId, socket);
|
|
480
|
+
}
|
|
481
|
+
return this._prepareAndOpenSocket(socket, socketUrl, sessionId, isShutdownSwitchover).then(function (webSocketUrl) {
|
|
482
|
+
newWSUrl = webSocketUrl;
|
|
483
|
+
_this8.logger.info("".concat(_this8.namespace, ": ").concat(isShutdownSwitchover ? '[shutdown] switchover' : '', " connected to mercury, success, action: connected for ").concat(sessionId, ", url: ").concat(newWSUrl));
|
|
225
484
|
|
|
226
|
-
//
|
|
227
|
-
if (
|
|
228
|
-
|
|
229
|
-
|
|
485
|
+
// Custom success handler for shutdown switchover
|
|
486
|
+
if (onSuccess) {
|
|
487
|
+
onSuccess(socket, webSocketUrl);
|
|
488
|
+
callback();
|
|
489
|
+
return _promise.default.resolve();
|
|
230
490
|
}
|
|
231
491
|
|
|
232
|
-
//
|
|
233
|
-
// the socket if it is in the process of being opened.
|
|
234
|
-
_this5.socket = socket;
|
|
235
|
-
_this5.logger.info("".concat(_this5.namespace, " connection url: ").concat(webSocketUrl));
|
|
236
|
-
return socket.open(webSocketUrl, options);
|
|
237
|
-
}).then(function () {
|
|
238
|
-
_this5.logger.info("".concat(_this5.namespace, ": connected to mercury, success, action: connected, url: ").concat(attemptWSUrl));
|
|
492
|
+
// Default behavior for normal connection
|
|
239
493
|
callback();
|
|
240
|
-
return
|
|
494
|
+
return _this8.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
241
495
|
if (haMessagingEnabled) {
|
|
242
|
-
return
|
|
496
|
+
return _this8.webex.internal.device.refresh();
|
|
243
497
|
}
|
|
244
498
|
return _promise.default.resolve();
|
|
245
499
|
});
|
|
246
500
|
}).catch(function (reason) {
|
|
247
|
-
|
|
248
|
-
|
|
501
|
+
// For shutdown, simpler error handling - just callback for retry
|
|
502
|
+
if (isShutdownSwitchover) {
|
|
503
|
+
_this8.logger.info("".concat(_this8.namespace, ": [shutdown] switchover attempt failed for ").concat(sessionId), reason);
|
|
504
|
+
return callback(reason);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Normal connection error handling (existing complex logic)
|
|
508
|
+
_this8.lastError = reason; // remember the last error
|
|
249
509
|
|
|
510
|
+
var backoffCall = _this8.backoffCalls.get(sessionId);
|
|
250
511
|
// Suppress connection errors that appear to be network related. This
|
|
251
512
|
// may end up suppressing metrics during outages, but we might not care
|
|
252
513
|
// (especially since many of our outages happen in a way that client
|
|
253
514
|
// metrics can't be trusted).
|
|
254
|
-
if (reason.code !== 1006 &&
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
retries:
|
|
515
|
+
if (reason.code !== 1006 && backoffCall && (backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()) > 0) {
|
|
516
|
+
_this8._emit(sessionId, 'connection_failed', reason, {
|
|
517
|
+
sessionId: sessionId,
|
|
518
|
+
retries: backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()
|
|
258
519
|
});
|
|
259
520
|
}
|
|
260
|
-
|
|
521
|
+
_this8.logger.info("".concat(_this8.namespace, ": connection attempt failed for ").concat(sessionId), reason, (backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()) === 0 ? reason.stack : '');
|
|
261
522
|
// UnknownResponse is produced by IE for any 4XXX; treated it like a bad
|
|
262
523
|
// web socket url and let WDM handle the token checking
|
|
263
524
|
if (reason instanceof _errors.UnknownResponse) {
|
|
264
|
-
|
|
265
|
-
return
|
|
525
|
+
_this8.logger.info("".concat(_this8.namespace, ": received unknown response code for ").concat(sessionId, ", refreshing device registration"));
|
|
526
|
+
return _this8.webex.internal.device.refresh().then(function () {
|
|
266
527
|
return callback(reason);
|
|
267
528
|
});
|
|
268
529
|
}
|
|
269
530
|
// NotAuthorized implies expired token
|
|
270
531
|
if (reason instanceof _errors.NotAuthorized) {
|
|
271
|
-
|
|
272
|
-
return
|
|
532
|
+
_this8.logger.info("".concat(_this8.namespace, ": received authorization error for ").concat(sessionId, ", reauthorizing"));
|
|
533
|
+
return _this8.webex.credentials.refresh({
|
|
273
534
|
force: true
|
|
274
535
|
}).then(function () {
|
|
275
536
|
return callback(reason);
|
|
@@ -284,15 +545,15 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
284
545
|
// BadRequest implies current credentials are for a Service Account
|
|
285
546
|
// Forbidden implies current user is not entitle for Webex
|
|
286
547
|
if (reason instanceof _errors.BadRequest || reason instanceof _errors.Forbidden) {
|
|
287
|
-
|
|
288
|
-
|
|
548
|
+
_this8.logger.warn("".concat(_this8.namespace, ": received unrecoverable response from mercury for ").concat(sessionId));
|
|
549
|
+
backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.abort();
|
|
289
550
|
return callback(reason);
|
|
290
551
|
}
|
|
291
552
|
if (reason instanceof _errors.ConnectionError) {
|
|
292
|
-
return
|
|
553
|
+
return _this8.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
|
|
293
554
|
if (haMessagingEnabled) {
|
|
294
|
-
|
|
295
|
-
return
|
|
555
|
+
_this8.logger.info("".concat(_this8.namespace, ": received a generic connection error for ").concat(sessionId, ", will try to connect to another datacenter. failed, action: 'failed', url: ").concat(newWSUrl, " error: ").concat(reason.message));
|
|
556
|
+
return _this8.webex.internal.services.markFailedUrl(newWSUrl);
|
|
296
557
|
}
|
|
297
558
|
return null;
|
|
298
559
|
}).then(function () {
|
|
@@ -301,73 +562,164 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
301
562
|
}
|
|
302
563
|
return callback(reason);
|
|
303
564
|
}).catch(function (reason) {
|
|
304
|
-
|
|
565
|
+
_this8.logger.error("".concat(_this8.namespace, ": failed to handle connection failure for ").concat(sessionId), reason);
|
|
305
566
|
callback(reason);
|
|
306
567
|
});
|
|
307
568
|
},
|
|
308
|
-
|
|
309
|
-
var
|
|
569
|
+
_prepareAndOpenSocket: function _prepareAndOpenSocket(socket, socketUrl, sessionId) {
|
|
570
|
+
var _this9 = this;
|
|
571
|
+
var isShutdownSwitchover = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
572
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
573
|
+
return _promise.default.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
|
|
574
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
575
|
+
webSocketUrl = _ref2[0],
|
|
576
|
+
token = _ref2[1];
|
|
577
|
+
var options = {
|
|
578
|
+
forceCloseDelay: _this9.config.forceCloseDelay,
|
|
579
|
+
pingInterval: _this9.config.pingInterval,
|
|
580
|
+
pongTimeout: _this9.config.pongTimeout,
|
|
581
|
+
token: token.toString(),
|
|
582
|
+
trackingId: "".concat(_this9.webex.sessionId, "_").concat((0, _now.default)()),
|
|
583
|
+
logger: _this9.logger
|
|
584
|
+
};
|
|
585
|
+
if (_this9.webex.config.defaultMercuryOptions) {
|
|
586
|
+
var customOptionsMsg = isShutdownSwitchover ? 'setting custom options for switchover' : 'setting custom options';
|
|
587
|
+
_this9.logger.info("".concat(_this9.namespace, ": ").concat(customOptionsMsg));
|
|
588
|
+
options = _objectSpread(_objectSpread({}, options), _this9.webex.config.defaultMercuryOptions);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Set the socket before opening it. This allows a disconnect() to close
|
|
592
|
+
// the socket if it is in the process of being opened.
|
|
593
|
+
_this9.sockets.set(sessionId, socket);
|
|
594
|
+
_this9.socket = _this9.sockets.get(_this9.defaultSessionId) || socket;
|
|
595
|
+
_this9.logger.info("".concat(_this9.namespace, " ").concat(logPrefix, " url for ").concat(sessionId, ": ").concat(webSocketUrl));
|
|
596
|
+
return socket.open(webSocketUrl, options).then(function () {
|
|
597
|
+
return webSocketUrl;
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
},
|
|
601
|
+
_connectWithBackoff: function _connectWithBackoff(webSocketUrl, sessionId) {
|
|
602
|
+
var _this10 = this;
|
|
603
|
+
var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
604
|
+
var _context$isShutdownSw = context.isShutdownSwitchover,
|
|
605
|
+
isShutdownSwitchover = _context$isShutdownSw === void 0 ? false : _context$isShutdownSw,
|
|
606
|
+
_context$attemptOptio = context.attemptOptions,
|
|
607
|
+
attemptOptions = _context$attemptOptio === void 0 ? {} : _context$attemptOptio;
|
|
310
608
|
return new _promise.default(function (resolve, reject) {
|
|
311
|
-
// eslint gets confused about whether
|
|
609
|
+
// eslint gets confused about whether call is actually used
|
|
312
610
|
// eslint-disable-next-line prefer-const
|
|
313
611
|
var call;
|
|
314
612
|
var onComplete = function onComplete(err) {
|
|
315
|
-
|
|
316
|
-
|
|
613
|
+
var sid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : sessionId;
|
|
614
|
+
if (isShutdownSwitchover) {
|
|
615
|
+
_this10._shutdownSwitchoverBackoffCalls.delete(sid);
|
|
616
|
+
} else {
|
|
617
|
+
_this10.backoffCalls.delete(sid);
|
|
618
|
+
}
|
|
317
619
|
if (err) {
|
|
318
|
-
|
|
620
|
+
var msg = isShutdownSwitchover ? "[shutdown] switchover failed after ".concat(call.getNumRetries(), " retries") : "failed to connect after ".concat(call.getNumRetries(), " retries");
|
|
621
|
+
_this10.logger.info("".concat(_this10.namespace, ": ").concat(msg, "; log statement about next retry was inaccurate; ").concat(err));
|
|
319
622
|
return reject(err);
|
|
320
623
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
624
|
+
// Update overall connected status
|
|
625
|
+
var sessionSocket = _this10.sockets.get(sid);
|
|
626
|
+
if (sessionSocket) {
|
|
627
|
+
sessionSocket.connecting = false;
|
|
628
|
+
sessionSocket.connected = true;
|
|
629
|
+
}
|
|
630
|
+
// Default success handling for normal connections
|
|
631
|
+
if (!isShutdownSwitchover) {
|
|
632
|
+
_this10.connecting = _this10.hasConnectingSockets();
|
|
633
|
+
_this10.connected = _this10.hasConnectedSockets();
|
|
634
|
+
_this10.hasEverConnected = true;
|
|
635
|
+
_this10._emit(sid, 'online', {
|
|
636
|
+
sessionId: sid
|
|
637
|
+
});
|
|
638
|
+
_this10.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
|
|
639
|
+
}
|
|
325
640
|
return resolve();
|
|
326
641
|
};
|
|
327
|
-
|
|
328
642
|
// eslint-disable-next-line prefer-reflect
|
|
329
643
|
call = _backoff.default.call(function (callback) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
644
|
+
var attemptNum = call.getNumRetries();
|
|
645
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
646
|
+
_this10.logger.info("".concat(_this10.namespace, ": executing ").concat(logPrefix, " attempt ").concat(attemptNum, " for ").concat(sessionId));
|
|
647
|
+
_this10._attemptConnection(webSocketUrl, sessionId, callback, attemptOptions);
|
|
648
|
+
}, function (err) {
|
|
649
|
+
return onComplete(err, sessionId);
|
|
650
|
+
});
|
|
333
651
|
call.setStrategy(new _backoff.default.ExponentialStrategy({
|
|
334
|
-
initialDelay:
|
|
335
|
-
maxDelay:
|
|
652
|
+
initialDelay: _this10.config.backoffTimeReset,
|
|
653
|
+
maxDelay: _this10.config.backoffTimeMax
|
|
336
654
|
}));
|
|
337
|
-
if (
|
|
338
|
-
call.failAfter(
|
|
339
|
-
} else if (
|
|
340
|
-
call.failAfter(
|
|
655
|
+
if (_this10.config.initialConnectionMaxRetries && !_this10.hasEverConnected && !isShutdownSwitchover) {
|
|
656
|
+
call.failAfter(_this10.config.initialConnectionMaxRetries);
|
|
657
|
+
} else if (_this10.config.maxRetries) {
|
|
658
|
+
call.failAfter(_this10.config.maxRetries);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Store the call BEFORE setting up event handlers to prevent race conditions
|
|
662
|
+
// Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
|
|
663
|
+
if (isShutdownSwitchover) {
|
|
664
|
+
_this10._shutdownSwitchoverBackoffCalls.set(sessionId, call);
|
|
665
|
+
} else {
|
|
666
|
+
_this10.backoffCalls.set(sessionId, call);
|
|
341
667
|
}
|
|
342
668
|
call.on('abort', function () {
|
|
343
|
-
|
|
344
|
-
|
|
669
|
+
var msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
|
|
670
|
+
_this10.logger.info("".concat(_this10.namespace, ": ").concat(msg, " aborted for ").concat(sessionId));
|
|
671
|
+
reject(new Error("Mercury ".concat(msg, " Aborted for ").concat(sessionId)));
|
|
345
672
|
});
|
|
346
673
|
call.on('callback', function (err) {
|
|
347
674
|
if (err) {
|
|
348
675
|
var number = call.getNumRetries();
|
|
349
|
-
var delay = Math.min(call.strategy_.nextBackoffDelay_,
|
|
350
|
-
|
|
676
|
+
var delay = Math.min(call.strategy_.nextBackoffDelay_, _this10.config.backoffTimeMax);
|
|
677
|
+
var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
|
|
678
|
+
_this10.logger.info("".concat(_this10.namespace, ": ").concat(logPrefix, " failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms for ").concat(sessionId));
|
|
351
679
|
/* istanbul ignore if */
|
|
352
680
|
if (process.env.NODE_ENV === 'development') {
|
|
353
|
-
|
|
681
|
+
_this10.logger.debug("".concat(_this10.namespace, ": "), err, err.stack);
|
|
354
682
|
}
|
|
355
683
|
return;
|
|
356
684
|
}
|
|
357
|
-
|
|
685
|
+
_this10.logger.info("".concat(_this10.namespace, ": connected ").concat(sessionId));
|
|
358
686
|
});
|
|
359
687
|
call.start();
|
|
360
|
-
_this6.backoffCall = call;
|
|
361
688
|
});
|
|
362
689
|
},
|
|
363
690
|
_emit: function _emit() {
|
|
364
|
-
for (var
|
|
365
|
-
args[
|
|
691
|
+
for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
|
|
692
|
+
args[_key5] = arguments[_key5];
|
|
366
693
|
}
|
|
367
694
|
try {
|
|
368
|
-
|
|
695
|
+
if (!args || args.length === 0) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// New signature: _emit(sessionId, eventName, ...rest)
|
|
700
|
+
// Backwards compatibility: if the first arg isn't a known sessionId (or defaultSessionId),
|
|
701
|
+
// treat the call as the old signature and forward directly to trigger(...)
|
|
702
|
+
var first = args[0],
|
|
703
|
+
second = args[1],
|
|
704
|
+
rest = args.slice(2);
|
|
705
|
+
if (typeof first === 'string' && (this.sockets.has(first) || first === this.defaultSessionId) && typeof second === 'string') {
|
|
706
|
+
var sessionId = first;
|
|
707
|
+
var eventName = second;
|
|
708
|
+
var suffix = sessionId === this.defaultSessionId ? '' : ":".concat(sessionId);
|
|
709
|
+
this.trigger.apply(this, ["".concat(eventName).concat(suffix)].concat((0, _toConsumableArray2.default)(rest)));
|
|
710
|
+
} else {
|
|
711
|
+
// Old usage: _emit(eventName, ...args)
|
|
712
|
+
this.trigger.apply(this, args);
|
|
713
|
+
}
|
|
369
714
|
} catch (error) {
|
|
370
|
-
|
|
715
|
+
// Safely handle errors without causing additional issues during cleanup
|
|
716
|
+
try {
|
|
717
|
+
this.logger.error("".concat(this.namespace, ": error occurred in event handler:"), error, ' with args: ', args);
|
|
718
|
+
} catch (logError) {
|
|
719
|
+
// If even logging fails, just ignore to prevent cascading errors during cleanup
|
|
720
|
+
// eslint-disable-next-line no-console
|
|
721
|
+
console.error('Mercury _emit error handling failed:', logError);
|
|
722
|
+
}
|
|
371
723
|
}
|
|
372
724
|
},
|
|
373
725
|
_getEventHandlers: function _getEventHandlers(eventType) {
|
|
@@ -388,36 +740,77 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
388
740
|
}
|
|
389
741
|
return handlers;
|
|
390
742
|
},
|
|
391
|
-
_onclose: function _onclose(event) {
|
|
743
|
+
_onclose: function _onclose(sessionId, event, sourceSocket) {
|
|
392
744
|
// I don't see any way to avoid the complexity or statement count in here.
|
|
393
745
|
/* eslint complexity: [0] */
|
|
394
746
|
|
|
395
747
|
try {
|
|
396
748
|
var reason = event.reason && event.reason.toLowerCase();
|
|
397
|
-
var
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
749
|
+
var sessionSocket = this.sockets.get(sessionId);
|
|
750
|
+
var socketUrl;
|
|
751
|
+
event.sessionId = sessionId;
|
|
752
|
+
var isActiveSocket = sourceSocket === sessionSocket;
|
|
753
|
+
if (sourceSocket) {
|
|
754
|
+
socketUrl = sourceSocket.url;
|
|
755
|
+
}
|
|
756
|
+
this.sockets.delete(sessionId);
|
|
757
|
+
if (isActiveSocket) {
|
|
758
|
+
// Only tear down state if the currently active socket closed
|
|
759
|
+
if (sessionSocket) {
|
|
760
|
+
sessionSocket.removeAllListeners();
|
|
761
|
+
sessionSocket = null;
|
|
762
|
+
this._emit(sessionId, 'offline', event);
|
|
763
|
+
}
|
|
764
|
+
// Update overall connected status
|
|
765
|
+
this.connecting = this.hasConnectingSockets();
|
|
766
|
+
this.connected = this.hasConnectedSockets();
|
|
767
|
+
if (!this.connected) {
|
|
768
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
|
|
769
|
+
}
|
|
770
|
+
} else {
|
|
771
|
+
// Old socket closed; do not flip connection state
|
|
772
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] non-active socket closed, code=").concat(event.code, " for ").concat(sessionId));
|
|
773
|
+
// Clean up listeners from old socket now that it's closed
|
|
774
|
+
if (sourceSocket) {
|
|
775
|
+
sourceSocket.removeAllListeners();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
403
778
|
switch (event.code) {
|
|
404
779
|
case 1003:
|
|
405
780
|
// metric: disconnect
|
|
406
|
-
this.logger.info("".concat(this.namespace, ": Mercury service rejected last message; will not reconnect: ").concat(event.reason));
|
|
407
|
-
this._emit('offline.permanent', event);
|
|
781
|
+
this.logger.info("".concat(this.namespace, ": Mercury service rejected last message for ").concat(sessionId, "; will not reconnect: ").concat(event.reason));
|
|
782
|
+
if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
|
|
408
783
|
break;
|
|
409
784
|
case 4000:
|
|
410
785
|
// metric: disconnect
|
|
411
|
-
this.logger.info("".concat(this.namespace, ": socket replaced; will not reconnect"));
|
|
412
|
-
this._emit('offline.replaced', event);
|
|
786
|
+
this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " replaced; will not reconnect"));
|
|
787
|
+
if (isActiveSocket) this._emit(sessionId, 'offline.replaced', event);
|
|
788
|
+
// If not active, nothing to do
|
|
789
|
+
break;
|
|
790
|
+
case 4001:
|
|
791
|
+
// replaced during shutdown
|
|
792
|
+
if (isActiveSocket) {
|
|
793
|
+
// Server closed active socket with 4001, meaning it expected this connection
|
|
794
|
+
// to be replaced, but the switchover in _handleImminentShutdown failed.
|
|
795
|
+
// This is a permanent failure - do not reconnect.
|
|
796
|
+
this.logger.warn("".concat(this.namespace, ": active socket closed with 4001; shutdown switchover failed for ").concat(sessionId));
|
|
797
|
+
this._emit(sessionId, 'offline.permanent', event);
|
|
798
|
+
} else {
|
|
799
|
+
// Expected: old socket closed after successful switchover
|
|
800
|
+
this.logger.info("".concat(this.namespace, ": old socket closed with 4001 (replaced during shutdown); no reconnect needed for ").concat(sessionId));
|
|
801
|
+
this._emit(sessionId, 'offline.replaced', event);
|
|
802
|
+
}
|
|
413
803
|
break;
|
|
414
804
|
case 1001:
|
|
415
805
|
case 1005:
|
|
416
806
|
case 1006:
|
|
417
807
|
case 1011:
|
|
418
|
-
this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
|
|
419
|
-
|
|
420
|
-
|
|
808
|
+
this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
|
|
809
|
+
if (isActiveSocket) {
|
|
810
|
+
this._emit(sessionId, 'offline.transient', event);
|
|
811
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting active socket to recover for ").concat(sessionId));
|
|
812
|
+
this._reconnect(socketUrl, sessionId);
|
|
813
|
+
}
|
|
421
814
|
// metric: disconnect
|
|
422
815
|
// if (code == 1011 && reason !== ping error) metric: unexpected disconnect
|
|
423
816
|
break;
|
|
@@ -425,32 +818,45 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
425
818
|
case 3050:
|
|
426
819
|
// 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
|
|
427
820
|
if (normalReconnectReasons.includes(reason)) {
|
|
428
|
-
this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
|
|
429
|
-
|
|
430
|
-
|
|
821
|
+
this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
|
|
822
|
+
if (isActiveSocket) {
|
|
823
|
+
this._emit(sessionId, 'offline.transient', event);
|
|
824
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting due to normal close for ").concat(sessionId));
|
|
825
|
+
this._reconnect(socketUrl, sessionId);
|
|
826
|
+
}
|
|
431
827
|
// metric: disconnect
|
|
432
828
|
// if (reason === done forced) metric: force closure
|
|
433
829
|
} else {
|
|
434
|
-
this.logger.info("".concat(this.namespace, ": socket disconnected; will not reconnect: ").concat(event.reason));
|
|
435
|
-
this._emit('offline.permanent', event);
|
|
830
|
+
this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; will not reconnect: ").concat(event.reason));
|
|
831
|
+
if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
|
|
436
832
|
}
|
|
437
833
|
break;
|
|
438
834
|
default:
|
|
439
|
-
this.logger.info("".concat(this.namespace, ": socket disconnected unexpectedly; will not reconnect"));
|
|
835
|
+
this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected unexpectedly; will not reconnect"));
|
|
440
836
|
// unexpected disconnect
|
|
441
|
-
this._emit('offline.permanent', event);
|
|
837
|
+
if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
|
|
442
838
|
}
|
|
443
839
|
} catch (error) {
|
|
444
|
-
this.logger.error("".concat(this.namespace, ": error occurred in close handler"), error);
|
|
840
|
+
this.logger.error("".concat(this.namespace, ": error occurred in close handler for ").concat(sessionId), error);
|
|
445
841
|
}
|
|
446
842
|
},
|
|
447
|
-
_onmessage: function _onmessage(event) {
|
|
448
|
-
var
|
|
449
|
-
this._setTimeOffset(event);
|
|
843
|
+
_onmessage: function _onmessage(sessionId, event) {
|
|
844
|
+
var _this11 = this;
|
|
845
|
+
this._setTimeOffset(sessionId, event);
|
|
450
846
|
var envelope = event.data;
|
|
451
847
|
if (process.env.ENABLE_MERCURY_LOGGING) {
|
|
452
|
-
this.logger.debug("".concat(this.namespace, ": message envelope: "), envelope);
|
|
848
|
+
this.logger.debug("".concat(this.namespace, ": message envelope from ").concat(sessionId, ": "), envelope);
|
|
849
|
+
}
|
|
850
|
+
envelope.sessionId = sessionId;
|
|
851
|
+
|
|
852
|
+
// Handle shutdown message shape: { type: 'shutdown' }
|
|
853
|
+
if (envelope && envelope.type === 'shutdown') {
|
|
854
|
+
this.logger.info("".concat(this.namespace, ": [shutdown] imminent shutdown message received for ").concat(sessionId));
|
|
855
|
+
this._emit(sessionId, 'event:mercury_shutdown_imminent', envelope);
|
|
856
|
+
this._handleImminentShutdown(sessionId);
|
|
857
|
+
return _promise.default.resolve();
|
|
453
858
|
}
|
|
859
|
+
envelope.sessionId = sessionId;
|
|
454
860
|
var data = envelope.data;
|
|
455
861
|
this._applyOverrides(data);
|
|
456
862
|
return this._getEventHandlers(data.eventType).reduce(function (promise, handler) {
|
|
@@ -458,37 +864,38 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
|
|
|
458
864
|
var namespace = handler.namespace,
|
|
459
865
|
name = handler.name;
|
|
460
866
|
return new _promise.default(function (resolve) {
|
|
461
|
-
return resolve((
|
|
867
|
+
return resolve((_this11.webex[namespace] || _this11.webex.internal[namespace])[name](data));
|
|
462
868
|
}).catch(function (reason) {
|
|
463
|
-
return
|
|
869
|
+
return _this11.logger.error("".concat(_this11.namespace, ": error occurred in autowired event handler for ").concat(data.eventType, " from ").concat(sessionId), reason);
|
|
464
870
|
});
|
|
465
871
|
});
|
|
466
872
|
}, _promise.default.resolve()).then(function () {
|
|
467
|
-
|
|
873
|
+
_this11._emit(sessionId, 'event', envelope);
|
|
468
874
|
var _data$eventType$split = data.eventType.split('.'),
|
|
469
875
|
_data$eventType$split2 = (0, _slicedToArray2.default)(_data$eventType$split, 1),
|
|
470
876
|
namespace = _data$eventType$split2[0];
|
|
471
877
|
if (namespace === data.eventType) {
|
|
472
|
-
|
|
878
|
+
_this11._emit(sessionId, "event:".concat(namespace), envelope);
|
|
473
879
|
} else {
|
|
474
|
-
|
|
475
|
-
|
|
880
|
+
_this11._emit(sessionId, "event:".concat(namespace), envelope);
|
|
881
|
+
_this11._emit(sessionId, "event:".concat(data.eventType), envelope);
|
|
476
882
|
}
|
|
477
883
|
}).catch(function (reason) {
|
|
478
|
-
|
|
884
|
+
_this11.logger.error("".concat(_this11.namespace, ": error occurred processing socket message from ").concat(sessionId), reason);
|
|
479
885
|
});
|
|
480
886
|
},
|
|
481
|
-
_setTimeOffset: function _setTimeOffset(event) {
|
|
887
|
+
_setTimeOffset: function _setTimeOffset(sessionId, event) {
|
|
482
888
|
var wsWriteTimestamp = event.data.wsWriteTimestamp;
|
|
483
889
|
if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
|
|
484
890
|
this.mercuryTimeOffset = (0, _now.default)() - wsWriteTimestamp;
|
|
485
891
|
}
|
|
486
892
|
},
|
|
487
893
|
_reconnect: function _reconnect(webSocketUrl) {
|
|
488
|
-
|
|
489
|
-
|
|
894
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
|
|
895
|
+
this.logger.info("".concat(this.namespace, ": reconnecting ").concat(sessionId));
|
|
896
|
+
return this.connect(webSocketUrl, sessionId);
|
|
490
897
|
},
|
|
491
|
-
version: "3.
|
|
492
|
-
}, ((0, _applyDecoratedDescriptor2.default)(_obj, "
|
|
493
|
-
var
|
|
898
|
+
version: "3.10.0-multi-llms.1"
|
|
899
|
+
}, ((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)));
|
|
900
|
+
var _default2 = exports.default = Mercury;
|
|
494
901
|
//# sourceMappingURL=mercury.js.map
|