Skip to content

Commit 0f0af38

Browse files
committed
++packet loss fix
1 parent 7f9b8b0 commit 0f0af38

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "jsonrpc-bidirectional",
33
"description": "Bidirectional JSONRPC over web sockets or HTTP with extensive plugin support.",
4-
"version": "9.7.2",
4+
"version": "9.8.2",
55
"scripts": {
66
"build": "node --experimental-worker build.js",
77
"prepublish": "node --experimental-worker build.js && node --expose-gc --max-old-space-size=1024 --experimental-worker tests/main.js",

src/Plugins/Client/WebSocketTransport.js

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ class WebSocketTransport extends JSONRPC.ClientPluginBase
125125
this._nKeepAliveIntervalMilliseconds = nKeepAliveIntervalMilliseconds;
126126
this._nIntervalIDSendKeepAlivePing = null;
127127
this._nTimeoutIDCheckKeepAliveReceived = null;
128+
this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry = null;
129+
130+
// Both ping and pong *received* control frames, NOT sent (can receive pong as replied, or ping as requests).
131+
this._nKeepAliveControlFramesReceived = 0;
128132

129133

130134
if(bAutoReconnect && !this._jsonrpcBidirectionalRouter && bBidirectionalWebSocketMode)
@@ -207,7 +211,14 @@ class WebSocketTransport extends JSONRPC.ClientPluginBase
207211
if(webSocket.ping)
208212
{
209213
this._nIntervalIDSendKeepAlivePing = setInterval(() => {
210-
webSocket.ping(fnNoop);
214+
try
215+
{
216+
webSocket.ping(fnNoop);
217+
}
218+
catch(error)
219+
{
220+
console.error(error);
221+
}
211222
}, this._nKeepAliveIntervalMilliseconds || Math.max(1, Math.min(4000, Math.floor(this._nKeepAliveTimeoutMilliseconds / 2))));
212223
}
213224

@@ -217,17 +228,47 @@ class WebSocketTransport extends JSONRPC.ClientPluginBase
217228
clearTimeout(this._nTimeoutIDCheckKeepAliveReceived);
218229
}
219230

231+
if(this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry !== null)
232+
{
233+
clearTimeout(this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry);
234+
}
235+
220236
this._nTimeoutIDCheckKeepAliveReceived = setTimeout(() => {
221-
if([WebSocket.CLOSING, WebSocket.OPEN].includes(webSocket.readyState))
237+
try
222238
{
223-
console.error(`Closing WebSocket because timed out after ${this._nKeepAliveTimeoutMilliseconds} milliseconds waiting for ping/pong keep alive control frame.`);
239+
if([WebSocket.CLOSING, WebSocket.OPEN].includes(webSocket.readyState))
240+
{
241+
console.error(`Closing WebSocket because timed out after ${this._nKeepAliveTimeoutMilliseconds} milliseconds waiting for ping/pong keep alive control frame.`);
224242

225-
webSocket.close(
226-
/*CLOSE_NORMAL*/ 1000, // Chrome only supports 1000 or the 3000-3999 range ///* CloseEvent.Internal Error */ 1011,
227-
`Closing WebSocket because timed out after ${this._nKeepAliveTimeoutMilliseconds} milliseconds waiting for ping/pong keep alive control frame.`
228-
);
243+
webSocket.close(
244+
/*CLOSE_NORMAL*/ 1000, // Chrome only supports 1000 or the 3000-3999 range ///* CloseEvent.Internal Error */ 1011,
245+
`Closing WebSocket because timed out after ${this._nKeepAliveTimeoutMilliseconds} milliseconds waiting for ping/pong keep alive control frame.`
246+
);
247+
}
248+
}
249+
catch(error)
250+
{
251+
console.error(error);
229252
}
230253
}, this._nKeepAliveTimeoutMilliseconds);
254+
255+
const nCurrentReceivedPingPongControlFramesCount = this._nKeepAliveControlFramesReceived;
256+
this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry = setTimeout(async() => {
257+
try
258+
{
259+
let nRetryPacketsFloodCount = 10;
260+
261+
while(--nRetryPacketsFloodCount >= 0 && nCurrentReceivedPingPongControlFramesCount === this._nKeepAliveControlFramesReceived)
262+
{
263+
webSocket.ping(fnNoop);
264+
await sleep(500);
265+
}
266+
}
267+
catch(error)
268+
{
269+
console.error(error);
270+
}
271+
}, this._nKeepAliveIntervalMilliseconds + /*Allow lots of latency*/ 5000);
231272
}).bind(this);
232273

233274

@@ -247,6 +288,12 @@ class WebSocketTransport extends JSONRPC.ClientPluginBase
247288
this._nTimeoutIDCheckKeepAliveReceived = null;
248289
}
249290

291+
if(this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry !== null)
292+
{
293+
clearTimeout(this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry);
294+
this._nTimeoutIDCheckKeepAliveReceived_ForPacketLossRetry = null;
295+
}
296+
250297
if(webSocket.on && webSocket.removeListener && process && process.release)
251298
{
252299
webSocket.removeListener("pong", fnOnKeepAlive);

0 commit comments

Comments
 (0)