@dxos/rpc 2.19.7-dev.42eb65c2 → 2.19.8-dev.98e1d63e

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/src/rpc.test.ts CHANGED
@@ -9,6 +9,7 @@ import { sleep } from '@dxos/async';
9
9
  import { Stream } from '@dxos/codec-protobuf';
10
10
 
11
11
  import { SerializedRpcError } from './errors';
12
+ import { Any } from './proto/gen/google/protobuf';
12
13
  import { RpcPeer } from './rpc';
13
14
  import { createLinkedPorts } from './testutil';
14
15
 
@@ -17,11 +18,11 @@ describe('RpcPeer', () => {
17
18
  const [alicePort, bobPort] = createLinkedPorts();
18
19
 
19
20
  const alice = new RpcPeer({
20
- messageHandler: async msg => new Uint8Array(),
21
+ messageHandler: async msg => ({}),
21
22
  port: alicePort
22
23
  });
23
24
  const bob = new RpcPeer({
24
- messageHandler: async msg => new Uint8Array(),
25
+ messageHandler: async msg => ({}),
25
26
  port: bobPort
26
27
  });
27
28
 
@@ -38,13 +39,13 @@ describe('RpcPeer', () => {
38
39
  const alice = new RpcPeer({
39
40
  messageHandler: async (method, msg) => {
40
41
  expect(method).toEqual('method');
41
- expect(msg).toEqual(Buffer.from('request'));
42
- return Buffer.from('response');
42
+ expect(msg.value).toEqual(Buffer.from('request'));
43
+ return { value: Buffer.from('response') };
43
44
  },
44
45
  port: alicePort
45
46
  });
46
47
  const bob = new RpcPeer({
47
- messageHandler: async (method, msg) => new Uint8Array(),
48
+ messageHandler: async (method, msg) => ({}),
48
49
  port: bobPort
49
50
  });
50
51
 
@@ -53,8 +54,8 @@ describe('RpcPeer', () => {
53
54
  bob.open()
54
55
  ]);
55
56
 
56
- const response = await bob.call('method', Buffer.from('request'));
57
- expect(response).toEqual(Buffer.from('response'));
57
+ const response = await bob.call('method', { value: Buffer.from('request') });
58
+ expect(response).toEqual({ value: Buffer.from('response') });
58
59
  });
59
60
 
60
61
  test('can send multiple requests', async () => {
@@ -65,7 +66,7 @@ describe('RpcPeer', () => {
65
66
  expect(method).toEqual('method');
66
67
  await sleep(5);
67
68
 
68
- const text = Buffer.from(msg).toString();
69
+ const text = Buffer.from(msg.value!).toString();
69
70
 
70
71
  if (text === 'error') {
71
72
  throw new Error('test error');
@@ -76,7 +77,7 @@ describe('RpcPeer', () => {
76
77
  port: alicePort
77
78
  });
78
79
  const bob = new RpcPeer({
79
- messageHandler: async msg => new Uint8Array(),
80
+ messageHandler: async msg => ({}),
80
81
  port: bobPort
81
82
  });
82
83
 
@@ -85,14 +86,14 @@ describe('RpcPeer', () => {
85
86
  bob.open()
86
87
  ]);
87
88
 
88
- expect(await bob.call('method', Buffer.from('request'))).toEqual(Buffer.from('request'));
89
+ expect((await bob.call('method', { value: Buffer.from('request') })).value).toEqual(Buffer.from('request'));
89
90
 
90
- const parallel1 = bob.call('method', Buffer.from('p1'));
91
- const parallel2 = bob.call('method', Buffer.from('p2'));
92
- const error = bob.call('method', Buffer.from('error'));
91
+ const parallel1 = bob.call('method', { value: Buffer.from('p1') });
92
+ const parallel2 = bob.call('method', { value: Buffer.from('p2') });
93
+ const error = bob.call('method', { value: Buffer.from('error') });
93
94
 
94
- await expect(await parallel1).toEqual(Buffer.from('p1'));
95
- await expect(await parallel2).toEqual(Buffer.from('p2'));
95
+ await expect(await parallel1).toEqual({ value: Buffer.from('p1') });
96
+ await expect(await parallel2).toEqual({ value: Buffer.from('p2') });
96
97
  await expect(error).toBeRejected();
97
98
  });
98
99
 
@@ -111,7 +112,7 @@ describe('RpcPeer', () => {
111
112
  port: alicePort
112
113
  });
113
114
  const bob = new RpcPeer({
114
- messageHandler: async msg => new Uint8Array(),
115
+ messageHandler: async msg => ({}),
115
116
  port: bobPort
116
117
  });
117
118
 
@@ -122,7 +123,7 @@ describe('RpcPeer', () => {
122
123
 
123
124
  let error!: Error;
124
125
  try {
125
- await bob.call('RpcMethodName', Buffer.from('request'));
126
+ await bob.call('RpcMethodName', { value: Buffer.from('request') });
126
127
  } catch (err: any) {
127
128
  error = err;
128
129
  }
@@ -145,7 +146,7 @@ describe('RpcPeer', () => {
145
146
  port: alicePort
146
147
  });
147
148
  const bob = new RpcPeer({
148
- messageHandler: async msg => new Uint8Array(),
149
+ messageHandler: async msg => ({}),
149
150
  port: bobPort
150
151
  });
151
152
 
@@ -154,7 +155,7 @@ describe('RpcPeer', () => {
154
155
  bob.open()
155
156
  ]);
156
157
 
157
- const req = bob.call('method', Buffer.from('request'));
158
+ const req = bob.call('method', { value: Buffer.from('request') });
158
159
  bob.close();
159
160
 
160
161
  await expect(req).toBeRejected();
@@ -172,7 +173,7 @@ describe('RpcPeer', () => {
172
173
  port: alicePort
173
174
  });
174
175
  const bob = new RpcPeer({
175
- messageHandler: async msg => new Uint8Array(),
176
+ messageHandler: async msg => ({}),
176
177
  port: bobPort,
177
178
  timeout: 50
178
179
  });
@@ -183,7 +184,7 @@ describe('RpcPeer', () => {
183
184
  ]);
184
185
 
185
186
  alice.close();
186
- const req = bob.call('method', Buffer.from('request'));
187
+ const req = bob.call('method', { value: Buffer.from('request') });
187
188
 
188
189
  await expect(req).toBeRejected();
189
190
  });
@@ -191,11 +192,11 @@ describe('RpcPeer', () => {
191
192
  test('open waits for the other peer to call open', async () => {
192
193
  const [alicePort, bobPort] = createLinkedPorts();
193
194
  const alice: RpcPeer = new RpcPeer({
194
- messageHandler: async msg => new Uint8Array(),
195
+ messageHandler: async msg => ({}),
195
196
  port: alicePort
196
197
  });
197
198
  const bob = new RpcPeer({
198
- messageHandler: async msg => new Uint8Array(),
199
+ messageHandler: async msg => ({}),
199
200
  port: bobPort
200
201
  });
201
202
 
@@ -219,7 +220,7 @@ describe('RpcPeer', () => {
219
220
 
220
221
  // eslint-disable-next-line prefer-const
221
222
  const alice: RpcPeer = new RpcPeer({
222
- messageHandler: async msg => new Uint8Array(),
223
+ messageHandler: async msg => ({}),
223
224
  port: alicePort
224
225
  });
225
226
  const aliceOpen = alice.open();
@@ -227,7 +228,7 @@ describe('RpcPeer', () => {
227
228
  await sleep(5);
228
229
 
229
230
  const bob = new RpcPeer({
230
- messageHandler: async msg => new Uint8Array(),
231
+ messageHandler: async msg => ({}),
231
232
  port: bobPort
232
233
  });
233
234
 
@@ -243,20 +244,20 @@ describe('RpcPeer', () => {
243
244
  const [alicePort, bobPort] = createLinkedPorts();
244
245
 
245
246
  const alice = new RpcPeer({
246
- messageHandler: async msg => new Uint8Array(),
247
+ messageHandler: async msg => ({}),
247
248
  streamHandler: (method, msg) => {
248
249
  expect(method).toEqual('method');
249
- expect(msg).toEqual(Buffer.from('request'));
250
- return new Stream<Uint8Array>(({ next, close }) => {
251
- next(Buffer.from('res1'));
252
- next(Buffer.from('res2'));
250
+ expect(msg.value!).toEqual(Buffer.from('request'));
251
+ return new Stream<Any>(({ next, close }) => {
252
+ next({ value: Buffer.from('res1') });
253
+ next({ value: Buffer.from('res2') });
253
254
  close();
254
255
  });
255
256
  },
256
257
  port: alicePort
257
258
  });
258
259
  const bob = new RpcPeer({
259
- messageHandler: async msg => new Uint8Array(),
260
+ messageHandler: async msg => ({}),
260
261
  port: bobPort
261
262
  });
262
263
 
@@ -265,12 +266,12 @@ describe('RpcPeer', () => {
265
266
  bob.open()
266
267
  ]);
267
268
 
268
- const stream = await bob.callStream('method', Buffer.from('request'));
269
+ const stream = await bob.callStream('method', { value: Buffer.from('request') });
269
270
  expect(stream).toBeA(Stream);
270
271
 
271
272
  expect(await Stream.consume(stream)).toEqual([
272
- { data: Buffer.from('res1') },
273
- { data: Buffer.from('res2') },
273
+ { data: { value: Buffer.from('res1') } },
274
+ { data: { value: Buffer.from('res2') } },
274
275
  { closed: true }
275
276
  ]);
276
277
  });
@@ -279,18 +280,18 @@ describe('RpcPeer', () => {
279
280
  const [alicePort, bobPort] = createLinkedPorts();
280
281
 
281
282
  const alice = new RpcPeer({
282
- messageHandler: async msg => new Uint8Array(),
283
+ messageHandler: async msg => ({}),
283
284
  streamHandler: (method, msg) => {
284
285
  expect(method).toEqual('method');
285
- expect(msg).toEqual(Buffer.from('request'));
286
- return new Stream<Uint8Array>(({ next, close }) => {
286
+ expect(msg.value).toEqual(Buffer.from('request'));
287
+ return new Stream<Any>(({ next, close }) => {
287
288
  close(new Error('Test error'));
288
289
  });
289
290
  },
290
291
  port: alicePort
291
292
  });
292
293
  const bob = new RpcPeer({
293
- messageHandler: async msg => new Uint8Array(),
294
+ messageHandler: async msg => ({}),
294
295
  port: bobPort
295
296
  });
296
297
 
@@ -299,7 +300,7 @@ describe('RpcPeer', () => {
299
300
  bob.open()
300
301
  ]);
301
302
 
302
- const stream = await bob.callStream('method', Buffer.from('request'));
303
+ const stream = await bob.callStream('method', { value: Buffer.from('request') });
303
304
  expect(stream).toBeA(Stream);
304
305
 
305
306
  const msgs = await Stream.consume(stream);
@@ -315,9 +316,9 @@ describe('RpcPeer', () => {
315
316
 
316
317
  let closeCalled = false;
317
318
  const alice = new RpcPeer({
318
- messageHandler: async msg => new Uint8Array(),
319
+ messageHandler: async msg => ({}),
319
320
  streamHandler: (method, msg) => {
320
- return new Stream<Uint8Array>(({ next, close }) => {
321
+ return new Stream<Any>(({ next, close }) => {
321
322
  return () => {
322
323
  closeCalled = true;
323
324
  };
@@ -327,7 +328,7 @@ describe('RpcPeer', () => {
327
328
  });
328
329
 
329
330
  const bob = new RpcPeer({
330
- messageHandler: async msg => new Uint8Array(),
331
+ messageHandler: async msg => ({}),
331
332
  port: bobPort
332
333
  });
333
334
 
@@ -336,7 +337,7 @@ describe('RpcPeer', () => {
336
337
  bob.open()
337
338
  ]);
338
339
 
339
- const stream = bob.callStream('method', Buffer.from('request'));
340
+ const stream = bob.callStream('method', { value: Buffer.from('request') });
340
341
  stream.close();
341
342
 
342
343
  await sleep(1);
@@ -350,7 +351,7 @@ describe('RpcPeer', () => {
350
351
 
351
352
  // eslint-disable-next-line prefer-const
352
353
  const alice: RpcPeer = new RpcPeer({
353
- messageHandler: async msg => new Uint8Array(),
354
+ messageHandler: async msg => ({}),
354
355
  port: alicePort
355
356
  });
356
357
  const aliceOpen = alice.open();
@@ -358,7 +359,7 @@ describe('RpcPeer', () => {
358
359
  await sleep(5);
359
360
 
360
361
  const bob = new RpcPeer({
361
- messageHandler: async msg => new Uint8Array(),
362
+ messageHandler: async msg => ({}),
362
363
  port: bobPort
363
364
  });
364
365
 
package/src/rpc.ts CHANGED
@@ -12,6 +12,7 @@ import { StackTrace } from '@dxos/debug';
12
12
  import { RpcClosedError, RpcNotOpenError, SerializedRpcError } from './errors';
13
13
  import { schema } from './proto/gen';
14
14
  import { Request, Response, Error as ErrorResponse, RpcMessage } from './proto/gen/dxos/rpc';
15
+ import { Any } from './proto/gen/google/protobuf';
15
16
 
16
17
  const DEFAULT_TIMEOUT = 3000;
17
18
 
@@ -20,8 +21,8 @@ const log = debug('dxos:rpc');
20
21
  type MaybePromise<T> = Promise<T> | T
21
22
 
22
23
  export interface RpcPeerOptions {
23
- messageHandler: (method: string, request: Uint8Array) => MaybePromise<Uint8Array>
24
- streamHandler?: (method: string, request: Uint8Array) => Stream<Uint8Array>
24
+ messageHandler: (method: string, request: Any) => MaybePromise<Any>
25
+ streamHandler?: (method: string, request: Any) => Stream<Any>
25
26
  port: RpcPort,
26
27
  timeout?: number,
27
28
  }
@@ -55,6 +56,8 @@ const codec = schema.getCodecForType('dxos.rpc.RpcMessage');
55
56
  * Both sides must be opened before making any RPC calls.
56
57
  *
57
58
  * Errors inside the handler get serialized and sent to the other side.
59
+ *
60
+ * Inspired by JSON-RPC 2.0 https://www.jsonrpc.org/specification.
58
61
  */
59
62
  export class RpcPeer {
60
63
  private readonly _outgoingRequests = new Map<number, RequestItem>();
@@ -169,7 +172,7 @@ export class RpcPeer {
169
172
  *
170
173
  * Peer should be open before making this call.
171
174
  */
172
- async call (method: string, request: Uint8Array): Promise<Uint8Array> {
175
+ async call (method: string, request: Any): Promise<Any> {
173
176
  if (!this._open) {
174
177
  throw new RpcNotOpenError();
175
178
  }
@@ -223,7 +226,7 @@ export class RpcPeer {
223
226
  *
224
227
  * Peer should be open before making this call.
225
228
  */
226
- callStream (method: string, request: Uint8Array): Stream<Uint8Array> {
229
+ callStream (method: string, request: Any): Stream<Any> {
227
230
  if (!this._open) {
228
231
  throw new RpcNotOpenError();
229
232
  }
package/src/trace.ts ADDED
@@ -0,0 +1,42 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import { Event } from '@dxos/async';
6
+
7
+ import { MessageTrace } from './proto/gen/dxos/rpc';
8
+ import { RpcPort } from './rpc';
9
+
10
+ export class PortTracer {
11
+ readonly message = new Event<MessageTrace>();
12
+
13
+ private readonly _port: RpcPort;
14
+
15
+ constructor (
16
+ private readonly _wrappedPort: RpcPort
17
+ ) {
18
+ this._port = {
19
+ send: (msg: Uint8Array) => {
20
+ this.message.emit({
21
+ direction: MessageTrace.Direction.OUTGOING,
22
+ data: msg
23
+ });
24
+
25
+ return this._wrappedPort.send(msg);
26
+ },
27
+ subscribe: (cb: (msg: Uint8Array) => void) => {
28
+ return this._wrappedPort.subscribe(msg => {
29
+ this.message.emit({
30
+ direction: MessageTrace.Direction.INCOMING,
31
+ data: msg
32
+ });
33
+ cb(msg);
34
+ });
35
+ }
36
+ };
37
+ }
38
+
39
+ public get port () {
40
+ return this._port;
41
+ }
42
+ }
@@ -1,48 +0,0 @@
1
- //
2
- // Copyright 2020 DXOS.org
3
- //
4
-
5
- syntax = "proto3";
6
-
7
- package dxos.rpc;
8
-
9
- message RpcMessage {
10
- oneof content {
11
- Request request = 1;
12
- Response response = 2;
13
-
14
- /// Means that the node is open to receiving requests. Second stage of the hasnshake protocol.
15
- bool open = 3;
16
-
17
- StreamClose streamClose = 4;
18
- }
19
- }
20
-
21
- message Request {
22
- int32 id = 1;
23
- string method = 2;
24
- bytes payload = 3;
25
- bool stream = 4;
26
- }
27
-
28
- message Response {
29
- int32 id = 1;
30
- oneof content {
31
- bytes payload = 2;
32
- Error error = 3;
33
- // Sent when stream is closed without an error.
34
- bool close = 4;
35
- }
36
- }
37
-
38
- // Sent by client to end the streaming response.
39
- message StreamClose {
40
- int32 id = 1;
41
- }
42
-
43
-
44
- message Error {
45
- string name = 1;
46
- string message = 2;
47
- string stack = 3;
48
- }