@dxos/messaging 0.5.8 → 0.5.9-main.079a532

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.
Files changed (44) hide show
  1. package/dist/lib/browser/index.mjs +812 -559
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +778 -545
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/types/src/messenger-monitor.d.ts +8 -0
  8. package/dist/types/src/messenger-monitor.d.ts.map +1 -0
  9. package/dist/types/src/messenger.d.ts +1 -0
  10. package/dist/types/src/messenger.d.ts.map +1 -1
  11. package/dist/types/src/signal-client/signal-client-monitor.d.ts +30 -0
  12. package/dist/types/src/signal-client/signal-client-monitor.d.ts.map +1 -0
  13. package/dist/types/src/signal-client/signal-client.d.ts +25 -50
  14. package/dist/types/src/signal-client/signal-client.d.ts.map +1 -1
  15. package/dist/types/src/signal-client/signal-local-state.d.ts +46 -0
  16. package/dist/types/src/signal-client/signal-local-state.d.ts.map +1 -0
  17. package/dist/types/src/signal-client/signal-rpc-client-monitor.d.ts +6 -0
  18. package/dist/types/src/signal-client/signal-rpc-client-monitor.d.ts.map +1 -0
  19. package/dist/types/src/signal-client/signal-rpc-client.d.ts +4 -2
  20. package/dist/types/src/signal-client/signal-rpc-client.d.ts.map +1 -1
  21. package/dist/types/src/signal-manager/memory-signal-manager.d.ts +0 -2
  22. package/dist/types/src/signal-manager/memory-signal-manager.d.ts.map +1 -1
  23. package/dist/types/src/signal-manager/signal-manager.d.ts +0 -2
  24. package/dist/types/src/signal-manager/signal-manager.d.ts.map +1 -1
  25. package/dist/types/src/signal-manager/websocket-signal-manager-monitor.d.ts +8 -0
  26. package/dist/types/src/signal-manager/websocket-signal-manager-monitor.d.ts.map +1 -0
  27. package/dist/types/src/signal-manager/websocket-signal-manager.d.ts +7 -3
  28. package/dist/types/src/signal-manager/websocket-signal-manager.d.ts.map +1 -1
  29. package/dist/types/src/signal-methods.d.ts +6 -4
  30. package/dist/types/src/signal-methods.d.ts.map +1 -1
  31. package/package.json +13 -12
  32. package/src/messenger-monitor.ts +20 -0
  33. package/src/messenger.ts +16 -5
  34. package/src/signal-client/signal-client-monitor.ts +111 -0
  35. package/src/signal-client/signal-client.test.ts +111 -259
  36. package/src/signal-client/signal-client.ts +141 -252
  37. package/src/signal-client/signal-local-state.ts +156 -0
  38. package/src/signal-client/signal-rpc-client-monitor.ts +15 -0
  39. package/src/signal-client/signal-rpc-client.ts +38 -21
  40. package/src/signal-manager/memory-signal-manager.ts +0 -2
  41. package/src/signal-manager/signal-manager.ts +0 -3
  42. package/src/signal-manager/websocket-signal-manager-monitor.ts +20 -0
  43. package/src/signal-manager/websocket-signal-manager.ts +48 -26
  44. package/src/signal-methods.ts +7 -4
@@ -2,14 +2,16 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import { expect, mockFn } from 'earljs';
5
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
6
+ import { expect } from 'earljs';
6
7
 
7
- import { sleep, Event, Trigger, asyncTimeout } from '@dxos/async';
8
- import { type Any, type TaggedType } from '@dxos/codec-protobuf';
8
+ import { Trigger, asyncTimeout, waitForCondition } from '@dxos/async';
9
+ import { type TaggedType } from '@dxos/codec-protobuf';
9
10
  import { PublicKey } from '@dxos/keys';
10
11
  import { type TYPES } from '@dxos/protocols';
11
12
  import { runTestSignalServer, type SignalServerRunner } from '@dxos/signal';
12
13
  import { afterAll, beforeAll, describe, test, afterTest } from '@dxos/test';
14
+ import { ComplexSet, range } from '@dxos/util';
13
15
 
14
16
  import { SignalClient } from './signal-client';
15
17
 
