polfan-server-js-client 0.4.3 → 0.4.4
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/.idea/workspace.xml +22 -16
- package/README.md +20 -0
- package/build/index.cjs.js +172 -51
- package/build/index.cjs.js.map +1 -1
- package/build/index.umd.js +1 -1
- package/build/index.umd.js.map +1 -1
- package/build/types/WebSocketChatClient.d.ts +34 -2
- package/package.json +1 -1
- package/src/WebSocketChatClient.ts +157 -26
- package/tests/websocket-reconnect.test.ts +408 -0
package/.idea/workspace.xml
CHANGED
|
@@ -4,8 +4,14 @@
|
|
|
4
4
|
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
5
|
</component>
|
|
6
6
|
<component name="ChangeListManager">
|
|
7
|
-
<list default="true" id="831dae43-0da1-47fd-a5f7-33dd5eec2992" name="Changes" comment="Bump version
|
|
8
|
-
<change beforePath="$PROJECT_DIR$/
|
|
7
|
+
<list default="true" id="831dae43-0da1-47fd-a5f7-33dd5eec2992" name="Changes" comment="Bump version">
|
|
8
|
+
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
9
|
+
<change beforePath="$PROJECT_DIR$/build/index.cjs.js" beforeDir="false" afterPath="$PROJECT_DIR$/build/index.cjs.js" afterDir="false" />
|
|
10
|
+
<change beforePath="$PROJECT_DIR$/build/index.cjs.js.map" beforeDir="false" afterPath="$PROJECT_DIR$/build/index.cjs.js.map" afterDir="false" />
|
|
11
|
+
<change beforePath="$PROJECT_DIR$/build/index.umd.js" beforeDir="false" afterPath="$PROJECT_DIR$/build/index.umd.js" afterDir="false" />
|
|
12
|
+
<change beforePath="$PROJECT_DIR$/build/index.umd.js.map" beforeDir="false" afterPath="$PROJECT_DIR$/build/index.umd.js.map" afterDir="false" />
|
|
13
|
+
<change beforePath="$PROJECT_DIR$/build/types/WebSocketChatClient.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/build/types/WebSocketChatClient.d.ts" afterDir="false" />
|
|
14
|
+
<change beforePath="$PROJECT_DIR$/src/WebSocketChatClient.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/WebSocketChatClient.ts" afterDir="false" />
|
|
9
15
|
</list>
|
|
10
16
|
<option name="SHOW_DIALOG" value="false" />
|
|
11
17
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
@@ -33,7 +39,7 @@
|
|
|
33
39
|
<entry key="$PROJECT_DIR$/src/types" value="claude/chat-reactions-polls-system-hwea5i" />
|
|
34
40
|
</map>
|
|
35
41
|
</option>
|
|
36
|
-
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR
|
|
42
|
+
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
37
43
|
<option name="RESET_MODE" value="HARD" />
|
|
38
44
|
<option name="ROOT_SYNC" value="DONT_SYNC" />
|
|
39
45
|
</component>
|
|
@@ -85,7 +91,7 @@
|
|
|
85
91
|
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
86
92
|
"codeWithMe.voiceChat.enabledByDefault": "false",
|
|
87
93
|
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
|
|
88
|
-
"git-widget-placeholder": "
|
|
94
|
+
"git-widget-placeholder": "master",
|
|
89
95
|
"git.auto.fetch.suggestion.counter": "3",
|
|
90
96
|
"ignore.virus.scanning.warn.message": "true",
|
|
91
97
|
"junie.onboarding.icon.badge.shown": "true",
|
|
@@ -258,15 +264,7 @@
|
|
|
258
264
|
<workItem from="1787648458595" duration="3034000" />
|
|
259
265
|
<workItem from="1787994100244" duration="588000" />
|
|
260
266
|
<workItem from="1788873818076" duration="1523000" />
|
|
261
|
-
<workItem from="1788879390791" duration="
|
|
262
|
-
</task>
|
|
263
|
-
<task id="LOCAL-00068" summary="Improve reconnect on timeout">
|
|
264
|
-
<option name="closed" value="true" />
|
|
265
|
-
<created>1765145773196</created>
|
|
266
|
-
<option name="number" value="00068" />
|
|
267
|
-
<option name="presentableId" value="LOCAL-00068" />
|
|
268
|
-
<option name="project" value="LOCAL" />
|
|
269
|
-
<updated>1765145773196</updated>
|
|
267
|
+
<workItem from="1788879390791" duration="2740000" />
|
|
270
268
|
</task>
|
|
271
269
|
<task id="LOCAL-00069" summary="Bump version">
|
|
272
270
|
<option name="closed" value="true" />
|
|
@@ -652,7 +650,15 @@
|
|
|
652
650
|
<option name="project" value="LOCAL" />
|
|
653
651
|
<updated>1787649696666</updated>
|
|
654
652
|
</task>
|
|
655
|
-
<
|
|
653
|
+
<task id="LOCAL-00117" summary="Bump version">
|
|
654
|
+
<option name="closed" value="true" />
|
|
655
|
+
<created>1788952429127</created>
|
|
656
|
+
<option name="number" value="00117" />
|
|
657
|
+
<option name="presentableId" value="LOCAL-00117" />
|
|
658
|
+
<option name="project" value="LOCAL" />
|
|
659
|
+
<updated>1788952429128</updated>
|
|
660
|
+
</task>
|
|
661
|
+
<option name="localTasksCounter" value="118" />
|
|
656
662
|
<servers />
|
|
657
663
|
</component>
|
|
658
664
|
<component name="TypeScriptGeneratedFilesManager">
|
|
@@ -744,7 +750,6 @@
|
|
|
744
750
|
<MESSAGE value="Fixes in WebApiChatClient" />
|
|
745
751
|
<MESSAGE value="Fix resolve window status after jump to message" />
|
|
746
752
|
<MESSAGE value="Fix jumpTo when window is in LIVE state" />
|
|
747
|
-
<MESSAGE value="Bump version" />
|
|
748
753
|
<MESSAGE value="Unread topic counter in summary, bump version" />
|
|
749
754
|
<MESSAGE value="Unread room counter in summary, bump version" />
|
|
750
755
|
<MESSAGE value="Reconcile tracked state on reconnect" />
|
|
@@ -757,7 +762,8 @@
|
|
|
757
762
|
<MESSAGE value="Revert "User presence status support" This reverts commit b9ff2004" />
|
|
758
763
|
<MESSAGE value="Bump version This reverts commit b9ff2004" />
|
|
759
764
|
<MESSAGE value="Role flags and the MentionAllRoles permission" />
|
|
760
|
-
<
|
|
765
|
+
<MESSAGE value="Bump version" />
|
|
766
|
+
<option name="LAST_COMMIT_MESSAGE" value="Bump version" />
|
|
761
767
|
</component>
|
|
762
768
|
<component name="XSLT-Support.FileAssociations.UIState">
|
|
763
769
|
<expand />
|
package/README.md
CHANGED
|
@@ -24,6 +24,26 @@ TypeScript client library to handle connection with Devana (new Polfan) chat ser
|
|
|
24
24
|
})();
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Connection maintenance
|
|
28
|
+
|
|
29
|
+
`WebSocketChatClient` keeps the connection alive: after any loss (error, connecting timeout, missing pong, closure with
|
|
30
|
+
a code other than 1000) it reconnects indefinitely, with an exponential backoff between attempts. The `disconnect` event
|
|
31
|
+
tells whether a retry follows. A pending `connect()` promise resolves once an attempt authenticates, and is rejected by
|
|
32
|
+
`disconnect()`, which also stops reconnecting. An invalid token (`Bye` with `AuthenticationException`) rejects `connect()`
|
|
33
|
+
with the `Bye` data, emits an `error` event and stops reconnecting as well.
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
const wsClient = new PServ.WebSocketChatClient({
|
|
37
|
+
token: 'your-access-token',
|
|
38
|
+
url: 'wss://pserv-websocket-address',
|
|
39
|
+
connectingTimeoutMs: 10000, // Per attempt (default)
|
|
40
|
+
reconnect: {
|
|
41
|
+
minDelayMs: 1000, // Delay before the first retry, doubled on every next one (default)
|
|
42
|
+
maxDelayMs: 30000, // Maximum delay between retries (default)
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
27
47
|
## State management
|
|
28
48
|
|
|
29
49
|
The library provides built-in state management for WebSocket client. To enable it, just pass `stateTracking`
|
package/build/index.cjs.js
CHANGED
|
@@ -5439,6 +5439,9 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5439
5439
|
WebSocketChatClient_defineProperty(_this, "pingMonitorInterval", void 0);
|
|
5440
5440
|
WebSocketChatClient_defineProperty(_this, "inFlightPingTimeout", void 0);
|
|
5441
5441
|
WebSocketChatClient_defineProperty(_this, "lastReceivedMessageAt", void 0);
|
|
5442
|
+
WebSocketChatClient_defineProperty(_this, "reconnectEnabled", false);
|
|
5443
|
+
WebSocketChatClient_defineProperty(_this, "reconnectTimeoutId", void 0);
|
|
5444
|
+
WebSocketChatClient_defineProperty(_this, "reconnectAttempts", 0);
|
|
5442
5445
|
_this.options = options;
|
|
5443
5446
|
if ((_this$options$stateTr = _this.options.stateTracking) !== null && _this$options$stateTr !== void 0 ? _this$options$stateTr : true) {
|
|
5444
5447
|
_this.state = new ChatStateTracker(_this);
|
|
@@ -5454,14 +5457,14 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5454
5457
|
key: "connect",
|
|
5455
5458
|
value: function () {
|
|
5456
5459
|
var _connect = WebSocketChatClient_asyncToGenerator(/*#__PURE__*/WebSocketChatClient_regenerator().m(function _callee() {
|
|
5457
|
-
var
|
|
5458
|
-
|
|
5459
|
-
_this$options$queryPa,
|
|
5460
|
-
_this$options$connect;
|
|
5461
|
-
var _this$connectPromise, params;
|
|
5460
|
+
var _this2 = this;
|
|
5461
|
+
var _this$connectPromise, connectPromise;
|
|
5462
5462
|
return WebSocketChatClient_regenerator().w(function (_context) {
|
|
5463
5463
|
while (1) switch (_context.n) {
|
|
5464
5464
|
case 0:
|
|
5465
|
+
this.reconnectEnabled = true;
|
|
5466
|
+
// A manual call does not wait for a scheduled retry.
|
|
5467
|
+
this.cancelScheduledReconnect();
|
|
5465
5468
|
if (!(this.isOpenWsState() || this.isConnectingWsState())) {
|
|
5466
5469
|
_context.n = 1;
|
|
5467
5470
|
break;
|
|
@@ -5471,26 +5474,23 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5471
5474
|
// Reuse the promise of an attempt that has not settled yet (an
|
|
5472
5475
|
// automatic reconnect), so the caller that started connecting is
|
|
5473
5476
|
// resolved by whichever attempt eventually authenticates.
|
|
5474
|
-
(
|
|
5475
|
-
|
|
5476
|
-
args
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
this.
|
|
5490
|
-
|
|
5491
|
-
}, (_this$options$connect = this.options.connectingTimeoutMs) !== null && _this$options$connect !== void 0 ? _this$options$connect : 10000);
|
|
5492
|
-
this.authenticated = false;
|
|
5493
|
-
return _context.a(2, this.connectPromise);
|
|
5477
|
+
if (!this.connectPromise) {
|
|
5478
|
+
this.connectPromise = new Promise(function () {
|
|
5479
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
5480
|
+
args[_key] = arguments[_key];
|
|
5481
|
+
}
|
|
5482
|
+
return _this2.authenticatedResolvers = args;
|
|
5483
|
+
});
|
|
5484
|
+
// Automatic reconnects create this promise with no one awaiting it,
|
|
5485
|
+
// so its rejection must not surface as an unhandled one. Callers
|
|
5486
|
+
// awaiting it still receive the rejection.
|
|
5487
|
+
this.connectPromise["catch"](function () {
|
|
5488
|
+
return undefined;
|
|
5489
|
+
});
|
|
5490
|
+
}
|
|
5491
|
+
connectPromise = this.connectPromise;
|
|
5492
|
+
this.openSocket();
|
|
5493
|
+
return _context.a(2, connectPromise);
|
|
5494
5494
|
}
|
|
5495
5495
|
}, _callee, this);
|
|
5496
5496
|
}));
|
|
@@ -5502,10 +5502,16 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5502
5502
|
}, {
|
|
5503
5503
|
key: "disconnect",
|
|
5504
5504
|
value: function disconnect() {
|
|
5505
|
-
var
|
|
5505
|
+
var wasActive = this.ws !== null || this.reconnectTimeoutId !== undefined;
|
|
5506
|
+
this.reconnectEnabled = false;
|
|
5507
|
+
this.reconnectAttempts = 0;
|
|
5508
|
+
this.cancelScheduledReconnect();
|
|
5509
|
+
this.releaseSocket(1000); // Normal closure
|
|
5506
5510
|
this.failPendingCommands(new Error('Client disconnected before the command was answered'));
|
|
5507
|
-
|
|
5508
|
-
|
|
5511
|
+
this.settleConnect(new Error('Client disconnected before authentication'));
|
|
5512
|
+
if (wasActive) {
|
|
5513
|
+
this.emit(this.Event.disconnect, false);
|
|
5514
|
+
}
|
|
5509
5515
|
}
|
|
5510
5516
|
}, {
|
|
5511
5517
|
key: "send",
|
|
@@ -5539,15 +5545,52 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5539
5545
|
get: function get() {
|
|
5540
5546
|
return this.isOpenWsState() && this.authenticated;
|
|
5541
5547
|
}
|
|
5548
|
+
}, {
|
|
5549
|
+
key: "openSocket",
|
|
5550
|
+
value: function openSocket() {
|
|
5551
|
+
var _this$options$queryPa,
|
|
5552
|
+
_this3 = this,
|
|
5553
|
+
_this$options$connect;
|
|
5554
|
+
// Never leave a previous socket attached (e.g. one still closing).
|
|
5555
|
+
this.releaseSocket(1000);
|
|
5556
|
+
var params = new URLSearchParams((_this$options$queryPa = this.options.queryParams) !== null && _this$options$queryPa !== void 0 ? _this$options$queryPa : {});
|
|
5557
|
+
params.set('token', this.options.token);
|
|
5558
|
+
var ws;
|
|
5559
|
+
try {
|
|
5560
|
+
ws = new WebSocket("".concat(this.options.url, "?").concat(params));
|
|
5561
|
+
} catch (error) {
|
|
5562
|
+
// Invalid URL - no retry can fix that.
|
|
5563
|
+
this.settleConnect(error);
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5567
|
+
// Events of an abandoned socket must not touch the current connection.
|
|
5568
|
+
ws.onmessage = function (ev) {
|
|
5569
|
+
return ws === _this3.ws && _this3.onMessage(ev);
|
|
5570
|
+
};
|
|
5571
|
+
ws.onclose = function (ev) {
|
|
5572
|
+
return ws === _this3.ws && _this3.onClose(ev);
|
|
5573
|
+
};
|
|
5574
|
+
// Not every implementation follows a failed handshake with a close
|
|
5575
|
+
// event (e.g. Node.js), so an error alone means the connection is lost.
|
|
5576
|
+
ws.onerror = function () {
|
|
5577
|
+
return ws === _this3.ws && _this3.handleConnectionLoss(true);
|
|
5578
|
+
};
|
|
5579
|
+
this.ws = ws;
|
|
5580
|
+
this.authenticated = false;
|
|
5581
|
+
this.connectingTimeoutId = setTimeout(function () {
|
|
5582
|
+
return _this3.triggerConnectionTimeout();
|
|
5583
|
+
}, (_this$options$connect = this.options.connectingTimeoutMs) !== null && _this$options$connect !== void 0 ? _this$options$connect : 10000);
|
|
5584
|
+
}
|
|
5542
5585
|
}, {
|
|
5543
5586
|
key: "sendEnvelope",
|
|
5544
5587
|
value: function sendEnvelope(envelope) {
|
|
5545
|
-
var _this$ws$readyState, _this$
|
|
5588
|
+
var _this$ws$readyState, _this$ws;
|
|
5546
5589
|
if (this.isReady) {
|
|
5547
5590
|
this.ws.send(JSON.stringify(envelope));
|
|
5548
5591
|
return;
|
|
5549
5592
|
}
|
|
5550
|
-
this.handleEnvelopeSendError(envelope, new Error("Cannot send - client is not ready (state=".concat((_this$ws$readyState = (_this$
|
|
5593
|
+
this.handleEnvelopeSendError(envelope, new Error("Cannot send - client is not ready (state=".concat((_this$ws$readyState = (_this$ws = this.ws) === null || _this$ws === void 0 ? void 0 : _this$ws.readyState) !== null && _this$ws$readyState !== void 0 ? _this$ws$readyState : '[no connection]', "; authenticated=").concat(this.authenticated, ")")));
|
|
5551
5594
|
}
|
|
5552
5595
|
}, {
|
|
5553
5596
|
key: "onMessage",
|
|
@@ -5563,35 +5606,110 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5563
5606
|
var isAuthenticated = envelope.type !== 'Bye';
|
|
5564
5607
|
this.authenticated = isAuthenticated;
|
|
5565
5608
|
if (isAuthenticated) {
|
|
5609
|
+
this.reconnectAttempts = 0;
|
|
5566
5610
|
this.startConnectionMonitor();
|
|
5567
5611
|
this.settleConnect();
|
|
5568
5612
|
this.emit(this.Event.connect);
|
|
5569
5613
|
this.sendFromQueue();
|
|
5570
5614
|
} else {
|
|
5615
|
+
var _envelope$data;
|
|
5571
5616
|
this.settleConnect(envelope.data);
|
|
5617
|
+
var error = (_envelope$data = envelope.data) === null || _envelope$data === void 0 || (_envelope$data = _envelope$data.reason) === null || _envelope$data === void 0 ? void 0 : _envelope$data.error;
|
|
5618
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === 'AuthenticationException') {
|
|
5619
|
+
// Invalid token - retrying would be rejected the same way.
|
|
5620
|
+
this.handleConnectionLoss(false);
|
|
5621
|
+
this.emit(this.Event.error, new Error("Authentication rejected: ".concat(error.message)));
|
|
5622
|
+
}
|
|
5572
5623
|
}
|
|
5573
5624
|
}
|
|
5574
5625
|
}
|
|
5575
5626
|
}, {
|
|
5576
5627
|
key: "onClose",
|
|
5577
5628
|
value: function onClose(event) {
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5629
|
+
// Connection was closed because of error
|
|
5630
|
+
this.handleConnectionLoss(event.code !== 1000);
|
|
5631
|
+
}
|
|
5632
|
+
|
|
5633
|
+
/**
|
|
5634
|
+
* Abandon the current socket without waiting for its close event (which
|
|
5635
|
+
* may never come, or take minutes on a dead TCP connection), settle
|
|
5636
|
+
* everything that depended on it and schedule a retry when requested.
|
|
5637
|
+
*/
|
|
5638
|
+
}, {
|
|
5639
|
+
key: "handleConnectionLoss",
|
|
5640
|
+
value: function handleConnectionLoss(reconnect) {
|
|
5641
|
+
this.releaseSocket(reconnect ? 3000 : 1000);
|
|
5581
5642
|
|
|
5582
5643
|
// The server can no longer answer anything that was queued or in
|
|
5583
5644
|
// flight, so settle those promises instead of leaving them pending.
|
|
5584
5645
|
this.failPendingCommands(new Error('Connection closed before the command was answered'));
|
|
5646
|
+
reconnect && (reconnect = this.reconnectEnabled);
|
|
5585
5647
|
if (reconnect) {
|
|
5586
5648
|
// Keep a pending connect() promise unsettled - the retry below is
|
|
5587
5649
|
// expected to authenticate and will resolve it.
|
|
5588
|
-
|
|
5650
|
+
this.scheduleReconnect();
|
|
5589
5651
|
} else {
|
|
5652
|
+
this.reconnectEnabled = false;
|
|
5590
5653
|
this.settleConnect(new Error('Connection closed before authentication'));
|
|
5591
5654
|
}
|
|
5592
5655
|
this.emit(this.Event.disconnect, reconnect);
|
|
5593
5656
|
}
|
|
5594
5657
|
|
|
5658
|
+
/**
|
|
5659
|
+
* Detach the current socket from the client and close it if it is still
|
|
5660
|
+
* alive, together with all timers bound to it.
|
|
5661
|
+
*/
|
|
5662
|
+
}, {
|
|
5663
|
+
key: "releaseSocket",
|
|
5664
|
+
value: function releaseSocket(closeCode) {
|
|
5665
|
+
this.stopConnectionMonitor();
|
|
5666
|
+
clearTimeout(this.connectingTimeoutId);
|
|
5667
|
+
this.connectingTimeoutId = undefined;
|
|
5668
|
+
this.authenticated = false;
|
|
5669
|
+
var ws = this.ws;
|
|
5670
|
+
this.ws = null;
|
|
5671
|
+
if (!ws) {
|
|
5672
|
+
return;
|
|
5673
|
+
}
|
|
5674
|
+
ws.onmessage = ws.onclose = ws.onerror = null;
|
|
5675
|
+
if (ws.readyState === ws.CONNECTING || ws.readyState === ws.OPEN) {
|
|
5676
|
+
try {
|
|
5677
|
+
ws.close(closeCode);
|
|
5678
|
+
} catch (_unused) {
|
|
5679
|
+
// Nothing more can be done with a broken socket.
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
}, {
|
|
5684
|
+
key: "scheduleReconnect",
|
|
5685
|
+
value: function scheduleReconnect() {
|
|
5686
|
+
var _this$options$reconne,
|
|
5687
|
+
_this$options$reconne2,
|
|
5688
|
+
_this$options$reconne3,
|
|
5689
|
+
_this$options$reconne4,
|
|
5690
|
+
_this4 = this;
|
|
5691
|
+
this.cancelScheduledReconnect();
|
|
5692
|
+
var minDelay = Math.max(0, (_this$options$reconne = (_this$options$reconne2 = this.options.reconnect) === null || _this$options$reconne2 === void 0 ? void 0 : _this$options$reconne2.minDelayMs) !== null && _this$options$reconne !== void 0 ? _this$options$reconne : 1000);
|
|
5693
|
+
var maxDelay = Math.max(minDelay, (_this$options$reconne3 = (_this$options$reconne4 = this.options.reconnect) === null || _this$options$reconne4 === void 0 ? void 0 : _this$options$reconne4.maxDelayMs) !== null && _this$options$reconne3 !== void 0 ? _this$options$reconne3 : 30000);
|
|
5694
|
+
var delay = Math.min(maxDelay, minDelay * Math.pow(2, Math.min(this.reconnectAttempts, 30)));
|
|
5695
|
+
this.reconnectAttempts++;
|
|
5696
|
+
|
|
5697
|
+
// Random jitter (50-100% of the delay) keeps clients from reconnecting
|
|
5698
|
+
// in lockstep after a server restart.
|
|
5699
|
+
this.reconnectTimeoutId = setTimeout(function () {
|
|
5700
|
+
_this4.reconnectTimeoutId = undefined;
|
|
5701
|
+
_this4.connect()["catch"](function () {
|
|
5702
|
+
return undefined;
|
|
5703
|
+
});
|
|
5704
|
+
}, delay / 2 + Math.random() * delay / 2);
|
|
5705
|
+
}
|
|
5706
|
+
}, {
|
|
5707
|
+
key: "cancelScheduledReconnect",
|
|
5708
|
+
value: function cancelScheduledReconnect() {
|
|
5709
|
+
clearTimeout(this.reconnectTimeoutId);
|
|
5710
|
+
this.reconnectTimeoutId = undefined;
|
|
5711
|
+
}
|
|
5712
|
+
|
|
5595
5713
|
/**
|
|
5596
5714
|
* Resolve (or reject, when an error is given) a pending connect() promise.
|
|
5597
5715
|
* No-op when there is nothing pending.
|
|
@@ -5634,16 +5752,16 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5634
5752
|
}, {
|
|
5635
5753
|
key: "sendFromQueue",
|
|
5636
5754
|
value: function sendFromQueue() {
|
|
5637
|
-
var
|
|
5755
|
+
var _this5 = this;
|
|
5638
5756
|
// Send awaiting data to server
|
|
5639
5757
|
var lastDelay = 0;
|
|
5640
5758
|
var _loop = function _loop() {
|
|
5641
|
-
var
|
|
5642
|
-
var envelope =
|
|
5759
|
+
var _this5$options$awaitQ;
|
|
5760
|
+
var envelope = _this5.sendQueue[dataIndex];
|
|
5643
5761
|
setTimeout(function () {
|
|
5644
|
-
return
|
|
5762
|
+
return _this5.sendEnvelope(envelope);
|
|
5645
5763
|
}, lastDelay);
|
|
5646
|
-
lastDelay += (
|
|
5764
|
+
lastDelay += (_this5$options$awaitQ = _this5.options.awaitQueueSendDelayMs) !== null && _this5$options$awaitQ !== void 0 ? _this5$options$awaitQ : 500;
|
|
5647
5765
|
};
|
|
5648
5766
|
for (var dataIndex in this.sendQueue) {
|
|
5649
5767
|
_loop();
|
|
@@ -5654,7 +5772,7 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5654
5772
|
}, {
|
|
5655
5773
|
key: "triggerConnectionTimeout",
|
|
5656
5774
|
value: function triggerConnectionTimeout() {
|
|
5657
|
-
this.
|
|
5775
|
+
this.handleConnectionLoss(true);
|
|
5658
5776
|
this.emit(this.Event.error, new Error('Connection timeout'));
|
|
5659
5777
|
}
|
|
5660
5778
|
}, {
|
|
@@ -5670,7 +5788,8 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5670
5788
|
}, {
|
|
5671
5789
|
key: "startConnectionMonitor",
|
|
5672
5790
|
value: function startConnectionMonitor() {
|
|
5673
|
-
var
|
|
5791
|
+
var _this6 = this;
|
|
5792
|
+
this.stopConnectionMonitor();
|
|
5674
5793
|
if (!this.options.ping.enabled) {
|
|
5675
5794
|
return;
|
|
5676
5795
|
}
|
|
@@ -5679,30 +5798,32 @@ var WebSocketChatClient = /*#__PURE__*/function (_AbstractChatClient) {
|
|
|
5679
5798
|
return WebSocketChatClient_regenerator().w(function (_context3) {
|
|
5680
5799
|
while (1) switch (_context3.n) {
|
|
5681
5800
|
case 0:
|
|
5682
|
-
if (!(!
|
|
5801
|
+
if (!(!_this6.isReady || _this6.inFlightPingTimeout)) {
|
|
5683
5802
|
_context3.n = 1;
|
|
5684
5803
|
break;
|
|
5685
5804
|
}
|
|
5686
5805
|
return _context3.a(2);
|
|
5687
5806
|
case 1:
|
|
5688
|
-
if (!(Date.now() -
|
|
5807
|
+
if (!(Date.now() - _this6.lastReceivedMessageAt < _this6.options.ping.noActivityTimeoutMs)) {
|
|
5689
5808
|
_context3.n = 2;
|
|
5690
5809
|
break;
|
|
5691
5810
|
}
|
|
5692
5811
|
return _context3.a(2);
|
|
5693
5812
|
case 2:
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5813
|
+
_this6.inFlightPingTimeout = setTimeout(function () {
|
|
5814
|
+
_this6.inFlightPingTimeout = undefined;
|
|
5815
|
+
// Closing a dead connection can hang in CLOSING for minutes,
|
|
5816
|
+
// so drop it right away instead of waiting for the close event.
|
|
5817
|
+
_this6.handleConnectionLoss(true);
|
|
5818
|
+
}, _this6.options.ping.pongBackTimeoutMs);
|
|
5698
5819
|
|
|
5699
5820
|
// A rejection here means the connection dropped while the ping was
|
|
5700
|
-
// in flight;
|
|
5701
|
-
|
|
5821
|
+
// in flight; the loss is already handled, so just stop waiting.
|
|
5822
|
+
_this6.send('Ping', {})["catch"](function () {
|
|
5702
5823
|
return undefined;
|
|
5703
5824
|
}).then(function () {
|
|
5704
|
-
clearTimeout(
|
|
5705
|
-
|
|
5825
|
+
clearTimeout(_this6.inFlightPingTimeout);
|
|
5826
|
+
_this6.inFlightPingTimeout = undefined;
|
|
5706
5827
|
});
|
|
5707
5828
|
case 3:
|
|
5708
5829
|
return _context3.a(2);
|