@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.
- package/dist/browser-mocha/bundle.js +5420 -1612
- package/dist/src/network-manager.d.ts.map +1 -1
- package/dist/src/network-manager.js +7 -6
- package/dist/src/network-manager.js.map +1 -1
- package/dist/src/proto/gen/dxos/credentials.d.ts +39 -0
- package/dist/src/proto/gen/dxos/credentials.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/halo/keys.d.ts +44 -2
- package/dist/src/proto/gen/dxos/halo/keys.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/halo/keys.js +4 -0
- package/dist/src/proto/gen/dxos/halo/keys.js.map +1 -1
- package/dist/src/proto/gen/dxos/mesh/signal.d.ts +58 -7
- package/dist/src/proto/gen/dxos/mesh/signal.d.ts.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 +1 -0
- 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/protocol-factory.js +3 -3
- package/dist/src/protocol-factory.js.map +1 -1
- package/dist/src/signal/in-memory-signal-manager.js +5 -5
- package/dist/src/signal/in-memory-signal-manager.js.map +1 -1
- package/dist/src/signal/message-router.d.ts +16 -4
- package/dist/src/signal/message-router.d.ts.map +1 -1
- package/dist/src/signal/message-router.js +91 -17
- package/dist/src/signal/message-router.js.map +1 -1
- package/dist/src/signal/message-router.test.js +120 -13
- package/dist/src/signal/message-router.test.js.map +1 -1
- package/dist/src/signal/signal-client.d.ts +2 -1
- package/dist/src/signal/signal-client.d.ts.map +1 -1
- package/dist/src/signal/signal-client.js +26 -16
- package/dist/src/signal/signal-client.js.map +1 -1
- package/dist/src/signal/signal-client.test.js +4 -2
- package/dist/src/signal/signal-client.test.js.map +1 -1
- package/dist/src/signal/websocket-rpc.js +3 -3
- package/dist/src/signal/websocket-rpc.js.map +1 -1
- package/dist/src/signal/websocket-signal-manager.js +2 -2
- package/dist/src/signal/websocket-signal-manager.js.map +1 -1
- package/dist/src/swarm/connection.js +8 -8
- package/dist/src/swarm/connection.js.map +1 -1
- package/dist/src/swarm/swarm.js +10 -10
- package/dist/src/swarm/swarm.js.map +1 -1
- package/dist/src/swarm/swarm.test.js +2 -0
- package/dist/src/swarm/swarm.test.js.map +1 -1
- package/dist/src/testing/test-protocol.d.ts.map +1 -1
- package/dist/src/testing/test-protocol.js +3 -3
- package/dist/src/testing/test-protocol.js.map +1 -1
- package/dist/src/topology/fully-connected-topology.js +3 -3
- package/dist/src/topology/fully-connected-topology.js.map +1 -1
- package/dist/src/topology/mmst-topology.js +5 -5
- package/dist/src/topology/mmst-topology.js.map +1 -1
- package/dist/src/topology/star-topology.js +4 -4
- package/dist/src/topology/star-topology.js.map +1 -1
- package/dist/src/transport/in-memory-transport.js +2 -2
- package/dist/src/transport/in-memory-transport.js.map +1 -1
- package/dist/src/transport/webrtc-transport.js +3 -3
- package/dist/src/transport/webrtc-transport.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -11
- package/src/network-manager.ts +2 -1
- package/src/proto/defs/dxos/mesh/signal.proto +13 -0
- package/src/proto/gen/dxos/credentials.ts +39 -0
- package/src/proto/gen/dxos/halo/keys.ts +44 -2
- package/src/proto/gen/dxos/mesh/signal.ts +58 -7
- package/src/proto/gen/google/protobuf.ts +2 -2
- package/src/proto/gen/index.ts +2 -1
- package/src/protocol-factory.ts +1 -1
- package/src/signal/in-memory-signal-manager.ts +1 -1
- package/src/signal/message-router.test.ts +154 -38
- package/src/signal/message-router.ts +107 -18
- package/src/signal/signal-client.test.ts +4 -2
- package/src/signal/signal-client.ts +42 -15
- package/src/signal/websocket-rpc.ts +1 -1
- package/src/signal/websocket-signal-manager.ts +1 -1
- package/src/swarm/connection.ts +1 -1
- package/src/swarm/swarm.test.ts +2 -0
- package/src/swarm/swarm.ts +2 -2
- package/src/testing/test-protocol.ts +1 -1
- package/src/topology/fully-connected-topology.ts +1 -1
- package/src/topology/mmst-topology.ts +1 -1
- package/src/topology/star-topology.ts +1 -1
- package/src/transport/in-memory-transport.ts +1 -1
- 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
|
|
20
|
-
sendMessage
|
|
21
|
-
onOffer
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
62
|
-
this.
|
|
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.
|
|
70
|
-
const offerRecord = this._offerRecords.get(message.
|
|
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.
|
|
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
|
-
|
|
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: {
|
|
169
|
+
data: { ack: { messageId: message.messageId } }
|
|
86
170
|
};
|
|
87
|
-
|
|
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:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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 (
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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';
|
package/src/swarm/connection.ts
CHANGED
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -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
|
|
package/src/swarm/swarm.ts
CHANGED
|
@@ -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
|
|
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';
|