@dxos/rpc 2.33.9-dev.a6069cb4 → 2.33.9-dev.bba8fc00
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/dist/src/proto/gen/dxos/rpc/test.d.ts +32 -4
- package/dist/src/proto/gen/dxos/rpc/test.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/rpc.d.ts +48 -8
- package/dist/src/proto/gen/dxos/rpc.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/rpc.js +4 -0
- package/dist/src/proto/gen/dxos/rpc.js.map +1 -1
- package/dist/src/proto/gen/google/protobuf.d.ts +2 -2
- package/dist/src/proto/gen/google/protobuf.d.ts.map +1 -1
- package/dist/src/proto/gen/index.d.ts.map +1 -1
- package/dist/src/proto/gen/index.js +1 -1
- package/dist/src/proto/gen/index.js.map +1 -1
- package/dist/src/rpc.d.ts.map +1 -1
- package/dist/src/rpc.js +26 -6
- package/dist/src/rpc.js.map +1 -1
- package/dist/src/rpc.test.js +71 -45
- package/dist/src/rpc.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/proto/gen/dxos/rpc/test.ts +32 -4
- package/src/proto/gen/dxos/rpc.ts +48 -8
- package/src/proto/gen/google/protobuf.ts +2 -2
- package/src/proto/gen/index.ts +1 -1
- package/src/rpc.test.ts +76 -45
- package/src/rpc.ts +32 -8
package/src/rpc.test.ts
CHANGED
@@ -13,17 +13,22 @@ import { Any } from './proto/gen/google/protobuf';
|
|
13
13
|
import { RpcPeer } from './rpc';
|
14
14
|
import { createLinkedPorts } from './testutil';
|
15
15
|
|
16
|
+
const createPayload = (value = ''): Any => ({
|
17
|
+
type_url: '',
|
18
|
+
value: Buffer.from(value)
|
19
|
+
});
|
20
|
+
|
16
21
|
describe('RpcPeer', () => {
|
17
22
|
describe('handshake', () => {
|
18
23
|
test('can open', async () => {
|
19
24
|
const [alicePort, bobPort] = createLinkedPorts();
|
20
25
|
|
21
26
|
const alice = new RpcPeer({
|
22
|
-
messageHandler: async msg => (
|
27
|
+
messageHandler: async msg => createPayload(),
|
23
28
|
port: alicePort
|
24
29
|
});
|
25
30
|
const bob = new RpcPeer({
|
26
|
-
messageHandler: async msg => (
|
31
|
+
messageHandler: async msg => createPayload(),
|
27
32
|
port: bobPort
|
28
33
|
});
|
29
34
|
|
@@ -36,11 +41,11 @@ describe('RpcPeer', () => {
|
|
36
41
|
test('open waits for the other peer to call open', async () => {
|
37
42
|
const [alicePort, bobPort] = createLinkedPorts();
|
38
43
|
const alice: RpcPeer = new RpcPeer({
|
39
|
-
messageHandler: async msg => (
|
44
|
+
messageHandler: async msg => createPayload(),
|
40
45
|
port: alicePort
|
41
46
|
});
|
42
47
|
const bob = new RpcPeer({
|
43
|
-
messageHandler: async msg => (
|
48
|
+
messageHandler: async msg => createPayload(),
|
44
49
|
port: bobPort
|
45
50
|
});
|
46
51
|
|
@@ -64,7 +69,7 @@ describe('RpcPeer', () => {
|
|
64
69
|
const [alicePort, bobPort] = createLinkedPorts();
|
65
70
|
|
66
71
|
const alice: RpcPeer = new RpcPeer({
|
67
|
-
messageHandler: async msg => (
|
72
|
+
messageHandler: async msg => createPayload(),
|
68
73
|
port: alicePort
|
69
74
|
});
|
70
75
|
const aliceOpen = alice.open();
|
@@ -72,7 +77,7 @@ describe('RpcPeer', () => {
|
|
72
77
|
await sleep(5);
|
73
78
|
|
74
79
|
const bob = new RpcPeer({
|
75
|
-
messageHandler: async msg => (
|
80
|
+
messageHandler: async msg => createPayload(),
|
76
81
|
port: bobPort
|
77
82
|
});
|
78
83
|
|
@@ -88,7 +93,7 @@ describe('RpcPeer', () => {
|
|
88
93
|
let portOpen = false;
|
89
94
|
|
90
95
|
const alice: RpcPeer = new RpcPeer({
|
91
|
-
messageHandler: async msg => (
|
96
|
+
messageHandler: async msg => createPayload(),
|
92
97
|
port: {
|
93
98
|
send: msg => {
|
94
99
|
portOpen && alicePort.send(msg);
|
@@ -98,7 +103,7 @@ describe('RpcPeer', () => {
|
|
98
103
|
});
|
99
104
|
|
100
105
|
const bob = new RpcPeer({
|
101
|
-
messageHandler: async msg => (
|
106
|
+
messageHandler: async msg => createPayload(),
|
102
107
|
port: {
|
103
108
|
send: msg => {
|
104
109
|
portOpen && bobPort.send(msg);
|
@@ -123,7 +128,7 @@ describe('RpcPeer', () => {
|
|
123
128
|
const [alicePort, bobPort] = createLinkedPorts();
|
124
129
|
|
125
130
|
const alice: RpcPeer = new RpcPeer({
|
126
|
-
messageHandler: async msg => (
|
131
|
+
messageHandler: async msg => createPayload(),
|
127
132
|
port: {
|
128
133
|
send: msg => { },
|
129
134
|
subscribe: alicePort.subscribe
|
@@ -131,7 +136,7 @@ describe('RpcPeer', () => {
|
|
131
136
|
});
|
132
137
|
|
133
138
|
const bob = new RpcPeer({
|
134
|
-
messageHandler: async msg => (
|
139
|
+
messageHandler: async msg => createPayload(),
|
135
140
|
port: bobPort
|
136
141
|
});
|
137
142
|
|
@@ -160,12 +165,12 @@ describe('RpcPeer', () => {
|
|
160
165
|
messageHandler: async (method, msg) => {
|
161
166
|
expect(method).toEqual('method');
|
162
167
|
expect(msg.value).toEqual(Buffer.from('request'));
|
163
|
-
return
|
168
|
+
return createPayload('response');
|
164
169
|
},
|
165
170
|
port: alicePort
|
166
171
|
});
|
167
172
|
const bob = new RpcPeer({
|
168
|
-
messageHandler: async (method, msg) => (
|
173
|
+
messageHandler: async (method, msg) => createPayload(),
|
169
174
|
port: bobPort
|
170
175
|
});
|
171
176
|
|
@@ -174,8 +179,8 @@ describe('RpcPeer', () => {
|
|
174
179
|
bob.open()
|
175
180
|
]);
|
176
181
|
|
177
|
-
const response = await bob.call('method',
|
178
|
-
expect(response).toEqual(
|
182
|
+
const response = await bob.call('method', createPayload('request'));
|
183
|
+
expect(response).toEqual(createPayload('response'));
|
179
184
|
});
|
180
185
|
|
181
186
|
test('can send multiple requests', async () => {
|
@@ -197,7 +202,7 @@ describe('RpcPeer', () => {
|
|
197
202
|
port: alicePort
|
198
203
|
});
|
199
204
|
const bob = new RpcPeer({
|
200
|
-
messageHandler: async msg => (
|
205
|
+
messageHandler: async msg => createPayload(),
|
201
206
|
port: bobPort
|
202
207
|
});
|
203
208
|
|
@@ -206,14 +211,14 @@ describe('RpcPeer', () => {
|
|
206
211
|
bob.open()
|
207
212
|
]);
|
208
213
|
|
209
|
-
expect((await bob.call('method',
|
214
|
+
expect((await bob.call('method', createPayload('request'))).value).toEqual(Buffer.from('request'));
|
210
215
|
|
211
|
-
const parallel1 = bob.call('method',
|
212
|
-
const parallel2 = bob.call('method',
|
213
|
-
const error = bob.call('method',
|
216
|
+
const parallel1 = bob.call('method', createPayload('p1'));
|
217
|
+
const parallel2 = bob.call('method', createPayload('p2'));
|
218
|
+
const error = bob.call('method', createPayload('error'));
|
214
219
|
|
215
|
-
await expect(await parallel1).toEqual(
|
216
|
-
await expect(await parallel2).toEqual(
|
220
|
+
await expect(await parallel1).toEqual(createPayload('p1'));
|
221
|
+
await expect(await parallel2).toEqual(createPayload('p2'));
|
217
222
|
await expect(error).toBeRejected();
|
218
223
|
});
|
219
224
|
|
@@ -232,7 +237,7 @@ describe('RpcPeer', () => {
|
|
232
237
|
port: alicePort
|
233
238
|
});
|
234
239
|
const bob = new RpcPeer({
|
235
|
-
messageHandler: async msg => (
|
240
|
+
messageHandler: async msg => createPayload(),
|
236
241
|
port: bobPort
|
237
242
|
});
|
238
243
|
|
@@ -243,7 +248,7 @@ describe('RpcPeer', () => {
|
|
243
248
|
|
244
249
|
let error!: Error;
|
245
250
|
try {
|
246
|
-
await bob.call('RpcMethodName',
|
251
|
+
await bob.call('RpcMethodName', createPayload('request'));
|
247
252
|
} catch (err: any) {
|
248
253
|
error = err;
|
249
254
|
}
|
@@ -266,7 +271,7 @@ describe('RpcPeer', () => {
|
|
266
271
|
port: alicePort
|
267
272
|
});
|
268
273
|
const bob = new RpcPeer({
|
269
|
-
messageHandler: async msg => (
|
274
|
+
messageHandler: async msg => createPayload(),
|
270
275
|
port: bobPort
|
271
276
|
});
|
272
277
|
|
@@ -275,7 +280,7 @@ describe('RpcPeer', () => {
|
|
275
280
|
bob.open()
|
276
281
|
]);
|
277
282
|
|
278
|
-
const req = bob.call('method',
|
283
|
+
const req = bob.call('method', createPayload('request'));
|
279
284
|
bob.close();
|
280
285
|
|
281
286
|
await expect(req).toBeRejected();
|
@@ -293,7 +298,7 @@ describe('RpcPeer', () => {
|
|
293
298
|
port: alicePort
|
294
299
|
});
|
295
300
|
const bob = new RpcPeer({
|
296
|
-
messageHandler: async msg => (
|
301
|
+
messageHandler: async msg => createPayload(),
|
297
302
|
port: bobPort,
|
298
303
|
timeout: 50
|
299
304
|
});
|
@@ -304,8 +309,34 @@ describe('RpcPeer', () => {
|
|
304
309
|
]);
|
305
310
|
|
306
311
|
alice.close();
|
307
|
-
const req = bob.call('method',
|
312
|
+
const req = bob.call('method', createPayload('request'));
|
313
|
+
|
314
|
+
await expect(req).toBeRejected();
|
315
|
+
});
|
316
|
+
|
317
|
+
test('requests failing on timeout', async () => {
|
318
|
+
const [alicePort, bobPort] = createLinkedPorts();
|
319
|
+
|
320
|
+
const alice: RpcPeer = new RpcPeer({
|
321
|
+
messageHandler: async (method, msg) => {
|
322
|
+
expect(method).toEqual('method');
|
323
|
+
await sleep(50);
|
324
|
+
return msg;
|
325
|
+
},
|
326
|
+
port: alicePort
|
327
|
+
});
|
328
|
+
const bob = new RpcPeer({
|
329
|
+
messageHandler: async msg => createPayload(),
|
330
|
+
port: bobPort,
|
331
|
+
timeout: 10
|
332
|
+
});
|
333
|
+
|
334
|
+
await Promise.all([
|
335
|
+
alice.open(),
|
336
|
+
bob.open()
|
337
|
+
]);
|
308
338
|
|
339
|
+
const req = bob.call('method', createPayload('request'));
|
309
340
|
await expect(req).toBeRejected();
|
310
341
|
});
|
311
342
|
|
@@ -316,20 +347,20 @@ describe('RpcPeer', () => {
|
|
316
347
|
const [alicePort, bobPort] = createLinkedPorts();
|
317
348
|
|
318
349
|
const alice = new RpcPeer({
|
319
|
-
messageHandler: async msg => (
|
350
|
+
messageHandler: async msg => createPayload(),
|
320
351
|
streamHandler: (method, msg) => {
|
321
352
|
expect(method).toEqual('method');
|
322
353
|
expect(msg.value!).toEqual(Buffer.from('request'));
|
323
354
|
return new Stream<Any>(({ next, close }) => {
|
324
|
-
next(
|
325
|
-
next(
|
355
|
+
next(createPayload('res1'));
|
356
|
+
next(createPayload('res2'));
|
326
357
|
close();
|
327
358
|
});
|
328
359
|
},
|
329
360
|
port: alicePort
|
330
361
|
});
|
331
362
|
const bob = new RpcPeer({
|
332
|
-
messageHandler: async msg => (
|
363
|
+
messageHandler: async msg => createPayload(),
|
333
364
|
port: bobPort
|
334
365
|
});
|
335
366
|
|
@@ -338,12 +369,12 @@ describe('RpcPeer', () => {
|
|
338
369
|
bob.open()
|
339
370
|
]);
|
340
371
|
|
341
|
-
const stream = await bob.callStream('method',
|
372
|
+
const stream = await bob.callStream('method', createPayload('request'));
|
342
373
|
expect(stream).toBeA(Stream);
|
343
374
|
|
344
375
|
expect(await Stream.consume(stream)).toEqual([
|
345
|
-
{ data:
|
346
|
-
{ data:
|
376
|
+
{ data: createPayload('res1') },
|
377
|
+
{ data: createPayload('res2') },
|
347
378
|
{ closed: true }
|
348
379
|
]);
|
349
380
|
});
|
@@ -352,7 +383,7 @@ describe('RpcPeer', () => {
|
|
352
383
|
const [alicePort, bobPort] = createLinkedPorts();
|
353
384
|
|
354
385
|
const alice = new RpcPeer({
|
355
|
-
messageHandler: async msg => (
|
386
|
+
messageHandler: async msg => createPayload(),
|
356
387
|
streamHandler: (method, msg) => {
|
357
388
|
expect(method).toEqual('method');
|
358
389
|
expect(msg.value).toEqual(Buffer.from('request'));
|
@@ -363,7 +394,7 @@ describe('RpcPeer', () => {
|
|
363
394
|
port: alicePort
|
364
395
|
});
|
365
396
|
const bob = new RpcPeer({
|
366
|
-
messageHandler: async msg => (
|
397
|
+
messageHandler: async msg => createPayload(),
|
367
398
|
port: bobPort
|
368
399
|
});
|
369
400
|
|
@@ -372,7 +403,7 @@ describe('RpcPeer', () => {
|
|
372
403
|
bob.open()
|
373
404
|
]);
|
374
405
|
|
375
|
-
const stream = await bob.callStream('method',
|
406
|
+
const stream = await bob.callStream('method', createPayload('request'));
|
376
407
|
expect(stream).toBeA(Stream);
|
377
408
|
|
378
409
|
const msgs = await Stream.consume(stream);
|
@@ -388,7 +419,7 @@ describe('RpcPeer', () => {
|
|
388
419
|
|
389
420
|
let closeCalled = false;
|
390
421
|
const alice = new RpcPeer({
|
391
|
-
messageHandler: async msg => (
|
422
|
+
messageHandler: async msg => createPayload(),
|
392
423
|
streamHandler: (method, msg) => new Stream<Any>(({ next, close }) => () => {
|
393
424
|
closeCalled = true;
|
394
425
|
}),
|
@@ -396,7 +427,7 @@ describe('RpcPeer', () => {
|
|
396
427
|
});
|
397
428
|
|
398
429
|
const bob = new RpcPeer({
|
399
|
-
messageHandler: async msg => (
|
430
|
+
messageHandler: async msg => createPayload(),
|
400
431
|
port: bobPort
|
401
432
|
});
|
402
433
|
|
@@ -405,7 +436,7 @@ describe('RpcPeer', () => {
|
|
405
436
|
bob.open()
|
406
437
|
]);
|
407
438
|
|
408
|
-
const stream = bob.callStream('method',
|
439
|
+
const stream = bob.callStream('method', createPayload('request'));
|
409
440
|
stream.close();
|
410
441
|
|
411
442
|
await sleep(1);
|
@@ -419,7 +450,7 @@ describe('RpcPeer', () => {
|
|
419
450
|
const [alicePort] = createLinkedPorts();
|
420
451
|
|
421
452
|
const alice = new RpcPeer({
|
422
|
-
messageHandler: async msg => (
|
453
|
+
messageHandler: async msg => createPayload(),
|
423
454
|
port: alicePort,
|
424
455
|
noHandshake: true
|
425
456
|
});
|
@@ -434,13 +465,13 @@ describe('RpcPeer', () => {
|
|
434
465
|
messageHandler: async (method, msg) => {
|
435
466
|
expect(method).toEqual('method');
|
436
467
|
expect(msg.value).toEqual(Buffer.from('request'));
|
437
|
-
return
|
468
|
+
return createPayload('response');
|
438
469
|
},
|
439
470
|
port: alicePort,
|
440
471
|
noHandshake: true
|
441
472
|
});
|
442
473
|
const bob = new RpcPeer({
|
443
|
-
messageHandler: async (method, msg) => (
|
474
|
+
messageHandler: async (method, msg) => createPayload(),
|
444
475
|
port: bobPort,
|
445
476
|
noHandshake: true
|
446
477
|
});
|
@@ -448,8 +479,8 @@ describe('RpcPeer', () => {
|
|
448
479
|
await alice.open();
|
449
480
|
await bob.open();
|
450
481
|
|
451
|
-
const response = await bob.call('method',
|
452
|
-
expect(response).toEqual(
|
482
|
+
const response = await bob.call('method', createPayload('request'));
|
483
|
+
expect(response).toEqual(createPayload('response'));
|
453
484
|
});
|
454
485
|
});
|
455
486
|
});
|
package/src/rpc.ts
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
import debug from 'debug';
|
6
6
|
import assert from 'node:assert';
|
7
7
|
|
8
|
-
import {
|
8
|
+
import { synchronized, Trigger } from '@dxos/async';
|
9
9
|
import { Stream } from '@dxos/codec-protobuf';
|
10
10
|
import { StackTrace } from '@dxos/debug';
|
11
11
|
import { exponentialBackoffInterval } from '@dxos/util';
|
@@ -143,7 +143,12 @@ export class RpcPeer {
|
|
143
143
|
if (decoded.request) {
|
144
144
|
if (!this._open) {
|
145
145
|
log('Received request while not open.');
|
146
|
-
await this._sendMessage({
|
146
|
+
await this._sendMessage({
|
147
|
+
response: {
|
148
|
+
id: decoded.request.id,
|
149
|
+
error: encodeError(new RpcClosedError())
|
150
|
+
}
|
151
|
+
});
|
147
152
|
return;
|
148
153
|
}
|
149
154
|
|
@@ -240,20 +245,18 @@ export class RpcPeer {
|
|
240
245
|
// Here we're attaching a dummy handler that will not interfere with error handling to avoid that warning.
|
241
246
|
promise.catch(() => {});
|
242
247
|
|
243
|
-
|
248
|
+
void this._sendMessage({
|
244
249
|
request: {
|
245
250
|
id,
|
246
251
|
method,
|
247
|
-
payload: request
|
252
|
+
payload: request,
|
253
|
+
stream: false
|
248
254
|
}
|
249
255
|
});
|
250
256
|
|
251
|
-
const timeoutPromise = sleep(this._options.timeout ?? DEFAULT_TIMEOUT).then(() => Promise.reject(new Error('Timeout')));
|
252
|
-
timeoutPromise.catch(() => {}); // Mute the promise.
|
253
|
-
|
254
257
|
let response: Response;
|
255
258
|
try {
|
256
|
-
response = await Promise.race([promise,
|
259
|
+
response = await Promise.race([promise, createTimeoutPromise(this._options.timeout ?? DEFAULT_TIMEOUT, new Error(`RPC call timed out: ${method}`))]);
|
257
260
|
} catch (err) {
|
258
261
|
if (err instanceof RpcClosedError) {
|
259
262
|
// Rethrow the error here to have the correct stack-trace.
|
@@ -410,3 +413,24 @@ const encodeError = (err: any): ErrorResponse => {
|
|
410
413
|
};
|
411
414
|
}
|
412
415
|
};
|
416
|
+
|
417
|
+
/**
|
418
|
+
* Creates a promise that will be rejected after a certain timeout.
|
419
|
+
* The promise will never cause unhandledPromiseRejection.
|
420
|
+
* The timeout will not block the Node.JS process from exiting.
|
421
|
+
*/
|
422
|
+
const createTimeoutPromise = (timeout: number, error: Error) => {
|
423
|
+
const timeoutPromise = new Promise<any>((resolve, reject) => {
|
424
|
+
const timeoutId = setTimeout(
|
425
|
+
() => reject(error),
|
426
|
+
timeout
|
427
|
+
);
|
428
|
+
|
429
|
+
// `unref` prevents the timeout from blocking Node.JS process from exiting. Not available in browsers.
|
430
|
+
if ('unref' in timeoutId) {
|
431
|
+
timeoutId.unref();
|
432
|
+
}
|
433
|
+
});
|
434
|
+
timeoutPromise.catch(() => {}); // Mute the promise.
|
435
|
+
return timeoutPromise;
|
436
|
+
};
|