@push-rpc/next 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -10
- package/dist/client/HttpClient.js +3 -3
- package/dist/client/HttpClient.js.map +1 -1
- package/dist/client/WebSocketConnection.d.ts +1 -1
- package/dist/client/WebSocketConnection.js +10 -7
- package/dist/client/WebSocketConnection.js.map +1 -1
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js.map +1 -1
- package/dist/rpc.d.ts +3 -0
- package/dist/rpc.js +4 -1
- package/dist/rpc.js.map +1 -1
- package/dist/server/ConnectionsServer.js +5 -2
- package/dist/server/ConnectionsServer.js.map +1 -1
- package/dist/server/http.js +3 -2
- package/dist/server/http.js.map +1 -1
- package/package.json +1 -1
- package/src/client/HttpClient.ts +4 -4
- package/src/client/WebSocketConnection.ts +12 -8
- package/src/client/index.ts +4 -0
- package/src/rpc.ts +5 -1
- package/src/server/ConnectionsServer.ts +5 -2
- package/src/server/http.ts +3 -3
- package/tests/connection.ts +36 -6
package/README.md
CHANGED
|
@@ -4,13 +4,24 @@ Main focus is on simplicity and good developer experience.
|
|
|
4
4
|
|
|
5
5
|
Best used with monorepos using TypeScript. Can also be used with JavaScript and non-JS clients.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Getting started](#getting-started)
|
|
11
|
+
- [Implementation details](#implementation)
|
|
12
|
+
- [Mapping to HTTP & WebSockets messages](#messages)
|
|
13
|
+
- [Detecting stale WebSockets](#stale-websockets)
|
|
14
|
+
- [Limitations](#limitations)
|
|
15
|
+
- [Glossary](#glossary)
|
|
16
|
+
- [Project using Push-RPC](#projects)
|
|
17
|
+
|
|
18
|
+
## Features <a name="features" id="features"></a>
|
|
8
19
|
|
|
9
20
|
- Developer friendly - remote call is a plain TS call for easy tracing between client and server and good
|
|
10
21
|
IDE integration.
|
|
11
22
|
- Based on HTTP, easy to integrate with existing infrastructure. Call visibility in browser DevTools.
|
|
12
23
|
- Gradually upgradeable - WS is only used when you need subscriptions.
|
|
13
|
-
- Server runs on Node.JS, client runs in the Node.JS/Browser/
|
|
24
|
+
- Server runs on Node.JS, client runs in the Node.JS/Browser/React Native.
|
|
14
25
|
|
|
15
26
|
Extra:
|
|
16
27
|
|
|
@@ -20,7 +31,7 @@ Extra:
|
|
|
20
31
|
- Throttling for subscriptions.
|
|
21
32
|
- Broken WS connection detection & auto-reconnecting.
|
|
22
33
|
|
|
23
|
-
## Getting
|
|
34
|
+
## Getting started <a name="getting-started"></a>
|
|
24
35
|
|
|
25
36
|
```
|
|
26
37
|
npm install @push-rpc/next
|
|
@@ -124,7 +135,9 @@ Run server.ts and then client.ts.
|
|
|
124
135
|
|
|
125
136
|
Server will send empty todo list on client connecting and then will send updated list on adding new item.
|
|
126
137
|
|
|
127
|
-
##
|
|
138
|
+
## Implementation details <a name="implementation"></a>
|
|
139
|
+
|
|
140
|
+
### Mapping to HTTP & WebSockets messages <a name="messages"></a>
|
|
128
141
|
|
|
129
142
|
There are the types of messages that can be sent from client to server:
|
|
130
143
|
|
|
@@ -204,7 +217,28 @@ topic name, remote function result and subscription parameters if any:
|
|
|
204
217
|
|
|
205
218
|
Both client & server will try to detect broken connections by sending WS ping/pongs.
|
|
206
219
|
|
|
207
|
-
|
|
220
|
+
### Detecting stale WebSockets <a name="stale-websockets"></a>
|
|
221
|
+
|
|
222
|
+
Detecting stale WebSocket connections is crucial for both server and client. For server, it is important to know
|
|
223
|
+
when to clean up resources associated with the client. For client, it is important to know when to try to reconnect.
|
|
224
|
+
|
|
225
|
+
In Push-RPC, the client is detecting stale connections by measuring time between incoming messages. If no messages
|
|
226
|
+
arrived for `pingInterval * 1.5` milliseconds, connection is considered stale and reconnection is initiated.
|
|
227
|
+
Client option `pingInterval` is specified when consuming service. By default, stale connection detection is disabled.
|
|
228
|
+
|
|
229
|
+
Server is detecting stale connections by sending WS ping messages every `pingInterval` milliseconds. If no pong
|
|
230
|
+
response is received within `pingInterval * 2` milliseconds, connection is considered stale and closed. Server option
|
|
231
|
+
`pingInterval` is specified when publishing services. It is 30 secs by default.
|
|
232
|
+
|
|
233
|
+
Since WebSockets in React Native don't support listening for incoming native WS ping messages, it is impossible to
|
|
234
|
+
use the native WS ping/pong mechanism for stale connection detection. Due to this limitation,
|
|
235
|
+
application ping/pongs are implemented instead.
|
|
236
|
+
|
|
237
|
+
## Limitations <a name="limitations"></a>
|
|
238
|
+
|
|
239
|
+
- Cookies are not been sent during HTTP & WS requests.
|
|
240
|
+
|
|
241
|
+
## Glossary <a name="glossary"></a>
|
|
208
242
|
|
|
209
243
|
**Remote function**. A function that is implemented at the server side and can be called from the client side. Function
|
|
210
244
|
can either be called synchronously or subscribed to. Subscribed function needs to be "triggered" at the server side to
|
|
@@ -234,11 +268,7 @@ Client notifications middleware is called with parameters (ctx, next, data, para
|
|
|
234
268
|
triggers will result in new notifications. Throttling can be used with reducers to aggregate values supplied in
|
|
235
269
|
triggers.
|
|
236
270
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
- Cookies are not been sent during HTTP & WS requests.
|
|
240
|
-
|
|
241
|
-
# Project using Push-RPC
|
|
271
|
+
## Project using Push-RPC <a name="projects"></a>
|
|
242
272
|
|
|
243
273
|
- [General Bots](https://github.com/GeneralBots/BotServer). A strongly typed LLM conversational platform focused in
|
|
244
274
|
convention over configuration and code-less approaches.
|
|
@@ -36,7 +36,7 @@ class HttpClient {
|
|
|
36
36
|
signal,
|
|
37
37
|
});
|
|
38
38
|
finished();
|
|
39
|
-
const hasError = response.headers.has(
|
|
39
|
+
const hasError = response.headers.has(rpc_js_1.ERROR_HEADER);
|
|
40
40
|
if (!hasError && response.status == 204) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
@@ -44,8 +44,8 @@ class HttpClient {
|
|
|
44
44
|
const text = await response.text();
|
|
45
45
|
const res = contentType && contentType.includes("application/json") ? (0, json_js_1.safeParseJson)(text) : text;
|
|
46
46
|
if (hasError || response.status < 200 || response.status >= 300) {
|
|
47
|
-
const error = new Error(!!response.headers.get(
|
|
48
|
-
? decodeURIComponent(response.headers.get(
|
|
47
|
+
const error = new Error(!!response.headers.get(rpc_js_1.ERROR_HEADER)
|
|
48
|
+
? decodeURIComponent(response.headers.get(rpc_js_1.ERROR_HEADER))
|
|
49
49
|
: undefined);
|
|
50
50
|
Object.assign(error, { code: response.status });
|
|
51
51
|
if (typeof res == "object") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/client/HttpClient.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/client/HttpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ export declare class WebSocketConnection {
|
|
|
22
22
|
connect(): Promise<void>;
|
|
23
23
|
isConnected(): boolean;
|
|
24
24
|
/**
|
|
25
|
-
* Connect this to server
|
|
25
|
+
* Connect this connection to the server
|
|
26
26
|
*
|
|
27
27
|
* Resolves on successful connection, rejects on connection error or connection timeout
|
|
28
28
|
*/
|
|
@@ -4,6 +4,7 @@ exports.setTestWebSocketConnectionDelay = exports.WebSocketConnection = void 0;
|
|
|
4
4
|
const logger_js_1 = require("../logger.js");
|
|
5
5
|
const json_js_1 = require("../utils/json.js");
|
|
6
6
|
const promises_js_1 = require("../utils/promises.js");
|
|
7
|
+
const rpc_js_1 = require("../rpc.js");
|
|
7
8
|
class WebSocketConnection {
|
|
8
9
|
constructor(url, clientId, options, consume, onConnected, onDisconnected) {
|
|
9
10
|
this.url = url;
|
|
@@ -40,17 +41,17 @@ class WebSocketConnection {
|
|
|
40
41
|
// already started connecting
|
|
41
42
|
if (this.waitConnectionPromise)
|
|
42
43
|
return this.waitConnectionPromise;
|
|
43
|
-
// start connection process
|
|
44
|
+
// start the connection process
|
|
44
45
|
let resolveConnectionPromise;
|
|
45
46
|
let errorDelay = 0;
|
|
46
47
|
this.waitConnectionPromise = new Promise(async (resolve) => {
|
|
47
48
|
resolveConnectionPromise = resolve;
|
|
48
49
|
while (true) {
|
|
49
|
-
// connect
|
|
50
|
+
// connect and wait for ...
|
|
50
51
|
await new Promise((resolve) => {
|
|
51
52
|
const connectionPromise = this.establishConnection(() => {
|
|
52
53
|
// 1. ...disconnected
|
|
53
|
-
// recreate promise so new clients will wait for new connection
|
|
54
|
+
// recreate promise so new clients will wait for the new connection
|
|
54
55
|
this.waitConnectionPromise = new Promise((resolve) => (resolveConnectionPromise = resolve));
|
|
55
56
|
resolve();
|
|
56
57
|
});
|
|
@@ -82,7 +83,7 @@ class WebSocketConnection {
|
|
|
82
83
|
return this.socket !== null;
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
|
-
* Connect this to server
|
|
86
|
+
* Connect this connection to the server
|
|
86
87
|
*
|
|
87
88
|
* Resolves on successful connection, rejects on connection error or connection timeout
|
|
88
89
|
*/
|
|
@@ -101,9 +102,6 @@ class WebSocketConnection {
|
|
|
101
102
|
this.heartbeat();
|
|
102
103
|
this.onConnected();
|
|
103
104
|
});
|
|
104
|
-
socket.addEventListener("ping", () => {
|
|
105
|
-
this.heartbeat();
|
|
106
|
-
});
|
|
107
105
|
socket.addEventListener("close", () => {
|
|
108
106
|
this.socket = null;
|
|
109
107
|
if (connected) {
|
|
@@ -127,6 +125,11 @@ class WebSocketConnection {
|
|
|
127
125
|
}
|
|
128
126
|
});
|
|
129
127
|
socket.addEventListener("message", (message) => {
|
|
128
|
+
this.heartbeat();
|
|
129
|
+
if (message.data === rpc_js_1.PING_MSG) {
|
|
130
|
+
socket.send(rpc_js_1.PONG_MSG);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
130
133
|
this.receiveSocketMessage(message.data);
|
|
131
134
|
});
|
|
132
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebSocketConnection.js","sourceRoot":"","sources":["../../src/client/WebSocketConnection.ts"],"names":[],"mappings":";;;AAAA,4CAAgC;AAChC,8CAA8C;AAC9C,sDAA2C;
|
|
1
|
+
{"version":3,"file":"WebSocketConnection.js","sourceRoot":"","sources":["../../src/client/WebSocketConnection.ts"],"names":[],"mappings":"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"}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export type ConsumeServicesOptions = {
|
|
|
17
17
|
callTimeout: number;
|
|
18
18
|
reconnectDelay: number;
|
|
19
19
|
errorDelayMaxDuration: number;
|
|
20
|
+
/**
|
|
21
|
+
* Milliseconds to wait before considering the connection stale and trying to reconnect.
|
|
22
|
+
* Should match the server pingInterval.
|
|
23
|
+
*/
|
|
20
24
|
pingInterval: number | null;
|
|
21
25
|
subscriptions: boolean;
|
|
22
26
|
middleware: Middleware<RpcContext>[];
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAEA,yDAAgD;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAEA,yDAAgD;AAwCzC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,kBAAmD,EAAE;IAKrD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;IAC5C,CAAC;IAED,MAAM,OAAO,GAAG;QACd,GAAG,cAAc;QACjB,GAAG,eAAe;KACnB,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,gCAAa,CAAI,GAAG,EAAE,OAAO,CAAC,CAAA;IAEjD,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;IACxB,CAAC;IAED,OAAO;QACL,MAAM;QACN,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE;KAC9B,CAAA;AACH,CAAC;AA1BD,0CA0BC;AAED,MAAM,cAAc,GAA2B;IAC7C,WAAW,EAAE,CAAC,GAAG,IAAI;IACrB,cAAc,EAAE,CAAC;IACjB,qBAAqB,EAAE,EAAE,GAAG,IAAI;IAChC,YAAY,EAAE,IAAI,EAAE,sDAAsD;IAC1E,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,EAAE;IACd,uBAAuB,EAAE,EAAE;IAC3B,eAAe,EAAE,KAAK;IACtB,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;IACrB,cAAc,EAAE,GAAG,EAAE,GAAE,CAAC;IACxB,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAE5B,mBAAmB,CAAC,GAAW;QAC7B,OAAO,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IACxE,CAAC;IACD,KAAK,EAAE,IAAI;CACZ,CAAA"}
|
package/dist/rpc.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export declare class CallOptions {
|
|
|
21
21
|
static KIND: string;
|
|
22
22
|
}
|
|
23
23
|
export declare const CLIENT_ID_HEADER = "x-rpc-client-id";
|
|
24
|
+
export declare const ERROR_HEADER = "x-error";
|
|
25
|
+
export declare const PING_MSG = "PING";
|
|
26
|
+
export declare const PONG_MSG = "PONG";
|
|
24
27
|
export type RpcConnectionContext = {
|
|
25
28
|
clientId: string;
|
|
26
29
|
};
|
package/dist/rpc.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvocationType = exports.CLIENT_ID_HEADER = exports.CallOptions = exports.RpcErrors = exports.RpcError = void 0;
|
|
3
|
+
exports.InvocationType = exports.PONG_MSG = exports.PING_MSG = exports.ERROR_HEADER = exports.CLIENT_ID_HEADER = exports.CallOptions = exports.RpcErrors = exports.RpcError = void 0;
|
|
4
4
|
class RpcError extends Error {
|
|
5
5
|
constructor(code, message) {
|
|
6
6
|
super(message);
|
|
@@ -22,6 +22,9 @@ class CallOptions {
|
|
|
22
22
|
exports.CallOptions = CallOptions;
|
|
23
23
|
CallOptions.KIND = "CallOptions";
|
|
24
24
|
exports.CLIENT_ID_HEADER = "x-rpc-client-id";
|
|
25
|
+
exports.ERROR_HEADER = "x-error";
|
|
26
|
+
exports.PING_MSG = "PING";
|
|
27
|
+
exports.PONG_MSG = "PONG";
|
|
25
28
|
var InvocationType;
|
|
26
29
|
(function (InvocationType) {
|
|
27
30
|
InvocationType["Call"] = "Call";
|
package/dist/rpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":";;;AASA,MAAa,QAAS,SAAQ,KAAK;IACjC,YACkB,IAAY,EAC5B,OAAgB;QAEhB,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;IAI9B,CAAC;CACF;AAPD,4BAOC;AAED,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,mDAAc,CAAA;IACd,iDAAa,CAAA;AACf,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB;AAED,MAAa,WAAW;IACtB,YAAY,OAA0B;QAKtB,SAAI,GAAG,WAAW,CAAC,IAAI,CAAA,CAAC,sDAAsD;QAJ5F,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAChC,CAAC;;AAHH,kCASC;AADe,gBAAI,GAAG,aAAa,AAAhB,CAAgB;AAGvB,QAAA,gBAAgB,GAAG,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":";;;AASA,MAAa,QAAS,SAAQ,KAAK;IACjC,YACkB,IAAY,EAC5B,OAAgB;QAEhB,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;IAI9B,CAAC;CACF;AAPD,4BAOC;AAED,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,mDAAc,CAAA;IACd,iDAAa,CAAA;AACf,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB;AAED,MAAa,WAAW;IACtB,YAAY,OAA0B;QAKtB,SAAI,GAAG,WAAW,CAAC,IAAI,CAAA,CAAC,sDAAsD;QAJ5F,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAChC,CAAC;;AAHH,kCASC;AADe,gBAAI,GAAG,aAAa,AAAhB,CAAgB;AAGvB,QAAA,gBAAgB,GAAG,iBAAiB,CAAA;AACpC,QAAA,YAAY,GAAG,SAAS,CAAA;AAExB,QAAA,QAAQ,GAAG,MAAM,CAAA;AACjB,QAAA,QAAQ,GAAG,MAAM,CAAA;AAW9B,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,+BAAa,CAAA;IACb,yCAAuB,CAAA;IACvB,6CAA2B,CAAA;IAC3B,mCAAiB,CAAA;IACjB,qCAAmB,CAAA;AACrB,CAAC,EANW,cAAc,8BAAd,cAAc,QAMzB"}
|
|
@@ -4,6 +4,7 @@ exports.ConnectionsServer = void 0;
|
|
|
4
4
|
const json_js_1 = require("../utils/json.js");
|
|
5
5
|
const ws_1 = require("ws");
|
|
6
6
|
const logger_js_1 = require("../logger.js");
|
|
7
|
+
const rpc_js_1 = require("../rpc.js");
|
|
7
8
|
class ConnectionsServer {
|
|
8
9
|
constructor(server, options, connectionClosed, closeSocketsWithDifferentPath) {
|
|
9
10
|
this.clientSockets = new Map();
|
|
@@ -31,7 +32,9 @@ class ConnectionsServer {
|
|
|
31
32
|
this.clientSockets.delete(clientId);
|
|
32
33
|
connectionClosed(clientId);
|
|
33
34
|
});
|
|
34
|
-
ws.on("
|
|
35
|
+
ws.on("message", () => {
|
|
36
|
+
// receiving any message is considered a sign of life,
|
|
37
|
+
// but currently the client only sends PONG_MSG
|
|
35
38
|
ws.alive = true;
|
|
36
39
|
});
|
|
37
40
|
});
|
|
@@ -43,7 +46,7 @@ class ConnectionsServer {
|
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
48
|
ws.alive = false;
|
|
46
|
-
ws.
|
|
49
|
+
ws.send(rpc_js_1.PONG_MSG);
|
|
47
50
|
});
|
|
48
51
|
}, options.pingInterval);
|
|
49
52
|
this.wss.on("close", () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsServer.js","sourceRoot":"","sources":["../../src/server/ConnectionsServer.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AAC9C,2BAA6C;AAE7C,4CAAgC;
|
|
1
|
+
{"version":3,"file":"ConnectionsServer.js","sourceRoot":"","sources":["../../src/server/ConnectionsServer.ts"],"names":[],"mappings":"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"}
|
package/dist/server/http.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.serveHttpRequest = void 0;
|
|
4
|
+
const rpc_js_1 = require("../rpc.js");
|
|
4
5
|
const json_js_1 = require("../utils/json.js");
|
|
5
6
|
const logger_js_1 = require("../logger.js");
|
|
6
7
|
const server_js_1 = require("../utils/server.js");
|
|
@@ -52,7 +53,7 @@ async function serveHttpRequest(req, res, path, hooks, createConnectionContext)
|
|
|
52
53
|
catch (e) {
|
|
53
54
|
if (e.code && typeof e.code == "number" && e.code >= 100 && e.code < 600) {
|
|
54
55
|
res.statusCode = e.code;
|
|
55
|
-
res.setHeader(
|
|
56
|
+
res.setHeader(rpc_js_1.ERROR_HEADER, encodeURIComponent(e["message"] ?? ""));
|
|
56
57
|
const { code, message, stack, ...rest } = e;
|
|
57
58
|
if (Object.keys(rest).length > 0) {
|
|
58
59
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -65,7 +66,7 @@ async function serveHttpRequest(req, res, path, hooks, createConnectionContext)
|
|
|
65
66
|
logger_js_1.log.warn(`Error in ${req.url}.`, e);
|
|
66
67
|
res.statusCode = 500;
|
|
67
68
|
if (e["message"]) {
|
|
68
|
-
res.setHeader(
|
|
69
|
+
res.setHeader(rpc_js_1.ERROR_HEADER, encodeURIComponent(e["message"]));
|
|
69
70
|
}
|
|
70
71
|
res.end();
|
|
71
72
|
return;
|
package/dist/server/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/server/http.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client/HttpClient.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {CLIENT_ID_HEADER, RpcErrors} from "../rpc.js"
|
|
1
|
+
import {CLIENT_ID_HEADER, ERROR_HEADER, RpcErrors} from "../rpc.js"
|
|
2
2
|
import {safeParseJson, safeStringify} from "../utils/json.js"
|
|
3
3
|
|
|
4
4
|
export class HttpClient {
|
|
@@ -49,7 +49,7 @@ export class HttpClient {
|
|
|
49
49
|
|
|
50
50
|
finished()
|
|
51
51
|
|
|
52
|
-
const hasError = response.headers.has(
|
|
52
|
+
const hasError = response.headers.has(ERROR_HEADER)
|
|
53
53
|
|
|
54
54
|
if (!hasError && response.status == 204) {
|
|
55
55
|
return
|
|
@@ -64,8 +64,8 @@ export class HttpClient {
|
|
|
64
64
|
|
|
65
65
|
if (hasError || response.status < 200 || response.status >= 300) {
|
|
66
66
|
const error = new Error(
|
|
67
|
-
!!response.headers.get(
|
|
68
|
-
? decodeURIComponent(response.headers.get(
|
|
67
|
+
!!response.headers.get(ERROR_HEADER)
|
|
68
|
+
? decodeURIComponent(response.headers.get(ERROR_HEADER)!!)
|
|
69
69
|
: undefined,
|
|
70
70
|
)
|
|
71
71
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {log} from "../logger.js"
|
|
2
2
|
import {safeParseJson} from "../utils/json.js"
|
|
3
3
|
import {adelay} from "../utils/promises.js"
|
|
4
|
+
import {PING_MSG, PONG_MSG} from "../rpc.js"
|
|
4
5
|
|
|
5
6
|
export class WebSocketConnection {
|
|
6
7
|
constructor(
|
|
@@ -53,7 +54,7 @@ export class WebSocketConnection {
|
|
|
53
54
|
// already started connecting
|
|
54
55
|
if (this.waitConnectionPromise) return this.waitConnectionPromise
|
|
55
56
|
|
|
56
|
-
// start connection process
|
|
57
|
+
// start the connection process
|
|
57
58
|
|
|
58
59
|
let resolveConnectionPromise: () => void
|
|
59
60
|
let errorDelay = 0
|
|
@@ -62,12 +63,12 @@ export class WebSocketConnection {
|
|
|
62
63
|
resolveConnectionPromise = resolve
|
|
63
64
|
|
|
64
65
|
while (true) {
|
|
65
|
-
// connect
|
|
66
|
+
// connect and wait for ...
|
|
66
67
|
await new Promise<void>((resolve) => {
|
|
67
68
|
const connectionPromise = this.establishConnection(() => {
|
|
68
69
|
// 1. ...disconnected
|
|
69
70
|
|
|
70
|
-
// recreate promise so new clients will wait for new connection
|
|
71
|
+
// recreate promise so new clients will wait for the new connection
|
|
71
72
|
this.waitConnectionPromise = new Promise(
|
|
72
73
|
(resolve) => (resolveConnectionPromise = resolve),
|
|
73
74
|
)
|
|
@@ -115,7 +116,7 @@ export class WebSocketConnection {
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
/**
|
|
118
|
-
* Connect this to server
|
|
119
|
+
* Connect this connection to the server
|
|
119
120
|
*
|
|
120
121
|
* Resolves on successful connection, rejects on connection error or connection timeout
|
|
121
122
|
*/
|
|
@@ -140,10 +141,6 @@ export class WebSocketConnection {
|
|
|
140
141
|
this.onConnected()
|
|
141
142
|
})
|
|
142
143
|
|
|
143
|
-
socket.addEventListener("ping", () => {
|
|
144
|
-
this.heartbeat()
|
|
145
|
-
})
|
|
146
|
-
|
|
147
144
|
socket.addEventListener("close", () => {
|
|
148
145
|
this.socket = null
|
|
149
146
|
|
|
@@ -172,6 +169,13 @@ export class WebSocketConnection {
|
|
|
172
169
|
})
|
|
173
170
|
|
|
174
171
|
socket.addEventListener("message", (message) => {
|
|
172
|
+
this.heartbeat()
|
|
173
|
+
|
|
174
|
+
if (message.data === PING_MSG) {
|
|
175
|
+
socket.send(PONG_MSG)
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
175
179
|
this.receiveSocketMessage(message.data)
|
|
176
180
|
})
|
|
177
181
|
} catch (e) {
|
package/src/client/index.ts
CHANGED
|
@@ -24,6 +24,10 @@ export type ConsumeServicesOptions = {
|
|
|
24
24
|
callTimeout: number
|
|
25
25
|
reconnectDelay: number
|
|
26
26
|
errorDelayMaxDuration: number
|
|
27
|
+
/**
|
|
28
|
+
* Milliseconds to wait before considering the connection stale and trying to reconnect.
|
|
29
|
+
* Should match the server pingInterval.
|
|
30
|
+
*/
|
|
27
31
|
pingInterval: number | null
|
|
28
32
|
subscriptions: boolean
|
|
29
33
|
middleware: Middleware<RpcContext>[]
|
package/src/rpc.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type Consumer<T extends RemoteFunction> = (data: ExtractPromiseResult<Ret
|
|
|
10
10
|
export class RpcError extends Error {
|
|
11
11
|
constructor(
|
|
12
12
|
public readonly code: number,
|
|
13
|
-
message?: string
|
|
13
|
+
message?: string,
|
|
14
14
|
) {
|
|
15
15
|
super(message)
|
|
16
16
|
}
|
|
@@ -33,6 +33,10 @@ export class CallOptions {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export const CLIENT_ID_HEADER = "x-rpc-client-id"
|
|
36
|
+
export const ERROR_HEADER = "x-error"
|
|
37
|
+
|
|
38
|
+
export const PING_MSG = "PING"
|
|
39
|
+
export const PONG_MSG = "PONG"
|
|
36
40
|
|
|
37
41
|
export type RpcConnectionContext = {
|
|
38
42
|
clientId: string
|
|
@@ -2,6 +2,7 @@ import {safeStringify} from "../utils/json.js"
|
|
|
2
2
|
import WebSocket, {WebSocketServer} from "ws"
|
|
3
3
|
import http from "http"
|
|
4
4
|
import {log} from "../logger.js"
|
|
5
|
+
import {PONG_MSG} from "../rpc.js"
|
|
5
6
|
|
|
6
7
|
export class ConnectionsServer {
|
|
7
8
|
constructor(
|
|
@@ -39,7 +40,9 @@ export class ConnectionsServer {
|
|
|
39
40
|
connectionClosed(clientId)
|
|
40
41
|
})
|
|
41
42
|
|
|
42
|
-
ws.on("
|
|
43
|
+
ws.on("message", () => {
|
|
44
|
+
// receiving any message is considered a sign of life,
|
|
45
|
+
// but currently the client only sends PONG_MSG
|
|
43
46
|
ws.alive = true
|
|
44
47
|
})
|
|
45
48
|
})
|
|
@@ -53,7 +56,7 @@ export class ConnectionsServer {
|
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
ws.alive = false
|
|
56
|
-
ws.
|
|
59
|
+
ws.send(PONG_MSG)
|
|
57
60
|
})
|
|
58
61
|
}, options.pingInterval)
|
|
59
62
|
|
package/src/server/http.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as http from "http"
|
|
2
2
|
import {IncomingMessage, ServerResponse} from "http"
|
|
3
|
-
import {RpcConnectionContext} from "../rpc.js"
|
|
3
|
+
import {ERROR_HEADER, RpcConnectionContext} from "../rpc.js"
|
|
4
4
|
import {safeParseJson, safeStringify} from "../utils/json.js"
|
|
5
5
|
import {log} from "../logger.js"
|
|
6
6
|
import {decompressRequest} from "../utils/server.js"
|
|
@@ -70,7 +70,7 @@ export async function serveHttpRequest(
|
|
|
70
70
|
if (e.code && typeof e.code == "number" && e.code >= 100 && e.code < 600) {
|
|
71
71
|
res.statusCode = e.code
|
|
72
72
|
|
|
73
|
-
res.setHeader(
|
|
73
|
+
res.setHeader(ERROR_HEADER, encodeURIComponent(e["message"] ?? ""))
|
|
74
74
|
const {code, message, stack, ...rest} = e
|
|
75
75
|
if (Object.keys(rest).length > 0) {
|
|
76
76
|
res.setHeader("Content-Type", "application/json")
|
|
@@ -83,7 +83,7 @@ export async function serveHttpRequest(
|
|
|
83
83
|
|
|
84
84
|
res.statusCode = 500
|
|
85
85
|
if (e["message"]) {
|
|
86
|
-
res.setHeader(
|
|
86
|
+
res.setHeader(ERROR_HEADER, encodeURIComponent(e["message"]))
|
|
87
87
|
}
|
|
88
88
|
res.end()
|
|
89
89
|
return
|
package/tests/connection.ts
CHANGED
|
@@ -5,10 +5,7 @@ import {adelay} from "../src/utils/promises.js"
|
|
|
5
5
|
|
|
6
6
|
describe("connection", () => {
|
|
7
7
|
it("server close connection on ping timeout", async () => {
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
oldPing = WebSocket.prototype.ping
|
|
11
|
-
WebSocket.prototype.ping = () => {}
|
|
8
|
+
let oldSend: typeof WebSocket.prototype.send
|
|
12
9
|
|
|
13
10
|
const pingInterval = 100
|
|
14
11
|
|
|
@@ -20,7 +17,7 @@ describe("connection", () => {
|
|
|
20
17
|
},
|
|
21
18
|
{
|
|
22
19
|
pingInterval,
|
|
23
|
-
}
|
|
20
|
+
},
|
|
24
21
|
)
|
|
25
22
|
|
|
26
23
|
const remote = await createTestClient<typeof services>({
|
|
@@ -30,13 +27,16 @@ describe("connection", () => {
|
|
|
30
27
|
await remote.test.call.subscribe(() => {})
|
|
31
28
|
assert.equal(testServer?._allSubscriptions().length, 1)
|
|
32
29
|
|
|
30
|
+
oldSend = WebSocket.prototype.send
|
|
31
|
+
WebSocket.prototype.send = () => {}
|
|
32
|
+
|
|
33
33
|
// wait for timeout
|
|
34
34
|
await adelay(pingInterval * 2.5)
|
|
35
35
|
|
|
36
36
|
// should be closed
|
|
37
37
|
assert.equal(testServer?._allSubscriptions().length, 0)
|
|
38
38
|
|
|
39
|
-
WebSocket.prototype.
|
|
39
|
+
WebSocket.prototype.send = oldSend
|
|
40
40
|
}).timeout(5000)
|
|
41
41
|
|
|
42
42
|
it("client close connection on ping timeout", async () => {
|
|
@@ -89,6 +89,36 @@ describe("connection", () => {
|
|
|
89
89
|
assert.equal(testClient!.isConnected(), true)
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
+
it("notifications considered as pings", async () => {
|
|
93
|
+
const pingInterval = 200 // less than server pings, so client will close connection first
|
|
94
|
+
|
|
95
|
+
const services = await startTestServer({
|
|
96
|
+
test: {
|
|
97
|
+
async call() {
|
|
98
|
+
return "1"
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const remote = await createTestClient<typeof services>({
|
|
104
|
+
pingInterval,
|
|
105
|
+
reconnectDelay: pingInterval * 2, // will not reconnect right away
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
await remote.test.call.subscribe(() => {})
|
|
109
|
+
|
|
110
|
+
await adelay(pingInterval)
|
|
111
|
+
services.test.call.trigger(undefined, "2")
|
|
112
|
+
|
|
113
|
+
assert.equal(testClient!.isConnected(), true)
|
|
114
|
+
|
|
115
|
+
// wait for timeout
|
|
116
|
+
await adelay(pingInterval * 1.5)
|
|
117
|
+
|
|
118
|
+
// still connected, because got notification from trigger
|
|
119
|
+
assert.equal(testClient!.isConnected(), true)
|
|
120
|
+
})
|
|
121
|
+
|
|
92
122
|
it("close will stop reconnection loop", async () => {
|
|
93
123
|
const services = await startTestServer({
|
|
94
124
|
item: async () => "1",
|