@dxos/network-manager 2.33.9-dev.e605934d → 2.33.9-dev.eb69ac10

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 (83) hide show
  1. package/dist/browser-mocha/bundle.js +5420 -1612
  2. package/dist/src/network-manager.d.ts.map +1 -1
  3. package/dist/src/network-manager.js +7 -6
  4. package/dist/src/network-manager.js.map +1 -1
  5. package/dist/src/proto/gen/dxos/credentials.d.ts +39 -0
  6. package/dist/src/proto/gen/dxos/credentials.d.ts.map +1 -1
  7. package/dist/src/proto/gen/dxos/halo/keys.d.ts +44 -2
  8. package/dist/src/proto/gen/dxos/halo/keys.d.ts.map +1 -1
  9. package/dist/src/proto/gen/dxos/halo/keys.js +4 -0
  10. package/dist/src/proto/gen/dxos/halo/keys.js.map +1 -1
  11. package/dist/src/proto/gen/dxos/mesh/signal.d.ts +58 -7
  12. package/dist/src/proto/gen/dxos/mesh/signal.d.ts.map +1 -1
  13. package/dist/src/proto/gen/google/protobuf.d.ts +2 -2
  14. package/dist/src/proto/gen/google/protobuf.d.ts.map +1 -1
  15. package/dist/src/proto/gen/index.d.ts +1 -0
  16. package/dist/src/proto/gen/index.d.ts.map +1 -1
  17. package/dist/src/proto/gen/index.js +1 -1
  18. package/dist/src/proto/gen/index.js.map +1 -1
  19. package/dist/src/protocol-factory.js +3 -3
  20. package/dist/src/protocol-factory.js.map +1 -1
  21. package/dist/src/signal/in-memory-signal-manager.js +5 -5
  22. package/dist/src/signal/in-memory-signal-manager.js.map +1 -1
  23. package/dist/src/signal/message-router.d.ts +16 -4
  24. package/dist/src/signal/message-router.d.ts.map +1 -1
  25. package/dist/src/signal/message-router.js +91 -17
  26. package/dist/src/signal/message-router.js.map +1 -1
  27. package/dist/src/signal/message-router.test.js +120 -13
  28. package/dist/src/signal/message-router.test.js.map +1 -1
  29. package/dist/src/signal/signal-client.d.ts +2 -1
  30. package/dist/src/signal/signal-client.d.ts.map +1 -1
  31. package/dist/src/signal/signal-client.js +26 -16
  32. package/dist/src/signal/signal-client.js.map +1 -1
  33. package/dist/src/signal/signal-client.test.js +4 -2
  34. package/dist/src/signal/signal-client.test.js.map +1 -1
  35. package/dist/src/signal/websocket-rpc.js +3 -3
  36. package/dist/src/signal/websocket-rpc.js.map +1 -1
  37. package/dist/src/signal/websocket-signal-manager.js +2 -2
  38. package/dist/src/signal/websocket-signal-manager.js.map +1 -1
  39. package/dist/src/swarm/connection.js +8 -8
  40. package/dist/src/swarm/connection.js.map +1 -1
  41. package/dist/src/swarm/swarm.js +10 -10
  42. package/dist/src/swarm/swarm.js.map +1 -1
  43. package/dist/src/swarm/swarm.test.js +2 -0
  44. package/dist/src/swarm/swarm.test.js.map +1 -1
  45. package/dist/src/testing/test-protocol.d.ts.map +1 -1
  46. package/dist/src/testing/test-protocol.js +3 -3
  47. package/dist/src/testing/test-protocol.js.map +1 -1
  48. package/dist/src/topology/fully-connected-topology.js +3 -3
  49. package/dist/src/topology/fully-connected-topology.js.map +1 -1
  50. package/dist/src/topology/mmst-topology.js +5 -5
  51. package/dist/src/topology/mmst-topology.js.map +1 -1
  52. package/dist/src/topology/star-topology.js +4 -4
  53. package/dist/src/topology/star-topology.js.map +1 -1
  54. package/dist/src/transport/in-memory-transport.js +2 -2
  55. package/dist/src/transport/in-memory-transport.js.map +1 -1
  56. package/dist/src/transport/webrtc-transport.js +3 -3
  57. package/dist/src/transport/webrtc-transport.js.map +1 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +14 -11
  60. package/src/network-manager.ts +2 -1
  61. package/src/proto/defs/dxos/mesh/signal.proto +13 -0
  62. package/src/proto/gen/dxos/credentials.ts +39 -0
  63. package/src/proto/gen/dxos/halo/keys.ts +44 -2
  64. package/src/proto/gen/dxos/mesh/signal.ts +58 -7
  65. package/src/proto/gen/google/protobuf.ts +2 -2
  66. package/src/proto/gen/index.ts +2 -1
  67. package/src/protocol-factory.ts +1 -1
  68. package/src/signal/in-memory-signal-manager.ts +1 -1
  69. package/src/signal/message-router.test.ts +154 -38
  70. package/src/signal/message-router.ts +107 -18
  71. package/src/signal/signal-client.test.ts +4 -2
  72. package/src/signal/signal-client.ts +42 -15
  73. package/src/signal/websocket-rpc.ts +1 -1
  74. package/src/signal/websocket-signal-manager.ts +1 -1
  75. package/src/swarm/connection.ts +1 -1
  76. package/src/swarm/swarm.test.ts +2 -0
  77. package/src/swarm/swarm.ts +2 -2
  78. package/src/testing/test-protocol.ts +1 -1
  79. package/src/topology/fully-connected-topology.ts +1 -1
  80. package/src/topology/mmst-topology.ts +1 -1
  81. package/src/topology/star-topology.ts +1 -1
  82. package/src/transport/in-memory-transport.ts +1 -1
  83. package/src/transport/webrtc-transport.ts +1 -1
