@push-rpc/next 2.0.6 → 2.0.8
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 +5 -2
- package/dist/client/HttpClient.js +5 -1
- package/dist/client/HttpClient.js.map +1 -1
- package/dist/client/RemoteSubscriptions.d.ts +5 -0
- package/dist/client/RemoteSubscriptions.js +54 -14
- package/dist/client/RemoteSubscriptions.js.map +1 -1
- package/dist/client/RpcClientImpl.d.ts +1 -1
- package/dist/client/RpcClientImpl.js +5 -0
- package/dist/client/RpcClientImpl.js.map +1 -1
- package/dist/client/WebSocketConnection.d.ts +2 -1
- package/dist/client/WebSocketConnection.js +16 -13
- package/dist/client/WebSocketConnection.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/HttpClient.ts +7 -1
- package/src/client/RemoteSubscriptions.ts +77 -27
- package/src/client/RpcClientImpl.ts +6 -1
- package/src/client/WebSocketConnection.ts +23 -12
- package/src/client/index.ts +3 -1
- package/tests/subscriptions.ts +183 -1
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
Client/server framework
|
|
2
|
+
|
|
1
3
|
## Glossary
|
|
2
4
|
|
|
3
5
|
**Remote function**. A function that is implemented at the server side and can be called from the client side. Function
|
|
@@ -29,6 +31,7 @@ triggers.
|
|
|
29
31
|
|
|
30
32
|
- [important] Importing index.js from the root of the package will import node's http package. Not good for clients.
|
|
31
33
|
- Browser sockets don't have 'ping' event. Need to find a different way to detect connection loss.
|
|
34
|
+
- Перевірити, що throttling працює відразу для всіх підписників
|
|
32
35
|
|
|
33
36
|
## Features
|
|
34
37
|
|
|
@@ -37,5 +40,5 @@ triggers.
|
|
|
37
40
|
- Based on HTTP, easy to integrate with existing infrastructure
|
|
38
41
|
- Gradually upgradeable - WS is only used when you need subscriptions
|
|
39
42
|
- Supports compressed HTTP requests.
|
|
40
|
-
- Server runs on Node.JS, client runs in the Node.JS/Browser/ReactNative.
|
|
41
|
-
supported.
|
|
43
|
+
- Server runs on Node.JS, client runs in the Node.JS/Browser/ReactNative. For RN some extra setup is required (
|
|
44
|
+
document). Bun/Deno should also work, but not officially supported.
|
|
@@ -22,9 +22,10 @@ class HttpClient {
|
|
|
22
22
|
return `${this.url}/${itemName}`;
|
|
23
23
|
}
|
|
24
24
|
async httpRequest(method, itemName, params, callTimeout, headers) {
|
|
25
|
+
const itemUrl = this.getItemUrl(itemName);
|
|
25
26
|
try {
|
|
26
27
|
const { signal, finished } = timeoutSignal(callTimeout);
|
|
27
|
-
const response = await fetch(
|
|
28
|
+
const response = await fetch(itemUrl, {
|
|
28
29
|
method,
|
|
29
30
|
headers: {
|
|
30
31
|
"Content-Type": "application/json",
|
|
@@ -54,6 +55,9 @@ class HttpClient {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
catch (e) {
|
|
58
|
+
if (e.message == "Error" || !e.message) {
|
|
59
|
+
e.message = `Error ${e.code} while ${itemUrl}`;
|
|
60
|
+
}
|
|
57
61
|
if (e.message == "fetch failed" && e.cause) {
|
|
58
62
|
e = e.cause;
|
|
59
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/client/HttpClient.ts"],"names":[],"mappings":";;;AAAA,sCAAqD;AACrD,8CAA6D;AAE7D,MAAa,UAAU;IACrB,YACU,GAAW,EACX,QAAgB,EAChB,UAAiD;QAFjD,QAAG,GAAH,GAAG,CAAQ;QACX,aAAQ,GAAR,QAAQ,CAAQ;QAChB,eAAU,GAAV,UAAU,CAAuC;IACxD,CAAC;IAEJ,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,MAAiB,EAAE,WAAmB;QACjE,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;IACzF,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,MAAiB,EAAE,WAAmB;QACtE,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;IACxF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,MAAiB,EAAE,WAAmB;QACxE,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;IACzF,CAAC;IAEO,UAAU,CAAC,QAAgB;QACjC,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,QAAQ,EAAE,CAAA;IAClC,CAAC;IAEO,KAAK,CAAC,WAAW,CACvB,MAAgC,EAChC,QAAgB,EAChB,MAAiB,EACjB,WAAmB,EACnB,OAA+B;QAE/B,IAAI,CAAC;YACH,MAAM,EAAC,MAAM,EAAE,QAAQ,EAAC,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;YAErD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/client/HttpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export declare class RemoteSubscriptions {
|
|
2
2
|
unsubscribe(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): boolean;
|
|
3
3
|
addSubscription(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): void;
|
|
4
|
+
pause(itemName: string, parameters: unknown[]): void;
|
|
5
|
+
unpause(itemName: string, parameters: unknown[]): void;
|
|
6
|
+
flushQueue(itemName: string, parameters: unknown[]): void;
|
|
7
|
+
emptyQueue(itemName: string, parameters: unknown[]): void;
|
|
4
8
|
private removeSubscription;
|
|
5
9
|
getCached(itemName: string, parameters: unknown[]): unknown | undefined;
|
|
6
10
|
consume(itemName: string, parameters: unknown[], data: unknown): void;
|
|
@@ -9,5 +13,6 @@ export declare class RemoteSubscriptions {
|
|
|
9
13
|
parameters: unknown[],
|
|
10
14
|
consumers: Array<(d: unknown) => void>
|
|
11
15
|
]>;
|
|
16
|
+
private getFilterSubscriptions;
|
|
12
17
|
private byItem;
|
|
13
18
|
}
|
|
@@ -18,10 +18,41 @@ class RemoteSubscriptions {
|
|
|
18
18
|
parameters,
|
|
19
19
|
cached: null,
|
|
20
20
|
consumers: [],
|
|
21
|
+
queue: [],
|
|
21
22
|
};
|
|
22
23
|
itemSubscriptions.byParameters.set(parametersKey, parameterSubscriptions);
|
|
23
24
|
parameterSubscriptions.consumers.push(consumer);
|
|
24
25
|
}
|
|
26
|
+
pause(itemName, parameters) {
|
|
27
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
28
|
+
if (!filterSubscriptions)
|
|
29
|
+
return;
|
|
30
|
+
filterSubscriptions.paused = true;
|
|
31
|
+
}
|
|
32
|
+
unpause(itemName, parameters) {
|
|
33
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
34
|
+
if (!filterSubscriptions)
|
|
35
|
+
return;
|
|
36
|
+
filterSubscriptions.paused = false;
|
|
37
|
+
}
|
|
38
|
+
flushQueue(itemName, parameters) {
|
|
39
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
40
|
+
if (!filterSubscriptions)
|
|
41
|
+
return;
|
|
42
|
+
filterSubscriptions.queue.forEach((data) => {
|
|
43
|
+
filterSubscriptions.cached = data;
|
|
44
|
+
filterSubscriptions.consumers.forEach((consumer) => {
|
|
45
|
+
consumer(data);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
filterSubscriptions.queue = [];
|
|
49
|
+
}
|
|
50
|
+
emptyQueue(itemName, parameters) {
|
|
51
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
52
|
+
if (!filterSubscriptions)
|
|
53
|
+
return;
|
|
54
|
+
filterSubscriptions.queue = [];
|
|
55
|
+
}
|
|
25
56
|
removeSubscription(itemName, parametersKey, consumer) {
|
|
26
57
|
const itemSubscriptions = this.byItem.get(itemName);
|
|
27
58
|
if (!itemSubscriptions)
|
|
@@ -43,25 +74,24 @@ class RemoteSubscriptions {
|
|
|
43
74
|
return false;
|
|
44
75
|
}
|
|
45
76
|
getCached(itemName, parameters) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
if (!itemSubscriptions)
|
|
77
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
78
|
+
if (!filterSubscriptions)
|
|
49
79
|
return;
|
|
50
|
-
|
|
51
|
-
return filterSubscriptions?.cached;
|
|
80
|
+
return filterSubscriptions.cached;
|
|
52
81
|
}
|
|
53
82
|
consume(itemName, parameters, data) {
|
|
54
|
-
const
|
|
55
|
-
const itemSubscriptions = this.byItem.get(itemName);
|
|
56
|
-
if (!itemSubscriptions)
|
|
57
|
-
return;
|
|
58
|
-
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey);
|
|
83
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
59
84
|
if (!filterSubscriptions)
|
|
60
85
|
return;
|
|
61
|
-
filterSubscriptions.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
86
|
+
if (filterSubscriptions.paused) {
|
|
87
|
+
filterSubscriptions.queue.push(data);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
filterSubscriptions.cached = data;
|
|
91
|
+
filterSubscriptions.consumers.forEach((consumer) => {
|
|
92
|
+
consumer(data);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
65
95
|
}
|
|
66
96
|
getAllSubscriptions() {
|
|
67
97
|
const result = [];
|
|
@@ -72,6 +102,16 @@ class RemoteSubscriptions {
|
|
|
72
102
|
}
|
|
73
103
|
return result;
|
|
74
104
|
}
|
|
105
|
+
getFilterSubscriptions(itemName, parameters) {
|
|
106
|
+
const parametersKey = getParametersKey(parameters);
|
|
107
|
+
const itemSubscriptions = this.byItem.get(itemName);
|
|
108
|
+
if (!itemSubscriptions)
|
|
109
|
+
return;
|
|
110
|
+
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey);
|
|
111
|
+
if (!filterSubscriptions)
|
|
112
|
+
return;
|
|
113
|
+
return filterSubscriptions;
|
|
114
|
+
}
|
|
75
115
|
}
|
|
76
116
|
exports.RemoteSubscriptions = RemoteSubscriptions;
|
|
77
117
|
function getParametersKey(parameters) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteSubscriptions.js","sourceRoot":"","sources":["../../src/client/RemoteSubscriptions.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AAE9C,MAAa,mBAAmB;IAAhC;
|
|
1
|
+
{"version":3,"file":"RemoteSubscriptions.js","sourceRoot":"","sources":["../../src/client/RemoteSubscriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { ConsumeServicesOptions, RpcClient } from "./index.js";
|
|
|
4
4
|
export declare class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
5
5
|
private readonly options;
|
|
6
6
|
constructor(url: string, options: ConsumeServicesOptions);
|
|
7
|
-
|
|
7
|
+
readonly clientId: string;
|
|
8
8
|
private readonly httpClient;
|
|
9
9
|
private readonly remoteSubscriptions;
|
|
10
10
|
private readonly connection;
|
|
@@ -25,10 +25,15 @@ class RpcClientImpl {
|
|
|
25
25
|
await this.connection.connect();
|
|
26
26
|
try {
|
|
27
27
|
this.remoteSubscriptions.addSubscription(itemName, parameters, consumer);
|
|
28
|
+
this.remoteSubscriptions.pause(itemName, parameters);
|
|
28
29
|
const data = await this.invoke(itemName, rpc_js_1.InvocationType.Subscribe, (...parameters) => this.httpClient.subscribe(itemName, parameters, callOptions?.timeout ?? this.options.callTimeout), parameters);
|
|
30
|
+
this.remoteSubscriptions.unpause(itemName, parameters);
|
|
29
31
|
this.remoteSubscriptions.consume(itemName, parameters, data);
|
|
32
|
+
this.remoteSubscriptions.flushQueue(itemName, parameters);
|
|
30
33
|
}
|
|
31
34
|
catch (e) {
|
|
35
|
+
this.remoteSubscriptions.unpause(itemName, parameters);
|
|
36
|
+
this.remoteSubscriptions.emptyQueue(itemName, parameters);
|
|
32
37
|
await this.unsubscribe(itemName, parameters, consumer);
|
|
33
38
|
throw e;
|
|
34
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RpcClientImpl.js","sourceRoot":"","sources":["../../src/client/RpcClientImpl.ts"],"names":[],"mappings":";;;AAAA,sCAA2E;AAC3E,mDAA0C;AAC1C,qEAA4D;AAC5D,qEAA4D;AAC5D,mCAA6B;AAC7B,2CAAmE;AAEnE,0DAAsD;AAEtD,MAAa,aAAa;IACxB,YACE,GAAW,EACM,OAA+B;QAA/B,YAAO,GAAP,OAAO,CAAwB;
|
|
1
|
+
{"version":3,"file":"RpcClientImpl.js","sourceRoot":"","sources":["../../src/client/RpcClientImpl.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,9 +13,10 @@ export declare class WebSocketConnection {
|
|
|
13
13
|
}, consume: (itemName: string, parameters: unknown[], data: unknown) => void, onConnected: () => void, onDisconnected: () => void);
|
|
14
14
|
private resolveClose;
|
|
15
15
|
close(): Promise<void>;
|
|
16
|
+
private waitConnectionPromise;
|
|
16
17
|
/**
|
|
17
18
|
* Connect to the server, on each disconnect try to disconnect.
|
|
18
|
-
* Resolves at
|
|
19
|
+
* Resolves at next successful connect. Reconnection loop continues even after resolution
|
|
19
20
|
* Never rejects
|
|
20
21
|
*/
|
|
21
22
|
connect(): Promise<void>;
|
|
@@ -14,7 +14,7 @@ class WebSocketConnection {
|
|
|
14
14
|
this.onDisconnected = onDisconnected;
|
|
15
15
|
this.resolveClose = () => { };
|
|
16
16
|
this.socket = null;
|
|
17
|
-
this.disconnectedMark =
|
|
17
|
+
this.disconnectedMark = false;
|
|
18
18
|
this.pingTimeout = null;
|
|
19
19
|
this.clientId = clientId;
|
|
20
20
|
}
|
|
@@ -29,7 +29,7 @@ class WebSocketConnection {
|
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Connect to the server, on each disconnect try to disconnect.
|
|
32
|
-
* Resolves at
|
|
32
|
+
* Resolves at next successful connect. Reconnection loop continues even after resolution
|
|
33
33
|
* Never rejects
|
|
34
34
|
*/
|
|
35
35
|
connect() {
|
|
@@ -38,24 +38,26 @@ class WebSocketConnection {
|
|
|
38
38
|
return Promise.resolve();
|
|
39
39
|
}
|
|
40
40
|
// already started connecting
|
|
41
|
-
if (this.
|
|
42
|
-
return
|
|
41
|
+
if (this.waitConnectionPromise)
|
|
42
|
+
return this.waitConnectionPromise;
|
|
43
43
|
// start connection process
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
let resolveConnectionPromise;
|
|
45
|
+
let errorDelay = 0;
|
|
46
|
+
this.waitConnectionPromise = new Promise(async (resolve) => {
|
|
47
|
+
resolveConnectionPromise = resolve;
|
|
48
48
|
while (true) {
|
|
49
49
|
// connect, and wait for ...
|
|
50
50
|
await new Promise((resolve) => {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const connectionPromise = this.establishConnection(() => {
|
|
52
|
+
// 1. ...disconnected
|
|
53
|
+
// recreate promise so new clients will wait for new connection
|
|
54
|
+
this.waitConnectionPromise = new Promise((resolve) => (resolveConnectionPromise = resolve));
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
53
57
|
connectionPromise.then(() => {
|
|
54
58
|
// first reconnect after successful connection is done without delay
|
|
55
59
|
errorDelay = 0;
|
|
56
|
-
|
|
57
|
-
onFirstConnection();
|
|
58
|
-
onFirstConnection = () => { };
|
|
60
|
+
resolveConnectionPromise();
|
|
59
61
|
}, (e) => {
|
|
60
62
|
logger_js_1.log.warn("Unable to connect WS", e);
|
|
61
63
|
// 2. ... unable to establish connection
|
|
@@ -74,6 +76,7 @@ class WebSocketConnection {
|
|
|
74
76
|
errorDelay = Math.round(Math.random() * this.options.errorDelayMaxDuration);
|
|
75
77
|
}
|
|
76
78
|
});
|
|
79
|
+
return this.waitConnectionPromise;
|
|
77
80
|
}
|
|
78
81
|
isConnected() {
|
|
79
82
|
return this.socket !== null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebSocketConnection.js","sourceRoot":"","sources":["../../src/client/WebSocketConnection.ts"],"names":[],"mappings":";;;AAAA,4CAAgC;AAChC,8CAA8C;AAC9C,sDAA2C;AAE3C,MAAa,mBAAmB;IAC9B,YACmB,GAAW,EACX,QAAgB,EAChB,OAKhB,EACgB,OAAyE,EACzE,WAAuB,EACvB,cAA0B;QAV1B,QAAG,GAAH,GAAG,CAAQ;QACX,aAAQ,GAAR,QAAQ,CAAQ;QAChB,YAAO,GAAP,OAAO,CAKvB;QACgB,YAAO,GAAP,OAAO,CAAkE;QACzE,gBAAW,GAAX,WAAW,CAAY;QACvB,mBAAc,GAAd,cAAc,CAAY;QAKrC,iBAAY,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;
|
|
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
|
@@ -2,6 +2,7 @@ import { RpcContext, Services } from "../rpc.js";
|
|
|
2
2
|
import { ServicesWithSubscriptions } from "./remote.js";
|
|
3
3
|
import { Middleware } from "../utils/middleware.js";
|
|
4
4
|
export type RpcClient = {
|
|
5
|
+
readonly clientId: string;
|
|
5
6
|
isConnected(): boolean;
|
|
6
7
|
close(): Promise<void>;
|
|
7
8
|
_allSubscriptions(): Array<any[]>;
|
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;AA4BzC,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,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;CACF,CAAA"}
|
package/package.json
CHANGED
package/src/client/HttpClient.ts
CHANGED
|
@@ -31,10 +31,12 @@ export class HttpClient {
|
|
|
31
31
|
callTimeout: number,
|
|
32
32
|
headers: Record<string, string>
|
|
33
33
|
): Promise<unknown> {
|
|
34
|
+
const itemUrl = this.getItemUrl(itemName)
|
|
35
|
+
|
|
34
36
|
try {
|
|
35
37
|
const {signal, finished} = timeoutSignal(callTimeout)
|
|
36
38
|
|
|
37
|
-
const response = await fetch(
|
|
39
|
+
const response = await fetch(itemUrl, {
|
|
38
40
|
method,
|
|
39
41
|
headers: {
|
|
40
42
|
"Content-Type": "application/json",
|
|
@@ -72,6 +74,10 @@ export class HttpClient {
|
|
|
72
74
|
return res
|
|
73
75
|
}
|
|
74
76
|
} catch (e: any) {
|
|
77
|
+
if (e.message == "Error" || !e.message) {
|
|
78
|
+
e.message = `Error ${e.code} while ${itemUrl}`
|
|
79
|
+
}
|
|
80
|
+
|
|
75
81
|
if (e.message == "fetch failed" && e.cause) {
|
|
76
82
|
e = e.cause
|
|
77
83
|
}
|
|
@@ -12,15 +12,54 @@ export class RemoteSubscriptions {
|
|
|
12
12
|
this.byItem.set(itemName, itemSubscriptions)
|
|
13
13
|
|
|
14
14
|
const parametersKey = getParametersKey(parameters)
|
|
15
|
-
const parameterSubscriptions = itemSubscriptions.byParameters.get(
|
|
15
|
+
const parameterSubscriptions: ParametersSubscription = itemSubscriptions.byParameters.get(
|
|
16
|
+
parametersKey
|
|
17
|
+
) || {
|
|
16
18
|
parameters,
|
|
17
19
|
cached: null,
|
|
18
20
|
consumers: [],
|
|
21
|
+
queue: [],
|
|
19
22
|
}
|
|
23
|
+
|
|
20
24
|
itemSubscriptions.byParameters.set(parametersKey, parameterSubscriptions)
|
|
21
25
|
parameterSubscriptions.consumers.push(consumer)
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
pause(itemName: string, parameters: unknown[]) {
|
|
29
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
30
|
+
if (!filterSubscriptions) return
|
|
31
|
+
|
|
32
|
+
filterSubscriptions.paused = true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
unpause(itemName: string, parameters: unknown[]) {
|
|
36
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
37
|
+
if (!filterSubscriptions) return
|
|
38
|
+
|
|
39
|
+
filterSubscriptions.paused = false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
flushQueue(itemName: string, parameters: unknown[]) {
|
|
43
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
44
|
+
if (!filterSubscriptions) return
|
|
45
|
+
|
|
46
|
+
filterSubscriptions.queue.forEach((data) => {
|
|
47
|
+
filterSubscriptions.cached = data
|
|
48
|
+
filterSubscriptions.consumers.forEach((consumer) => {
|
|
49
|
+
consumer(data)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
filterSubscriptions.queue = []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
emptyQueue(itemName: string, parameters: unknown[]) {
|
|
57
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
58
|
+
if (!filterSubscriptions) return
|
|
59
|
+
|
|
60
|
+
filterSubscriptions.queue = []
|
|
61
|
+
}
|
|
62
|
+
|
|
24
63
|
private removeSubscription(
|
|
25
64
|
itemName: string,
|
|
26
65
|
parametersKey: string,
|
|
@@ -51,30 +90,24 @@ export class RemoteSubscriptions {
|
|
|
51
90
|
}
|
|
52
91
|
|
|
53
92
|
getCached(itemName: string, parameters: unknown[]): unknown | undefined {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
const itemSubscriptions = this.byItem.get(itemName)
|
|
57
|
-
if (!itemSubscriptions) return
|
|
58
|
-
|
|
59
|
-
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey)
|
|
93
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
94
|
+
if (!filterSubscriptions) return
|
|
60
95
|
|
|
61
|
-
return filterSubscriptions
|
|
96
|
+
return filterSubscriptions.cached
|
|
62
97
|
}
|
|
63
98
|
|
|
64
99
|
consume(itemName: string, parameters: unknown[], data: unknown) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const itemSubscriptions = this.byItem.get(itemName)
|
|
68
|
-
if (!itemSubscriptions) return
|
|
69
|
-
|
|
70
|
-
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey)
|
|
71
|
-
|
|
100
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
72
101
|
if (!filterSubscriptions) return
|
|
73
102
|
|
|
74
|
-
filterSubscriptions.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
if (filterSubscriptions.paused) {
|
|
104
|
+
filterSubscriptions.queue.push(data)
|
|
105
|
+
} else {
|
|
106
|
+
filterSubscriptions.cached = data
|
|
107
|
+
filterSubscriptions.consumers.forEach((consumer) => {
|
|
108
|
+
consumer(data)
|
|
109
|
+
})
|
|
110
|
+
}
|
|
78
111
|
}
|
|
79
112
|
|
|
80
113
|
getAllSubscriptions(): Array<
|
|
@@ -91,18 +124,35 @@ export class RemoteSubscriptions {
|
|
|
91
124
|
return result
|
|
92
125
|
}
|
|
93
126
|
|
|
127
|
+
private getFilterSubscriptions(
|
|
128
|
+
itemName: string,
|
|
129
|
+
parameters: unknown[]
|
|
130
|
+
): ParametersSubscription | undefined {
|
|
131
|
+
const parametersKey = getParametersKey(parameters)
|
|
132
|
+
|
|
133
|
+
const itemSubscriptions = this.byItem.get(itemName)
|
|
134
|
+
if (!itemSubscriptions) return
|
|
135
|
+
|
|
136
|
+
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey)
|
|
137
|
+
if (!filterSubscriptions) return
|
|
138
|
+
|
|
139
|
+
return filterSubscriptions
|
|
140
|
+
}
|
|
141
|
+
|
|
94
142
|
private byItem: Map<string, ItemSubscription> = new Map()
|
|
95
143
|
}
|
|
96
144
|
|
|
97
145
|
type ItemSubscription = {
|
|
98
|
-
byParameters: Map<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
146
|
+
byParameters: Map<string, ParametersSubscription>
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
type ParametersSubscription = {
|
|
150
|
+
parameters: unknown[]
|
|
151
|
+
cached: unknown
|
|
152
|
+
consumers: Array<(d: unknown) => void>
|
|
153
|
+
|
|
154
|
+
paused: boolean
|
|
155
|
+
queue: unknown[]
|
|
106
156
|
}
|
|
107
157
|
|
|
108
158
|
function getParametersKey(parameters: unknown[]) {
|
|
@@ -37,7 +37,7 @@ export class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
public readonly clientId = nanoid()
|
|
41
41
|
private readonly httpClient: HttpClient
|
|
42
42
|
private readonly remoteSubscriptions: RemoteSubscriptions
|
|
43
43
|
private readonly connection: WebSocketConnection
|
|
@@ -119,6 +119,7 @@ export class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
|
119
119
|
|
|
120
120
|
try {
|
|
121
121
|
this.remoteSubscriptions.addSubscription(itemName, parameters, consumer)
|
|
122
|
+
this.remoteSubscriptions.pause(itemName, parameters)
|
|
122
123
|
|
|
123
124
|
const data = await this.invoke(
|
|
124
125
|
itemName,
|
|
@@ -132,8 +133,12 @@ export class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
|
132
133
|
parameters
|
|
133
134
|
)
|
|
134
135
|
|
|
136
|
+
this.remoteSubscriptions.unpause(itemName, parameters)
|
|
135
137
|
this.remoteSubscriptions.consume(itemName, parameters, data)
|
|
138
|
+
this.remoteSubscriptions.flushQueue(itemName, parameters)
|
|
136
139
|
} catch (e) {
|
|
140
|
+
this.remoteSubscriptions.unpause(itemName, parameters)
|
|
141
|
+
this.remoteSubscriptions.emptyQueue(itemName, parameters)
|
|
137
142
|
await this.unsubscribe(itemName, parameters, consumer)
|
|
138
143
|
throw e
|
|
139
144
|
}
|
|
@@ -33,9 +33,11 @@ export class WebSocketConnection {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
private waitConnectionPromise: Promise<void> | undefined
|
|
37
|
+
|
|
36
38
|
/**
|
|
37
39
|
* Connect to the server, on each disconnect try to disconnect.
|
|
38
|
-
* Resolves at
|
|
40
|
+
* Resolves at next successful connect. Reconnection loop continues even after resolution
|
|
39
41
|
* Never rejects
|
|
40
42
|
*/
|
|
41
43
|
connect() {
|
|
@@ -45,29 +47,36 @@ export class WebSocketConnection {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
// already started connecting
|
|
48
|
-
if (this.
|
|
50
|
+
if (this.waitConnectionPromise) return this.waitConnectionPromise
|
|
49
51
|
|
|
50
52
|
// start connection process
|
|
51
|
-
this.disconnectedMark = false
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
let resolveConnectionPromise: () => void
|
|
55
|
+
let errorDelay = 0
|
|
56
|
+
|
|
57
|
+
this.waitConnectionPromise = new Promise(async (resolve) => {
|
|
58
|
+
resolveConnectionPromise = resolve
|
|
56
59
|
|
|
57
60
|
while (true) {
|
|
58
61
|
// connect, and wait for ...
|
|
59
62
|
await new Promise<void>((resolve) => {
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
const connectionPromise = this.establishConnection(() => {
|
|
64
|
+
// 1. ...disconnected
|
|
65
|
+
|
|
66
|
+
// recreate promise so new clients will wait for new connection
|
|
67
|
+
this.waitConnectionPromise = new Promise(
|
|
68
|
+
(resolve) => (resolveConnectionPromise = resolve)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
resolve()
|
|
72
|
+
})
|
|
62
73
|
|
|
63
74
|
connectionPromise.then(
|
|
64
75
|
() => {
|
|
65
76
|
// first reconnect after successful connection is done without delay
|
|
66
77
|
errorDelay = 0
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
onFirstConnection()
|
|
70
|
-
onFirstConnection = () => {}
|
|
79
|
+
resolveConnectionPromise()
|
|
71
80
|
},
|
|
72
81
|
(e) => {
|
|
73
82
|
log.warn("Unable to connect WS", e)
|
|
@@ -93,6 +102,8 @@ export class WebSocketConnection {
|
|
|
93
102
|
errorDelay = Math.round(Math.random() * this.options.errorDelayMaxDuration)
|
|
94
103
|
}
|
|
95
104
|
})
|
|
105
|
+
|
|
106
|
+
return this.waitConnectionPromise
|
|
96
107
|
}
|
|
97
108
|
|
|
98
109
|
public isConnected() {
|
|
@@ -162,7 +173,7 @@ export class WebSocketConnection {
|
|
|
162
173
|
}
|
|
163
174
|
|
|
164
175
|
private socket: WebSocket | null = null
|
|
165
|
-
private disconnectedMark =
|
|
176
|
+
private disconnectedMark = false
|
|
166
177
|
private pingTimeout: NodeJS.Timeout | null = null
|
|
167
178
|
|
|
168
179
|
private heartbeat() {
|
package/src/client/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ import {RpcClientImpl} from "./RpcClientImpl.js"
|
|
|
4
4
|
import {Middleware} from "../utils/middleware.js"
|
|
5
5
|
|
|
6
6
|
export type RpcClient = {
|
|
7
|
+
readonly clientId: string
|
|
8
|
+
|
|
7
9
|
isConnected(): boolean
|
|
8
10
|
close(): Promise<void>
|
|
9
11
|
|
|
@@ -65,7 +67,7 @@ const defaultOptions: ConsumeServicesOptions = {
|
|
|
65
67
|
onConnected: () => {},
|
|
66
68
|
onDisconnected: () => {},
|
|
67
69
|
getHeaders: async () => ({}),
|
|
68
|
-
|
|
70
|
+
|
|
69
71
|
getSubscriptionsUrl(url: string): string {
|
|
70
72
|
return url.replace(/^https(.*)/, "wss$1").replace(/^http(.*)/, "ws$1")
|
|
71
73
|
},
|
package/tests/subscriptions.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {assert} from "chai"
|
|
2
2
|
import {createTestClient, startTestServer, testClient, testServer} from "./testUtils.js"
|
|
3
3
|
import {adelay} from "../src/utils/promises.js"
|
|
4
|
-
import {CallOptions, RpcErrors} from "../src/index.js"
|
|
4
|
+
import {CallOptions, RpcConnectionContext, RpcErrors} from "../src/index.js"
|
|
5
|
+
import {IncomingMessage} from "http"
|
|
6
|
+
import {CLIENT_ID_HEADER} from "../src/rpc.js"
|
|
5
7
|
|
|
6
8
|
describe("Subscriptions", () => {
|
|
7
9
|
it("subscribe delivers data", async () => {
|
|
@@ -472,4 +474,184 @@ describe("Subscriptions", () => {
|
|
|
472
474
|
assert.equal(testClient!._allSubscriptions().length, 0)
|
|
473
475
|
assert.equal(testServer!._allSubscriptions().length, 0)
|
|
474
476
|
}).timeout(5000)
|
|
477
|
+
|
|
478
|
+
it("missing update in case of concurrent subscribe/trigger", async () => {
|
|
479
|
+
const delay = 50
|
|
480
|
+
|
|
481
|
+
const services = await startTestServer({
|
|
482
|
+
test: {
|
|
483
|
+
async longOp() {
|
|
484
|
+
await adelay(delay)
|
|
485
|
+
return 1
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
const client = await createTestClient<typeof services>({
|
|
491
|
+
callTimeout: 2 * delay,
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
let received = 0
|
|
495
|
+
|
|
496
|
+
client.test.longOp.subscribe((val) => {
|
|
497
|
+
console.log("got ", val)
|
|
498
|
+
|
|
499
|
+
received = val
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
await adelay(20)
|
|
503
|
+
services.test.longOp.trigger(undefined, 2)
|
|
504
|
+
|
|
505
|
+
await adelay(2 * delay)
|
|
506
|
+
|
|
507
|
+
assert.equal(received, 2)
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
it.skip("two concurrent subscribes and trigger", async () => {
|
|
511
|
+
const delay = 50
|
|
512
|
+
|
|
513
|
+
const services = await startTestServer({
|
|
514
|
+
test: {
|
|
515
|
+
async longOp() {
|
|
516
|
+
await adelay(delay)
|
|
517
|
+
return 1
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
const client = await createTestClient<typeof services>({
|
|
523
|
+
callTimeout: 2 * delay,
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
let receivedA = 0
|
|
527
|
+
let receivedB = 0
|
|
528
|
+
|
|
529
|
+
client.test.longOp.subscribe((val) => {
|
|
530
|
+
console.log("gotA", val)
|
|
531
|
+
receivedA = val
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
client.test.longOp.subscribe((val) => {
|
|
535
|
+
console.log("gotB", val)
|
|
536
|
+
receivedB = val
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
await adelay(20)
|
|
540
|
+
services.test.longOp.trigger(undefined, 2)
|
|
541
|
+
|
|
542
|
+
await adelay(2 * delay)
|
|
543
|
+
|
|
544
|
+
assert.equal(receivedA, 2)
|
|
545
|
+
assert.equal(receivedB, 2)
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
it("clear queue on subscription failure", async () => {
|
|
549
|
+
const delay = 50
|
|
550
|
+
|
|
551
|
+
let invocation = 0
|
|
552
|
+
const services = await startTestServer({
|
|
553
|
+
test: {
|
|
554
|
+
async longOp(): Promise<number> {
|
|
555
|
+
await adelay(delay)
|
|
556
|
+
if (invocation++ == 1) {
|
|
557
|
+
throw new Error("AA")
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return 1
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
const client = await createTestClient<typeof services>({
|
|
566
|
+
callTimeout: 2 * delay,
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
let received = 0
|
|
570
|
+
|
|
571
|
+
client.test.longOp.subscribe((val) => {
|
|
572
|
+
received = val
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
await adelay(1.5 * delay)
|
|
576
|
+
|
|
577
|
+
client.test.longOp
|
|
578
|
+
.subscribe((val) => {
|
|
579
|
+
received = val
|
|
580
|
+
})
|
|
581
|
+
.catch((e) => {
|
|
582
|
+
// ok
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
await adelay(20)
|
|
586
|
+
services.test.longOp.trigger(undefined, 2) // this should be skipped
|
|
587
|
+
|
|
588
|
+
await adelay(1.5 * delay - 20)
|
|
589
|
+
|
|
590
|
+
client.test.longOp.subscribe((val) => {
|
|
591
|
+
received = val
|
|
592
|
+
})
|
|
593
|
+
|
|
594
|
+
await adelay(1.5 * delay)
|
|
595
|
+
|
|
596
|
+
assert.equal(received, 1)
|
|
597
|
+
})
|
|
598
|
+
|
|
599
|
+
it("subscribe waits for connection", async () => {
|
|
600
|
+
const delay = 50
|
|
601
|
+
|
|
602
|
+
let connectedClients = 0
|
|
603
|
+
let serverCalled = 0
|
|
604
|
+
|
|
605
|
+
const services = await startTestServer(
|
|
606
|
+
{
|
|
607
|
+
test: {
|
|
608
|
+
async op(params: {key: number}): Promise<number> {
|
|
609
|
+
serverCalled++
|
|
610
|
+
return 1
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
async createConnectionContext(req: IncomingMessage): Promise<RpcConnectionContext> {
|
|
616
|
+
const header = req.headers[CLIENT_ID_HEADER]
|
|
617
|
+
|
|
618
|
+
connectedClients++
|
|
619
|
+
|
|
620
|
+
return {
|
|
621
|
+
clientId: (Array.isArray(header) ? header[0] : header) || "anon",
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
}
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
const client = await createTestClient<typeof services>({
|
|
628
|
+
callTimeout: 2 * delay,
|
|
629
|
+
})
|
|
630
|
+
|
|
631
|
+
let received1
|
|
632
|
+
let received2
|
|
633
|
+
|
|
634
|
+
client.test.op.subscribe(
|
|
635
|
+
(val) => {
|
|
636
|
+
received1 = val
|
|
637
|
+
},
|
|
638
|
+
{key: 1}
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
await adelay(40)
|
|
642
|
+
|
|
643
|
+
client.test.op.subscribe(
|
|
644
|
+
(val) => {
|
|
645
|
+
received2 = val
|
|
646
|
+
},
|
|
647
|
+
{key: 2}
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
await adelay(1.5 * delay)
|
|
651
|
+
|
|
652
|
+
assert.equal(received1, 1)
|
|
653
|
+
assert.equal(received2, 1)
|
|
654
|
+
assert.equal(serverCalled, 2)
|
|
655
|
+
assert.equal(testServer!._allSubscriptions().length, 2)
|
|
656
|
+
})
|
|
475
657
|
})
|