@@ -22,307 +24,157 @@ const PAYLOAD: TaggedType<TYPES, 'google.protobuf.Any'> = {
22
24
  describe('SignalClient', () => {
23
25
  let broker1: SignalServerRunner;
24
26
 
25
- let broker2: SignalServerRunner;
26
-
27
27
  beforeAll(async () => {
28
28
  broker1 = await runTestSignalServer();
29
- // broker2 = await await createTestBroker(signalApiPort2);
30
29
  });
31
30
 
32
- afterAll(() => {
33
- void broker1.stop();
34
- // code await broker2.stop();
31
+ afterAll(async () => {
32
+ await broker1.stop();
35
33
  });
36
34
 
37
- const waitForSubscription = async (signal: SignalClient, peerId: PublicKey) => {
38
- await asyncTimeout(
39
- signal._reconciled.waitForCondition(() => signal._messageStreams.has(peerId)),
40
- 500,
41
- );
42
- };
43
-
44
35
  test('message between 2 clients', async () => {
45
- const peer1 = PublicKey.random();
46
- const peer2 = PublicKey.random();
47
- const received = new Trigger<any>();
48
- const api1 = new SignalClient(
49
- broker1.url(),
50
- async (msg) => {
51
- received.wake(msg);
52
- },
53
- async () => {},
54
- );
55
- void api1.open();
56
- afterTest(() => api1.close());
57
- const api2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
58
- void api2.open();
59
- afterTest(() => api2.close());
60
-
61
- await api1.subscribeMessages(peer1);
62
- await waitForSubscription(api1, peer1);
63
-
64
- const message = {
65
- author: peer2,
66
- recipient: peer1,
67
- payload: PAYLOAD,
68
- };
69
- await api2.sendMessage(message);
70
- expect(await received.wait()).toEqual(message);
71
- })
72
- .timeout(500)
73
- .retries(2);
36
+ const [peer1, peer2] = setupPeers({ peerCount: 2 });
37
+
38
+ await peer1.client.subscribeMessages(peer1.id);
39
+ await waitForSubscription(peer1.client, peer1.id);
40
+
41
+ const message = createMessage(peer2, peer1);
42
+ await peer2.client.sendMessage(message);
43
+ expect(await peer1.waitForNextMessage()).toEqual(message);
44
+ }).timeout(500);
74
45
 
75
46
  test('join', async () => {
76
47
  const topic = PublicKey.random();
77
- const peer1 = PublicKey.random();
78
- const peer2 = PublicKey.random();
79
-
80
- const trigger1 = new Trigger();
81
- const api1 = new SignalClient(
82
- broker1.url(),
83
- async () => {},
84
- async ({ swarmEvent }) => {
85
- if (!!swarmEvent.peerAvailable && peer2.equals(swarmEvent.peerAvailable.peer)) {
86
- trigger1.wake();
87
- }
88
- },
89
- );
90
- void api1.open();
91
- afterTest(() => api1.close());
92
-
93
- const trigger2 = new Trigger();
94
- const api2 = new SignalClient(
95
- broker1.url(),
96
- async () => {},
97
- async ({ swarmEvent }) => {
98
- if (!!swarmEvent.peerAvailable && peer1.equals(swarmEvent.peerAvailable.peer)) {
99
- trigger2.wake();
100
- }
101
- },
102
- );
103
- void api2.open();
104
- afterTest(() => api2.close());
105
- await api1.join({ topic, peerId: peer1 });
106
- await api2.join({ topic, peerId: peer2 });
48
+ const [peer1, peer2] = setupPeers({ peerCount: 2 });
107
49
 
108
- await trigger1.wait();
109
- await trigger2.wait();
110
- })
111
- .timeout(500)
112
- .retries(2);
50
+ await peer1.client.join({ topic, peerId: peer1.id });
51
+ await peer2.client.join({ topic, peerId: peer2.id });
113
52
 
114
- test('signal to self', async () => {
115
- const peer1 = PublicKey.random();
116
- const peer2 = PublicKey.random();
117
- const received = new Trigger<any>();
118
- const api1 = new SignalClient(
119
- broker1.url(),
120
- async (msg) => {
121
- received.wake(msg);
122
- },
123
- async () => {},
124
- );
125
- void api1.open();
126
- afterTest(() => api1.close());
53
+ await peer1.waitForPeer(peer2.id);
54
+ await peer2.waitForPeer(peer1.id);
55
+ }).timeout(500);
127
56
 
128
- await api1.subscribeMessages(peer1);
129
- await waitForSubscription(api1, peer1);
57
+ test('signal to self', async () => {
58
+ const [peer1, peer2] = setupPeers({ peerCount: 2 });
130
59
 
131
- const message = {
132
- author: peer2,
133
- recipient: peer1,
134
- payload: PAYLOAD,
135
- };
136
- await api1.sendMessage(message);
60
+ await peer1.client.subscribeMessages(peer1.id);
61
+ await waitForSubscription(peer1.client, peer1.id);
137
62
 
138
- expect(await received.wait()).toEqual(message);
63
+ const message = createMessage(peer2, peer1);
64
+ await peer1.client.sendMessage(message);
65
+ expect(await peer1.waitForNextMessage()).toEqual(message);
139
66
  }).timeout(500);
140
67
 
141
68
  test('unsubscribe from messages', async () => {
142
- const peer1 = PublicKey.random();
143
- const peer2 = PublicKey.random();
144
-
145
- const received = new Event<any>();
146
- const client1 = new SignalClient(
147
- broker1.url(),
148
- async (msg) => {
149
- received.emit(msg);
150
- },
151
- async () => {},
152
- );
153
- void client1.open();
154
- afterTest(() => client1.close());
69
+ const [peer1, peer2] = setupPeers({ peerCount: 2 });
155
70
 
156
- const client2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
157
- void client2.open();
158
- afterTest(() => client2.close());
71
+ await peer1.client.subscribeMessages(peer1.id);
72
+ await peer2.client.subscribeMessages(peer2.id);
73
+ await waitForSubscription(peer1.client, peer1.id);
159
74
 
160
- await client1.subscribeMessages(peer1);
161
- await client2.subscribeMessages(peer2);
162
- await waitForSubscription(client2, peer2);
163
-
164
- const message = {
165
- author: peer2,
166
- recipient: peer1,
167
- payload: PAYLOAD,
168
- };
75
+ const message = createMessage(peer2, peer1);
169
76
 
170
77
  {
171
- const promise = received.waitFor((msg) => {
172
- expect(msg).toEqual(message);
173
- return true;
174
- });
175
- await client2.sendMessage(message);
176
- await promise;
78
+ await peer2.client.sendMessage(message);
79
+ expect(await peer1.waitForNextMessage()).toEqual(message);
177
80
  }
178
81
 
179
82
  // unsubscribing.
180
- await client1.unsubscribeMessages(peer1);
83
+ await peer1.client.unsubscribeMessages(peer1.id);
181
84
 
182
85
  {
183
- const promise = received.waitFor((msg) => {
184
- expect(msg).toEqual(message);
185
- return true;
186
- });
187
- await client2.sendMessage(message);
188
- await expect(asyncTimeout(promise, 200)).toBeRejected();
86
+ await peer2.client.sendMessage(message);
87
+ await expect(peer1.waitForNextMessage({ timeout: 200 })).toBeRejected();
189
88
  }
190
- })
191
- .timeout(1_000)
192
- .retries(2);
89
+ }).timeout(1_500);
193
90
 
194
91
  test('signal after re-entrance', async () => {
195
- const peer1 = PublicKey.random();
196
- const peer2 = PublicKey.random();
197
-
198
- const received = new Event<any>();
199
- const client1 = new SignalClient(
200
- broker1.url(),
201
- async (msg) => {
202
- received.emit(msg);
203
- },
204
- async () => {},
205
- );
206
- void client1.open();
207
- afterTest(() => client1.close());
92
+ const [peer1, peer2] = setupPeers({ peerCount: 2 });
208
93
 
209
- const client2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
210
- void client2.open();
211
- afterTest(() => client2.close());
212
-
213
- const message = {
214
- author: peer2,
215
- recipient: peer1,
216
- payload: PAYLOAD,
217
- };
94
+ const message = createMessage(peer2, peer1);
218
95
 
219
- await client1.subscribeMessages(peer1);
220
- await waitForSubscription(client1, peer1);
96
+ await peer1.client.subscribeMessages(peer1.id);
97
+ await waitForSubscription(peer1.client, peer1.id);
221
98
 
222
99
  {
223
- const promise = received.waitFor((msg) => {
224
- expect(msg).toEqual(message);
225
- return true;
226
- });
227
- await client2.sendMessage(message);
228
- await promise;
100
+ await peer2.client.sendMessage(message);
101
+ expect(await peer1.waitForNextMessage()).toEqual(message);
229
102
  }
230
103
 
231
104
  //
232
105
  // close and reopen first client
233
106
  //
234
107
 
235
- await client1.close();
236
- void client1.open();
237
- await waitForSubscription(client1, peer1);
108
+ await peer1.client.close();
109
+ await peer1.client.open();
110
+ await waitForSubscription(peer1.client, peer1.id);
238
111
 
239
112
  {
240
- const promise = received.waitFor((msg) => {
241
- expect(msg).toEqual(message);
242
- return true;
243
- });
244
- await client2.sendMessage(message);
245
- await promise;
113
+ await peer2.client.sendMessage(message);
114
+ expect(await peer1.waitForNextMessage()).toEqual(message);
246
115
  }
247
- })
248
- .timeout(1_000)
249
- .retries(2);
250
-
251
- test
252
- .skip('join across multiple signal servers', async () => {
253
- const topic = PublicKey.random();
254
- const peer1 = PublicKey.random();
255
- const peer2 = PublicKey.random();
256
- // This feature is not implemented yet.
257
- const api1 = new SignalClient(
258
- broker1.url(),
259
- async () => {},
260
- async () => {},
261
- );
262
- void api1.open();
263
- afterTest(() => api1.close());
264
- const api2 = new SignalClient(
265
- broker2.url(),
266
- async () => {},
267
- async () => {},
268
- );
269
- void api2.open();
270
- afterTest(() => api2.close());
271
-
272
- await api1.join({ topic, peerId: peer1 });
273
- await api2.join({ topic, peerId: peer2 });
274
-
275
- // await waitForExpect(async () => {
276
- // const peers = await api2.lookup(topic);
277
- // expect(peers.length).toEqual(2);
278
- // }, 4_000);
279
-
280
- // await waitForExpect(async () => {
281
- // const peers = await api1.lookup(topic);
282
- // expect(peers.length).toEqual(2);
283
- // }, 4_000);
284
- })
285
- .timeout(5_000);
286
-
287
- // Skip because communication between signal servers is not yet implemented.
288
- test
289
- .skip('newly joined peer can receive signals from other signal servers', async () => {
290
- const topic = PublicKey.random();
291
- const peer1 = PublicKey.random();
292
- const peer2 = PublicKey.random();
293
- const signalMock =
294
- mockFn<
295
- ({ author, recipient, payload }: { author: PublicKey; recipient: PublicKey; payload: Any }) => Promise<void>
296
- >().resolvesTo();
297
-
298
- const api1 = new SignalClient(
299
- broker1.url(),
300
- async () => {},
301
- async () => {},
116
+ }).timeout(1_000);
117
+
118
+ const setupPeers = (options?: { broker?: SignalServerRunner; peerCount?: number }): TestPeer[] => {
119
+ return range(options?.peerCount ?? 1, () => {
120
+ const peers = new ComplexSet(PublicKey.hash);
121
+ let nextMessage: any | null = null;
122
+ const nextMessageTrigger = new Trigger();
123
+ const id = PublicKey.random();
124
+ const client = new SignalClient(
125
+ (options?.broker ?? broker1).url(),
126
+ async (msg) => {
127
+ nextMessage = msg;
128
+ nextMessageTrigger.wake();
129
+ },
130
+ async (event) => {
131
+ if (event.swarmEvent.peerAvailable) {
132
+ peers.add(PublicKey.from(event.swarmEvent.peerAvailable.peer));
133
+ } else if (event.swarmEvent.peerLeft) {
134
+ peers.delete(PublicKey.from(event.swarmEvent.peerLeft.peer));
135
+ }
136
+ },
302
137
  );
303
- void api1.open();
304
- afterTest(() => api1.close());
305
- const api2 = new SignalClient(broker2.url(), signalMock, async () => {});
306
- void api2.open();
307
- afterTest(() => api2.close());
308
-
309
- await api1.join({ topic, peerId: peer1 });
310
- await sleep(3000);
311
- await api2.join({ topic, peerId: peer2 });
312
-
313
- const message = {
314
- author: peer2,
315
- recipient: peer1,
316
- payload: {
317
- type_url: 'something',
318
- value: Buffer.from('0'),
138
+ void client.open();
139
+ afterTest(async () => {
140
+ await client.close();
141
+ });
142
+ return {
143
+ id,
144
+ client,
145
+ waitForNextMessage: async (options?: { timeout?: number }) => {
146
+ if (nextMessage == null) {
147
+ await nextMessageTrigger.wait(options);
148
+ }
149
+ const result = nextMessage!;
150
+ nextMessageTrigger.reset();
151
+ nextMessage = null;
152
+ return result;
319
153
  },
154
+ waitForPeer: (peerId: PublicKey) => waitForCondition({ condition: () => peers.has(peerId) }),
320
155
  };
321
- await api1.sendMessage(message);
156
+ });
157
+ };
158
+
159
+ const createMessage = (from: TestPeer, to: TestPeer, payload: any = PAYLOAD) => {
160
+ return {
161
+ author: from.id,
162
+ recipient: to.id,
163
+ payload: PAYLOAD,
164
+ };
165
+ };
322
166
 
323
- // await waitForExpect(() => {
324
- // expect(signalMock).toHaveBeenCalledWith([message]);
325
- // }, 4_000);
326
- })
327
- .timeout(5_000);
167
+ const waitForSubscription = async (signal: SignalClient, peerId: PublicKey) => {
168
+ await asyncTimeout(
169
+ signal.localState.reconciled.waitForCondition(() => signal.localState.messageStreams.has(peerId)),
170
+ 500,
171
+ );
172
+ };
328
173
  });
174
+
175
+ interface TestPeer {
176
+ id: PublicKey;
177
+ client: SignalClient;
178
+ waitForNextMessage: (options?: { timeout?: number }) => Promise<any>;
179
+ waitForPeer: (peerId: PublicKey) => Promise<boolean>;
180
+ }