@@ -3,9 +3,10 @@
3
3
  //
4
4
 
5
5
  import assert from 'assert';
6
+ import debug from 'debug';
6
7
 
7
8
  import { PublicKey } from '@dxos/protocols';
8
- import { ComplexMap } from '@dxos/util';
9
+ import { ComplexMap, ComplexSet, exponentialBackoffInterval, SubscriptionGroup } from '@dxos/util';
9
10
 
10
11
  import { Answer, Message } from '../proto/gen/dxos/mesh/signal';
11
12
  import { SignalMessaging } from './signal-manager';
@@ -16,11 +17,14 @@ interface OfferRecord {
16
17
  }
17
18
 
18
19
  interface MessageRouterOptions {
19
- onSignal: (message: Message) => Promise<void>;
20
- sendMessage: (message: Message) => Promise<void>;
21
- onOffer: (message: Message) => Promise<Answer>;
20
+ onSignal?: (message: Message) => Promise<void>;
21
+ sendMessage?: (message: Message) => Promise<void>;
22
+ onOffer?: (message: Message) => Promise<Answer>;
23
+ retryDelay?: number;
24
+ timeout?: number;
22
25
  }
23
26
 
27
+ const log = debug('dxos:network-manager:message-router');
24
28
  /**
25
29
  * Adds offer/answer RPC and reliable messaging.
26
30
  */
@@ -31,59 +35,144 @@ export class MessageRouter implements SignalMessaging {
31
35
  private readonly _sendMessage: (message: Message) => Promise<void>;
32
36
  private readonly _onOffer: (message: Message) => Promise<Answer>;
33
37
 
38
+ private readonly _onAckCallbacks = new ComplexMap<PublicKey, () => void>(key => key.toHex());
39
+ private readonly _receivedMessages = new ComplexSet<PublicKey>(key => key.toHex());
40
+ private readonly _retryDelay: number;
41
+ private readonly _timeout: number;
42
+
43
+ private readonly _subscriptions = new SubscriptionGroup();
44
+
34
45
  constructor ({
35
46
  sendMessage,
36
47
  onSignal,
37
- onOffer
38
- }: MessageRouterOptions) {
48
+ onOffer,
49
+ retryDelay = 100,
50
+ timeout = 3000
51
+ }: MessageRouterOptions = {}) {
52
+ assert(sendMessage);
39
53
  this._sendMessage = sendMessage;
54
+ assert(onSignal);
40
55
  this._onSignal = onSignal;
56
+ assert(onOffer);
41
57
  this._onOffer = onOffer;
58
+ this._retryDelay = retryDelay;
59
+ this._timeout = timeout;
42
60
  }
43
61
 
