@push-rpc/next 2.0.17 → 2.0.18
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/.prettierrc.json +1 -1
- package/dist/client/RemoteSubscriptions.d.ts +7 -0
- package/dist/client/RemoteSubscriptions.js +22 -5
- package/dist/client/RemoteSubscriptions.js.map +1 -1
- package/dist/client/RpcClientImpl.js +8 -1
- package/dist/client/RpcClientImpl.js.map +1 -1
- package/package.json +1 -1
- package/src/client/RemoteSubscriptions.ts +35 -8
- package/src/client/RpcClientImpl.ts +11 -2
- package/tests/subscriptions.ts +55 -22
package/.prettierrc.json
CHANGED
|
@@ -3,6 +3,7 @@ export declare class RemoteSubscriptions {
|
|
|
3
3
|
private cache;
|
|
4
4
|
constructor(cache: ClientCache | null);
|
|
5
5
|
unsubscribe(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): boolean;
|
|
6
|
+
/** Add subscription in pending state */
|
|
6
7
|
addSubscription(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): void;
|
|
7
8
|
pause(itemName: string, parameters: unknown[]): void;
|
|
8
9
|
unpause(itemName: string, parameters: unknown[]): void;
|
|
@@ -11,6 +12,7 @@ export declare class RemoteSubscriptions {
|
|
|
11
12
|
private removeSubscription;
|
|
12
13
|
getCached(itemName: string, parameters: unknown[]): unknown | undefined;
|
|
13
14
|
consume(itemName: string, parameters: unknown[], data: unknown): void;
|
|
15
|
+
getConsumerSubscription(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): ConsumerSubscription | undefined;
|
|
14
16
|
getAllSubscriptions(): Array<[
|
|
15
17
|
itemName: string,
|
|
16
18
|
parameters: unknown[],
|
|
@@ -19,3 +21,8 @@ export declare class RemoteSubscriptions {
|
|
|
19
21
|
private getFilterSubscriptions;
|
|
20
22
|
private byItem;
|
|
21
23
|
}
|
|
24
|
+
type ConsumerSubscription = {
|
|
25
|
+
consumer: (d: unknown) => void;
|
|
26
|
+
completed: boolean;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -11,6 +11,7 @@ class RemoteSubscriptions {
|
|
|
11
11
|
const parametersKey = getParametersKey(parameters);
|
|
12
12
|
return this.removeSubscription(itemName, parametersKey, consumer);
|
|
13
13
|
}
|
|
14
|
+
/** Add subscription in pending state */
|
|
14
15
|
addSubscription(itemName, parameters, consumer) {
|
|
15
16
|
const itemSubscriptions = this.byItem.get(itemName) || { byParameters: new Map() };
|
|
16
17
|
this.byItem.set(itemName, itemSubscriptions);
|
|
@@ -22,7 +23,10 @@ class RemoteSubscriptions {
|
|
|
22
23
|
queue: [],
|
|
23
24
|
};
|
|
24
25
|
itemSubscriptions.byParameters.set(parametersKey, parameterSubscriptions);
|
|
25
|
-
parameterSubscriptions.consumers.push(
|
|
26
|
+
parameterSubscriptions.consumers.push({
|
|
27
|
+
consumer,
|
|
28
|
+
completed: false,
|
|
29
|
+
});
|
|
26
30
|
}
|
|
27
31
|
pause(itemName, parameters) {
|
|
28
32
|
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
@@ -45,7 +49,9 @@ class RemoteSubscriptions {
|
|
|
45
49
|
this.cache.put(itemName, parameters, data);
|
|
46
50
|
filterSubscriptions.cached = data;
|
|
47
51
|
filterSubscriptions.consumers.forEach((consumer) => {
|
|
48
|
-
consumer
|
|
52
|
+
if (consumer.completed) {
|
|
53
|
+
consumer.consumer(data);
|
|
54
|
+
}
|
|
49
55
|
});
|
|
50
56
|
});
|
|
51
57
|
filterSubscriptions.queue = [];
|
|
@@ -63,7 +69,7 @@ class RemoteSubscriptions {
|
|
|
63
69
|
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey);
|
|
64
70
|
if (!filterSubscriptions)
|
|
65
71
|
return false;
|
|
66
|
-
const index = filterSubscriptions.consumers.
|
|
72
|
+
const index = filterSubscriptions.consumers.findIndex((c) => c.consumer == consumer);
|
|
67
73
|
if (index == -1)
|
|
68
74
|
return false;
|
|
69
75
|
filterSubscriptions.consumers.splice(index, 1);
|
|
@@ -94,15 +100,26 @@ class RemoteSubscriptions {
|
|
|
94
100
|
this.cache.put(itemName, parameters, data);
|
|
95
101
|
filterSubscriptions.cached = data;
|
|
96
102
|
filterSubscriptions.consumers.forEach((consumer) => {
|
|
97
|
-
consumer
|
|
103
|
+
if (consumer.completed) {
|
|
104
|
+
consumer.consumer(data);
|
|
105
|
+
}
|
|
98
106
|
});
|
|
99
107
|
}
|
|
100
108
|
}
|
|
109
|
+
getConsumerSubscription(itemName, parameters, consumer) {
|
|
110
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters);
|
|
111
|
+
return (filterSubscriptions?.consumers || []).find((c) => c.consumer == consumer);
|
|
112
|
+
}
|
|
101
113
|
getAllSubscriptions() {
|
|
102
114
|
const result = [];
|
|
103
115
|
for (const [itemName, itemSubscriptions] of this.byItem) {
|
|
104
116
|
for (const [, parameterSubscriptions] of itemSubscriptions.byParameters) {
|
|
105
|
-
|
|
117
|
+
const consumers = parameterSubscriptions.consumers
|
|
118
|
+
.filter((c) => c.completed)
|
|
119
|
+
.map((c) => c.consumer);
|
|
120
|
+
if (consumers.length) {
|
|
121
|
+
result.push([itemName, parameterSubscriptions.parameters, consumers]);
|
|
122
|
+
}
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
125
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteSubscriptions.js","sourceRoot":"","sources":["../../src/client/RemoteSubscriptions.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AAI9C,MAAa,mBAAmB;IAC9B,YAAoB,KAAyB;QAAzB,UAAK,GAAL,KAAK,CAAoB;
|
|
1
|
+
{"version":3,"file":"RemoteSubscriptions.js","sourceRoot":"","sources":["../../src/client/RemoteSubscriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,11 +20,18 @@ class RpcClientImpl {
|
|
|
20
20
|
if (cached !== undefined) {
|
|
21
21
|
consumer(cached);
|
|
22
22
|
}
|
|
23
|
+
// add subscription in pending state to test later if it was unsubscribed during connection wait
|
|
24
|
+
this.remoteSubscriptions.addSubscription(itemName, parameters, consumer);
|
|
23
25
|
// Needs to be awaited b/c resubscribe will make a 2nd request then.
|
|
24
26
|
// Also, server needs the connection to be established before making a subscription
|
|
25
27
|
await this.connection.connect();
|
|
26
28
|
try {
|
|
27
|
-
|
|
29
|
+
// check if already unsubscribed
|
|
30
|
+
const sub = this.remoteSubscriptions.getConsumerSubscription(itemName, parameters, consumer);
|
|
31
|
+
if (!sub)
|
|
32
|
+
return;
|
|
33
|
+
// mark as completed - will resubscribe on reconnects
|
|
34
|
+
sub.completed = true;
|
|
28
35
|
this.remoteSubscriptions.pause(itemName, parameters);
|
|
29
36
|
const data = await this.invoke(itemName, rpc_js_1.InvocationType.Subscribe, (...parameters) => this.httpClient.subscribe(itemName, parameters, callOptions?.timeout ?? this.options.callTimeout), parameters);
|
|
30
37
|
this.remoteSubscriptions.unpause(itemName, parameters);
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"RpcClientImpl.js","sourceRoot":"","sources":["../../src/client/RpcClientImpl.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -3,8 +3,7 @@ import {safeStringify} from "../utils/json.js"
|
|
|
3
3
|
import {ClientCache} from "./index"
|
|
4
4
|
|
|
5
5
|
export class RemoteSubscriptions {
|
|
6
|
-
constructor(private cache: ClientCache | null) {
|
|
7
|
-
}
|
|
6
|
+
constructor(private cache: ClientCache | null) {}
|
|
8
7
|
|
|
9
8
|
unsubscribe(itemName: string, parameters: unknown[], consumer: (d: unknown) => void): boolean {
|
|
10
9
|
const parametersKey = getParametersKey(parameters)
|
|
@@ -12,6 +11,7 @@ export class RemoteSubscriptions {
|
|
|
12
11
|
return this.removeSubscription(itemName, parametersKey, consumer)
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
/** Add subscription in pending state */
|
|
15
15
|
addSubscription(itemName: string, parameters: unknown[], consumer: (d: unknown) => void) {
|
|
16
16
|
const itemSubscriptions = this.byItem.get(itemName) || {byParameters: new Map()}
|
|
17
17
|
this.byItem.set(itemName, itemSubscriptions)
|
|
@@ -27,7 +27,10 @@ export class RemoteSubscriptions {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
itemSubscriptions.byParameters.set(parametersKey, parameterSubscriptions)
|
|
30
|
-
parameterSubscriptions.consumers.push(
|
|
30
|
+
parameterSubscriptions.consumers.push({
|
|
31
|
+
consumer,
|
|
32
|
+
completed: false,
|
|
33
|
+
})
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
pause(itemName: string, parameters: unknown[]) {
|
|
@@ -52,7 +55,9 @@ export class RemoteSubscriptions {
|
|
|
52
55
|
if (this.cache) this.cache.put(itemName, parameters, data)
|
|
53
56
|
filterSubscriptions.cached = data
|
|
54
57
|
filterSubscriptions.consumers.forEach((consumer) => {
|
|
55
|
-
consumer
|
|
58
|
+
if (consumer.completed) {
|
|
59
|
+
consumer.consumer(data)
|
|
60
|
+
}
|
|
56
61
|
})
|
|
57
62
|
})
|
|
58
63
|
|
|
@@ -77,7 +82,7 @@ export class RemoteSubscriptions {
|
|
|
77
82
|
const filterSubscriptions = itemSubscriptions.byParameters.get(parametersKey)
|
|
78
83
|
if (!filterSubscriptions) return false
|
|
79
84
|
|
|
80
|
-
const index = filterSubscriptions.consumers.
|
|
85
|
+
const index = filterSubscriptions.consumers.findIndex((c) => c.consumer == consumer)
|
|
81
86
|
if (index == -1) return false
|
|
82
87
|
|
|
83
88
|
filterSubscriptions.consumers.splice(index, 1)
|
|
@@ -112,11 +117,22 @@ export class RemoteSubscriptions {
|
|
|
112
117
|
if (this.cache) this.cache.put(itemName, parameters, data)
|
|
113
118
|
filterSubscriptions.cached = data
|
|
114
119
|
filterSubscriptions.consumers.forEach((consumer) => {
|
|
115
|
-
consumer
|
|
120
|
+
if (consumer.completed) {
|
|
121
|
+
consumer.consumer(data)
|
|
122
|
+
}
|
|
116
123
|
})
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
|
|
127
|
+
getConsumerSubscription(
|
|
128
|
+
itemName: string,
|
|
129
|
+
parameters: unknown[],
|
|
130
|
+
consumer: (d: unknown) => void,
|
|
131
|
+
): ConsumerSubscription | undefined {
|
|
132
|
+
const filterSubscriptions = this.getFilterSubscriptions(itemName, parameters)
|
|
133
|
+
return (filterSubscriptions?.consumers || []).find((c) => c.consumer == consumer)
|
|
134
|
+
}
|
|
135
|
+
|
|
120
136
|
getAllSubscriptions(): Array<
|
|
121
137
|
[itemName: string, parameters: unknown[], consumers: Array<(d: unknown) => void>]
|
|
122
138
|
> {
|
|
@@ -124,7 +140,13 @@ export class RemoteSubscriptions {
|
|
|
124
140
|
|
|
125
141
|
for (const [itemName, itemSubscriptions] of this.byItem) {
|
|
126
142
|
for (const [, parameterSubscriptions] of itemSubscriptions.byParameters) {
|
|
127
|
-
|
|
143
|
+
const consumers = parameterSubscriptions.consumers
|
|
144
|
+
.filter((c) => c.completed)
|
|
145
|
+
.map((c) => c.consumer)
|
|
146
|
+
|
|
147
|
+
if (consumers.length) {
|
|
148
|
+
result.push([itemName, parameterSubscriptions.parameters, consumers])
|
|
149
|
+
}
|
|
128
150
|
}
|
|
129
151
|
}
|
|
130
152
|
|
|
@@ -156,12 +178,17 @@ type ItemSubscription = {
|
|
|
156
178
|
type ParametersSubscription = {
|
|
157
179
|
parameters: unknown[]
|
|
158
180
|
cached: unknown
|
|
159
|
-
consumers:
|
|
181
|
+
consumers: ConsumerSubscription[]
|
|
160
182
|
|
|
161
183
|
paused: boolean
|
|
162
184
|
queue: unknown[]
|
|
163
185
|
}
|
|
164
186
|
|
|
187
|
+
type ConsumerSubscription = {
|
|
188
|
+
consumer: (d: unknown) => void
|
|
189
|
+
completed: boolean
|
|
190
|
+
}
|
|
191
|
+
|
|
165
192
|
function getParametersKey(parameters: unknown[]) {
|
|
166
193
|
return safeStringify(parameters)
|
|
167
194
|
}
|
|
@@ -5,7 +5,7 @@ import {WebSocketConnection} from "./WebSocketConnection.js"
|
|
|
5
5
|
import {nanoid} from "nanoid"
|
|
6
6
|
import {createRemote, ServicesWithSubscriptions} from "./remote.js"
|
|
7
7
|
import {ConsumeServicesOptions, RpcClient} from "./index.js"
|
|
8
|
-
import {
|
|
8
|
+
import {withMiddlewares} from "../utils/middleware.js"
|
|
9
9
|
|
|
10
10
|
export class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
11
11
|
constructor(
|
|
@@ -128,12 +128,21 @@ export class RpcClientImpl<S extends Services<S>> implements RpcClient {
|
|
|
128
128
|
consumer(cached)
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// add subscription in pending state to test later if it was unsubscribed during connection wait
|
|
132
|
+
this.remoteSubscriptions.addSubscription(itemName, parameters, consumer)
|
|
133
|
+
|
|
131
134
|
// Needs to be awaited b/c resubscribe will make a 2nd request then.
|
|
132
135
|
// Also, server needs the connection to be established before making a subscription
|
|
133
136
|
await this.connection.connect()
|
|
134
137
|
|
|
135
138
|
try {
|
|
136
|
-
|
|
139
|
+
// check if already unsubscribed
|
|
140
|
+
const sub = this.remoteSubscriptions.getConsumerSubscription(itemName, parameters, consumer)
|
|
141
|
+
if (!sub) return
|
|
142
|
+
|
|
143
|
+
// mark as completed - will resubscribe on reconnects
|
|
144
|
+
sub.completed = true
|
|
145
|
+
|
|
137
146
|
this.remoteSubscriptions.pause(itemName, parameters)
|
|
138
147
|
|
|
139
148
|
const data = await this.invoke(
|
package/tests/subscriptions.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {adelay} from "../src/utils/promises.js"
|
|
|
4
4
|
import {CallOptions, RpcConnectionContext, RpcErrors} from "../src/index.js"
|
|
5
5
|
import {IncomingMessage} from "http"
|
|
6
6
|
import {CLIENT_ID_HEADER} from "../src/rpc.js"
|
|
7
|
+
import WebSocket from "ws"
|
|
7
8
|
|
|
8
9
|
describe("Subscriptions", () => {
|
|
9
10
|
it("subscribe delivers data", async () => {
|
|
@@ -70,8 +71,7 @@ describe("Subscriptions", () => {
|
|
|
70
71
|
const client = await createTestClient<typeof services>()
|
|
71
72
|
|
|
72
73
|
try {
|
|
73
|
-
await client.item.subscribe(() => {
|
|
74
|
-
})
|
|
74
|
+
await client.item.subscribe(() => {})
|
|
75
75
|
assert.fail("Error expected")
|
|
76
76
|
} catch (e: any) {
|
|
77
77
|
assert.equal(e.message, "AA")
|
|
@@ -90,8 +90,7 @@ describe("Subscriptions", () => {
|
|
|
90
90
|
const remote = await createTestClient<typeof services>()
|
|
91
91
|
|
|
92
92
|
remote.item
|
|
93
|
-
.subscribe(() => {
|
|
94
|
-
})
|
|
93
|
+
.subscribe(() => {})
|
|
95
94
|
.catch((e: any) => {
|
|
96
95
|
// ignored
|
|
97
96
|
})
|
|
@@ -280,8 +279,7 @@ describe("Subscriptions", () => {
|
|
|
280
279
|
|
|
281
280
|
const remote = await createTestClient<typeof server>()
|
|
282
281
|
|
|
283
|
-
await remote.testUnsub.item.subscribe(() => {
|
|
284
|
-
})
|
|
282
|
+
await remote.testUnsub.item.subscribe(() => {})
|
|
285
283
|
|
|
286
284
|
assert.equal(1, testServer?._allSubscriptions().length)
|
|
287
285
|
|
|
@@ -340,10 +338,8 @@ describe("Subscriptions", () => {
|
|
|
340
338
|
|
|
341
339
|
const remote = await createTestClient<typeof services>()
|
|
342
340
|
|
|
343
|
-
const sub1 = () => {
|
|
344
|
-
}
|
|
345
|
-
const sub2 = () => {
|
|
346
|
-
}
|
|
341
|
+
const sub1 = () => {}
|
|
342
|
+
const sub2 = () => {}
|
|
347
343
|
|
|
348
344
|
await remote.item.subscribe(sub1)
|
|
349
345
|
await adelay(20)
|
|
@@ -375,8 +371,7 @@ describe("Subscriptions", () => {
|
|
|
375
371
|
|
|
376
372
|
const remote = await createTestClient<typeof services>()
|
|
377
373
|
|
|
378
|
-
const sub = () => {
|
|
379
|
-
}
|
|
374
|
+
const sub = () => {}
|
|
380
375
|
|
|
381
376
|
await remote.item.subscribe(sub)
|
|
382
377
|
await adelay(20)
|
|
@@ -402,10 +397,8 @@ describe("Subscriptions", () => {
|
|
|
402
397
|
|
|
403
398
|
const remote = await createTestClient<typeof services>()
|
|
404
399
|
|
|
405
|
-
const sub1 = () => {
|
|
406
|
-
}
|
|
407
|
-
const sub2 = () => {
|
|
408
|
-
}
|
|
400
|
+
const sub1 = () => {}
|
|
401
|
+
const sub2 = () => {}
|
|
409
402
|
|
|
410
403
|
await remote.item.subscribe(sub1)
|
|
411
404
|
await adelay(20)
|
|
@@ -439,8 +432,7 @@ describe("Subscriptions", () => {
|
|
|
439
432
|
delivered = r
|
|
440
433
|
}
|
|
441
434
|
|
|
442
|
-
const sub2 = () => {
|
|
443
|
-
}
|
|
435
|
+
const sub2 = () => {}
|
|
444
436
|
|
|
445
437
|
await client.test.item.subscribe(sub1)
|
|
446
438
|
|
|
@@ -469,8 +461,7 @@ describe("Subscriptions", () => {
|
|
|
469
461
|
|
|
470
462
|
const client = await createTestClient<typeof services>()
|
|
471
463
|
|
|
472
|
-
const sub = () => {
|
|
473
|
-
}
|
|
464
|
+
const sub = () => {}
|
|
474
465
|
client.item.subscribe(sub)
|
|
475
466
|
|
|
476
467
|
await adelay(10)
|
|
@@ -483,6 +474,49 @@ describe("Subscriptions", () => {
|
|
|
483
474
|
assert.equal(testServer!._allSubscriptions().length, 0)
|
|
484
475
|
})
|
|
485
476
|
|
|
477
|
+
it("unsubscribe while disconnected bug", async () => {
|
|
478
|
+
const services = await startTestServer({
|
|
479
|
+
item: async () => {
|
|
480
|
+
return 1
|
|
481
|
+
},
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
// delay client connection open by 10ms
|
|
485
|
+
let oldAddEL: typeof WebSocket.prototype.addEventListener
|
|
486
|
+
|
|
487
|
+
oldAddEL = WebSocket.prototype.addEventListener
|
|
488
|
+
WebSocket.prototype.addEventListener = function (eventName: any, callback: any) {
|
|
489
|
+
if (eventName == "open") {
|
|
490
|
+
oldAddEL.apply(this, [
|
|
491
|
+
eventName,
|
|
492
|
+
() => {
|
|
493
|
+
setTimeout(callback, 10)
|
|
494
|
+
},
|
|
495
|
+
])
|
|
496
|
+
|
|
497
|
+
return
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return oldAddEL.apply(this, [eventName, callback])
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const client = await createTestClient<typeof services>()
|
|
504
|
+
|
|
505
|
+
const sub = () => {}
|
|
506
|
+
client.item.subscribe(sub)
|
|
507
|
+
|
|
508
|
+
await adelay(10)
|
|
509
|
+
|
|
510
|
+
client.item.unsubscribe(sub)
|
|
511
|
+
|
|
512
|
+
await adelay(40)
|
|
513
|
+
|
|
514
|
+
assert.equal(testClient!._allSubscriptions().length, 0)
|
|
515
|
+
assert.equal(testServer!._allSubscriptions().length, 0)
|
|
516
|
+
|
|
517
|
+
WebSocket.prototype.addEventListener = oldAddEL
|
|
518
|
+
})
|
|
519
|
+
|
|
486
520
|
it("skip unchanged data", async () => {
|
|
487
521
|
const item = {r: "1"}
|
|
488
522
|
|
|
@@ -529,8 +563,7 @@ describe("Subscriptions", () => {
|
|
|
529
563
|
})
|
|
530
564
|
|
|
531
565
|
try {
|
|
532
|
-
await client.test.longOp.subscribe(() => {
|
|
533
|
-
}, new CallOptions({timeout: callTimeout}))
|
|
566
|
+
await client.test.longOp.subscribe(() => {}, new CallOptions({timeout: callTimeout}))
|
|
534
567
|
assert.fail()
|
|
535
568
|
} catch (e: any) {
|
|
536
569
|
assert.equal(e.code, RpcErrors.Timeout)
|