44
62
  async receiveMessage (message: Message): Promise<void> {
63
+ log(`receive message: ${JSON.stringify(message)}`);
64
+ if (!message.data?.ack) {
65
+ if (this._receivedMessages.has(message.messageId!)) {
66
+ return;
67
+ }
68
+
69
+ this._receivedMessages.add(message.messageId!);
70
+ await this._sendAcknowledgement(message);
71
+ }
72
+
45
73
  if (message.data?.offer) {
46
74
  await this._handleOffer(message);
47
75
  } else if (message.data?.answer) {
48
76
  await this._resolveAnswers(message);
49
77
  } else if (message.data?.signal) {
50
- await this._onSignal(message);
78
+ await this._handleSignal(message);
79
+ } else if (message.data?.ack) {
80
+ await this._handleAcknowledgement(message);
51
81
  }
52
82
  }
53
83
 
54
84
  async signal (message: Message): Promise<void> {
55
85
  assert(message.data?.signal);
56
- await this._sendMessage(message);
86
+ await this._sendReliableMessage(message);
57
87
  }
58
88
 
59
89
  async offer (message: Message): Promise<Answer> {
90
+ message.messageId = PublicKey.random();
60
91
  const promise = new Promise<Answer>((resolve, reject) => {
61
- assert(message.sessionId);
62
- this._offerRecords.set(message.sessionId, { resolve, reject });
92
+ this._offerRecords.set(message.messageId!, { resolve, reject });
93
+ return this._sendReliableMessage(message);
63
94
  });
64
- await this._sendMessage(message);
65
95
  return promise;
66
96
  }
67
97
 
98
+ private async _sendReliableMessage (message: Message): Promise<PublicKey> {
99
+ // Setting unique messageId if it not specified yet.
100
+ message.messageId = message.messageId ?? PublicKey.random();
101
+ log(`sent message: ${JSON.stringify(message)}`);
102
+
103
+ // Setting retry interval if signal was not acknowledged.
104
+ const cancelRetry = exponentialBackoffInterval(async () => {
105
+ log(`retrying message: ${JSON.stringify(message)}`);
106
+ await this._sendMessage(message);
107
+ }, this._retryDelay);
108
+
109
+ const timeout = setTimeout(() => {
110
+ log('Signal was not delivered!');
111
+ this._onAckCallbacks.delete(message.messageId!);
112
+ cancelRetry();
113
+ }, this._timeout);
114
+
115
+ assert(!this._onAckCallbacks.has(message.messageId!));
116
+ this._onAckCallbacks.set(message.messageId, () => {
117
+ this._onAckCallbacks.delete(message.messageId!);
118
+ cancelRetry();
119
+ clearTimeout(timeout);
120
+ });
121
+ this._subscriptions.push(cancelRetry);
122
+ this._subscriptions.push(() => clearTimeout(timeout));
123
+
124
+ await this._sendMessage(message);
125
+ return message.messageId;
126
+ }
127
+
68
128
  private async _resolveAnswers (message: Message): Promise<void> {
69
- assert(message.sessionId);
70
- const offerRecord = this._offerRecords.get(message.sessionId);
129
+ assert(message.data?.answer?.offerMessageId, 'No offerMessageId');
130
+ const offerRecord = this._offerRecords.get(message.data.answer.offerMessageId);
71
131
  if (offerRecord) {
72
- this._offerRecords.delete(message.sessionId);
73
- assert(message.data?.answer);
132
+ this._offerRecords.delete(message.data.answer.offerMessageId);
133
+ assert(message.data?.answer, 'No Answer');
134
+ log(`resolving answer with ${message.data.answer}`);
74
135
  offerRecord.resolve(message.data.answer);
75
136
  }
76
137
  }
77
138
 
78
139
  private async _handleOffer (message: Message): Promise<void> {
79
140
  const answer = await this._onOffer(message);
80
- const answerMessage = {
141
+ answer.offerMessageId = message.messageId;
142
+ const answerMessage: Message = {
143
+ id: message.remoteId,
144
+ remoteId: message.id,
145
+ topic: message.topic,
146
+ sessionId: message.sessionId,
147
+ data: { answer }
148
+ };
149
+ await this._sendReliableMessage(answerMessage);
150
+ }
151
+
152
+ private async _handleSignal (message: Message): Promise<void> {
153
+ assert(message.messageId);
154
+ await this._onSignal(message);
155
+ }
156
+
157
+ private async _handleAcknowledgement (message: Message): Promise<void> {
158
+ assert(message.data?.ack?.messageId);
159
+ this._onAckCallbacks.get(message.data.ack.messageId)?.();
160
+ }
161
+
162
+ private async _sendAcknowledgement (message: Message): Promise<void> {
163
+ assert(message.messageId);
164
+ const ackMessage = {
81
165
  id: message.remoteId,
82
166
  remoteId: message.id,
83
167
  topic: message.topic,
84
168
  sessionId: message.sessionId,
85
- data: { answer: answer }
169
+ data: { ack: { messageId: message.messageId } }
86
170
  };
87
- await this._sendMessage(answerMessage);
171
+ log(`sent ack: ${JSON.stringify(ackMessage)}`);
172
+ await this._sendMessage(ackMessage);
173
+ }
174
+
175
+ destroy (): void {
176
+ this._subscriptions.unsubscribe();
88
177
  }
89
178
  }
@@ -61,7 +61,8 @@ describe('SignalApi', () => {
61
61
  remoteId: peer1,
62
62
  sessionId: PublicKey.random(),
63
63
  topic,
64
- data: { signal: { json: "foo: 'bar'" } }
64
+ data: { signal: { json: "foo: 'bar'" } },
65
+ messageId: undefined
65
66
  };
66
67
  await api2.signal(msg);
67
68
 
@@ -111,7 +112,8 @@ describe('SignalApi', () => {
111
112
  remoteId: peer1,
112
113
  sessionId: PublicKey.random(),
113
114
  topic,
114
- data: { signal: { json: 'bar' } }
115
+ data: { signal: { json: 'bar' } },
116
+ messageId: undefined
115
117
  };
116
118
  await api1.signal(msg);
117
119
 
@@ -5,8 +5,10 @@
5
5
  import debug from 'debug';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
+ import { failUndefined } from '@dxos/debug';
8
9
  import { PublicKey } from '@dxos/protocols';
9
10
 
11
+ import { schema } from '../proto/gen';
10
12
  import { Answer, Message } from '../proto/gen/dxos/mesh/signal';
11
13
  import { SignalApi } from './signal-api';
12
14
  import { WebsocketRpc } from './websocket-rpc';
@@ -90,13 +92,17 @@ export class SignalClient {
90
92
  data: message.data
91
93
  }));
92
94
 
93
- this._client.subscribe('signal', (msg: Message) => this._onSignal({
94
- id: PublicKey.from(msg.id!),
95
- remoteId: PublicKey.from(msg.remoteId!),
96
- topic: PublicKey.from(msg.topic!),
97
- sessionId: PublicKey.from(msg.sessionId!),
98
- data: msg.data
99
- }));
95
+ this._client.subscribe('signal', (msg: SignalMessage) => {
96
+ return this._onSignal({
97
+ id: PublicKey.from(msg.id!),
98
+ remoteId: PublicKey.from(msg.remoteId!),
99
+ topic: PublicKey.from(msg.topic!),
100
+ sessionId: PublicKey.from(msg.sessionId!),
101
+ data: schema.getCodecForType('dxos.mesh.signal.MessageData').decode(msg.data ?? failUndefined()),
102
+ // Field that MessageRouter adds, so on lower level it not always defined.
103
+ messageId: msg.messageId ? PublicKey.from(msg.messageId) : undefined
104
+ });
105
+ });
100
106
 
101
107
  this._clientCleanup.push(this._client.connected.on(() => {
102
108
  log('Socket connected');
@@ -210,6 +216,7 @@ export class SignalClient {
210
216
  /**
211
217
  * Routes an offer to the other peer's _onOffer callback.
212
218
  * @returns Other peer's _onOffer callback return value.
219
+ * @deprecated
213
220
  */
214
221
  async offer (msg: Message): Promise<Answer> {
215
222
  return this._client.call('offer', {
@@ -224,13 +231,33 @@ export class SignalClient {
224
231
  /**
225
232
  * Routes an offer to the other peer's _onSignal callback.
226
233
  */
227
- async signal (payload: Message): Promise<void> {
228
- return this._client.emit('signal', {
229
- id: payload.id?.asBuffer(),
230
- remoteId: payload.remoteId?.asBuffer(),
231
- topic: payload.topic?.asBuffer(),
232
- sessionId: payload.sessionId?.asBuffer(),
233
- data: payload.data
234
- });
234
+ async signal (message: Message): Promise<void> {
235
+ const signalMessage: SignalMessage = {
236
+ messageId: message.messageId?.asBuffer(),
237
+ id: message.id?.asBuffer(),
238
+ remoteId: message.remoteId?.asBuffer(),
239
+ topic: message.topic?.asBuffer(),
240
+ sessionId: message.sessionId?.asBuffer(),
241
+ data: Buffer.from(schema.getCodecForType('dxos.mesh.signal.MessageData').encode(message.data ?? failUndefined()))
242
+ };
243
+ return this._client.emit('signal', signalMessage);
235
244
  }
236
245
  }
246
+
247
+ /**
248
+ * Messages as processed by the signal server.
249
+ */
250
+ interface SignalMessage{
251
+ /**
252
+ * Sender's public key.
253
+ */
254
+ id?: Buffer;
255
+ /**
256
+ * Receiver`s public key.
257
+ */
258
+ remoteId?: Buffer;
259
+ topic?: Buffer;
260
+ sessionId?: Buffer;
261
+ data?: Buffer;
262
+ messageId?: Buffer;
263
+ }
@@ -2,10 +2,10 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
7
6
  import WebSocket from 'isomorphic-ws';
8
7
  import nanomessagerpc from 'nanomessage-rpc';
8
+ import assert from 'node:assert';
9
9
  import { promisify } from 'util';
10
10
 
11
11
  import { Event, Trigger, sleep } from '@dxos/async';
@@ -2,8 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
 
8
8
  import { Event, synchronized } from '@dxos/async';
9
9
  import { PublicKey } from '@dxos/protocols';
@@ -2,8 +2,8 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
 
8
8
  import { Event, synchronized } from '@dxos/async';
9
9
  import { ErrorStream } from '@dxos/debug';
@@ -52,12 +52,14 @@ const setup = ({ router = false } = {}) => {
52
52
  onSignal: msg => swarm1.onSignal(msg),
53
53
  onOffer: msg => swarm1.onOffer(msg)
54
54
  });
55
+ afterTest(() => mr1.destroy());
55
56
 
56
57
  const mr2: MessageRouter = new MessageRouter({
57
58
  sendMessage: msg => mr1.receiveMessage(msg),
58
59
  onSignal: msg => swarm2.onSignal(msg),
59
60
  onOffer: msg => swarm2.onOffer(msg)
60
61
  });
62
+ afterTest(() => mr2.destroy());
61
63
 
62
64
  const sm1: SignalMessaging = router ? mr1 : new MockSignalConnection(() => swarm2);
63
65
 
@@ -2,8 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
 
8
8
  import { Event } from '@dxos/async';
9
9
  import { discoveryKey } from '@dxos/crypto';
@@ -101,7 +101,7 @@ export class Swarm {
101
101
  }
102
102
 
103
103
  async onOffer (message: Message): Promise<Answer> {
104
- log(`Offer from ${message.id} topic=${this._topic}`);
104
+ log(`Offer from ${JSON.stringify(message)}`);
105
105
  // Id of the peer offering us the connection.
106
106
  assert(message.id);
107
107
  const remoteId = message.id;
@@ -4,9 +4,9 @@
4
4
 
5
5
  // Test/mock Protocol implementation used in network-manager tests.
6
6
 
7
- import assert from 'assert';
8
7
  import debug from 'debug';
9
8
  import { EventEmitter } from 'events';
9
+ import assert from 'node:assert';
10
10
 
11
11
  import { Extension, Protocol } from '@dxos/mesh-protocol';
12
12
  import { PublicKey } from '@dxos/protocols';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
5
+ import assert from 'node:assert';
6
6
 
7
7
  import { PublicKey } from '@dxos/protocols';
8
8
 
@@ -2,8 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
  import distance from 'xor-distance';
8
8
 
9
9
  import { PublicKey } from '@dxos/protocols';
@@ -2,8 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
 
8
8
  import { PublicKey } from '@dxos/protocols';
9
9
 
@@ -2,8 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import assert from 'assert';
6
5
  import debug from 'debug';
6
+ import assert from 'node:assert';
7
7
  import { Transform } from 'stream';
8
8
 
9
9
  import { Event } from '@dxos/async';
@@ -3,8 +3,8 @@
3
3
  //
4
4
 
5
5
  import wrtc from '@koush/wrtc';
6
- import assert from 'assert';
7
6
  import debug from 'debug';
7
+ import assert from 'node:assert';
8
8
  import SimplePeerConstructor, { Instance as SimplePeer } from 'simple-peer';
9
9
 
10
10
  import { Event } from '@dxos/async';