@dxos/network-manager 2.33.9-dev.7d11f506 → 2.33.9-dev.9bbef4e2
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/network-manager.blueprint-test.d.ts +3 -1
- package/dist/src/network-manager.blueprint-test.d.ts.map +1 -1
- package/dist/src/network-manager.blueprint-test.js +46 -17
- package/dist/src/network-manager.blueprint-test.js.map +1 -1
- package/dist/src/network-manager.browser-test.js +1 -1
- package/dist/src/network-manager.browser-test.js.map +1 -1
- package/dist/src/network-manager.d.ts.map +1 -1
- package/dist/src/network-manager.js +13 -12
- package/dist/src/network-manager.js.map +1 -1
- package/dist/src/network-manager.test.js +5 -4
- package/dist/src/network-manager.test.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 +74 -16
- package/dist/src/proto/gen/dxos/mesh/signal.d.ts.map +1 -1
- package/dist/src/proto/gen/dxos/mesh/signalMessage.d.ts +79 -0
- package/dist/src/proto/gen/dxos/mesh/signalMessage.d.ts.map +1 -0
- package/dist/src/proto/gen/dxos/mesh/signalMessage.js +3 -0
- package/dist/src/proto/gen/dxos/mesh/signalMessage.js.map +1 -0
- package/dist/src/proto/gen/google/protobuf.d.ts +8 -2
- package/dist/src/proto/gen/google/protobuf.d.ts.map +1 -1
- package/dist/src/proto/gen/index.d.ts +17 -4
- 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/proto/substitutions.d.ts +4 -0
- package/dist/src/proto/substitutions.d.ts.map +1 -1
- package/dist/src/proto/substitutions.js +3 -1
- package/dist/src/proto/substitutions.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.d.ts +7 -7
- package/dist/src/signal/in-memory-signal-manager.d.ts.map +1 -1
- package/dist/src/signal/in-memory-signal-manager.js +34 -13
- package/dist/src/signal/in-memory-signal-manager.js.map +1 -1
- package/dist/src/signal/index.d.ts +1 -2
- package/dist/src/signal/index.d.ts.map +1 -1
- package/dist/src/signal/index.js +1 -2
- package/dist/src/signal/index.js.map +1 -1
- package/dist/src/signal/integration.test.d.ts +2 -0
- package/dist/src/signal/integration.test.d.ts.map +1 -0
- package/dist/src/signal/integration.test.js +102 -0
- package/dist/src/signal/integration.test.js.map +1 -0
- package/dist/src/signal/message-router.d.ts +20 -8
- package/dist/src/signal/message-router.d.ts.map +1 -1
- package/dist/src/signal/message-router.js +96 -17
- package/dist/src/signal/message-router.js.map +1 -1
- package/dist/src/signal/message-router.test.js +125 -22
- package/dist/src/signal/message-router.test.js.map +1 -1
- package/dist/src/signal/signal-client.d.ts +33 -17
- package/dist/src/signal/signal-client.d.ts.map +1 -1
- package/dist/src/signal/signal-client.js +102 -82
- package/dist/src/signal/signal-client.js.map +1 -1
- package/dist/src/signal/signal-client.test.js +60 -75
- package/dist/src/signal/signal-client.test.js.map +1 -1
- package/dist/src/signal/{websocket-signal-manager.d.ts → signal-manager-impl.d.ts} +13 -11
- package/dist/src/signal/signal-manager-impl.d.ts.map +1 -0
- package/dist/src/signal/signal-manager-impl.js +151 -0
- package/dist/src/signal/signal-manager-impl.js.map +1 -0
- package/dist/src/signal/signal-manager.d.ts +12 -11
- package/dist/src/signal/signal-manager.d.ts.map +1 -1
- package/dist/src/signal/signal-rpc-client.d.ts +19 -0
- package/dist/src/signal/signal-rpc-client.d.ts.map +1 -0
- package/dist/src/signal/signal-rpc-client.js +108 -0
- package/dist/src/signal/signal-rpc-client.js.map +1 -0
- package/dist/src/signal/signal-rpc-client.test.d.ts +2 -0
- package/dist/src/signal/signal-rpc-client.test.d.ts.map +1 -0
- package/dist/src/signal/signal-rpc-client.test.js +74 -0
- package/dist/src/signal/signal-rpc-client.test.js.map +1 -0
- package/dist/src/swarm/connection.d.ts +3 -3
- package/dist/src/swarm/connection.d.ts.map +1 -1
- package/dist/src/swarm/connection.js +8 -11
- package/dist/src/swarm/connection.js.map +1 -1
- package/dist/src/swarm/swarm.d.ts +6 -7
- package/dist/src/swarm/swarm.d.ts.map +1 -1
- package/dist/src/swarm/swarm.js +29 -25
- package/dist/src/swarm/swarm.js.map +1 -1
- package/dist/src/swarm/swarm.test.js +156 -115
- 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.d.ts +0 -1
- package/dist/src/topology/fully-connected-topology.d.ts.map +1 -1
- package/dist/src/topology/fully-connected-topology.js +4 -9
- package/dist/src/topology/fully-connected-topology.js.map +1 -1
- package/dist/src/topology/mmst-topology.d.ts +0 -1
- package/dist/src/topology/mmst-topology.d.ts.map +1 -1
- package/dist/src/topology/mmst-topology.js +6 -11
- package/dist/src/topology/mmst-topology.js.map +1 -1
- package/dist/src/topology/star-topology.d.ts +0 -1
- package/dist/src/topology/star-topology.d.ts.map +1 -1
- package/dist/src/topology/star-topology.js +5 -10
- package/dist/src/topology/star-topology.js.map +1 -1
- package/dist/src/topology/topology.d.ts +0 -6
- package/dist/src/topology/topology.d.ts.map +1 -1
- package/dist/src/transport/in-memory-transport.d.ts +2 -2
- package/dist/src/transport/in-memory-transport.d.ts.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/transport.d.ts +3 -3
- package/dist/src/transport/transport.d.ts.map +1 -1
- package/dist/src/transport/webrtc-transport.d.ts +3 -3
- package/dist/src/transport/webrtc-transport.d.ts.map +1 -1
- package/dist/src/transport/webrtc-transport.js +3 -3
- package/dist/src/transport/webrtc-transport.js.map +1 -1
- package/dist/tests-setup.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -12
- package/src/network-manager.blueprint-test.ts +57 -22
- package/src/network-manager.browser-test.ts +1 -1
- package/src/network-manager.test.ts +8 -7
- package/src/network-manager.ts +10 -10
- package/src/proto/defs/dxos/mesh/signal.proto +54 -23
- package/src/proto/defs/dxos/mesh/signalMessage.proto +51 -0
- package/src/proto/gen/dxos/credentials.ts +40 -0
- package/src/proto/gen/dxos/halo/keys.ts +45 -2
- package/src/proto/gen/dxos/mesh/signal.ts +73 -16
- package/src/proto/gen/dxos/mesh/signalMessage.ts +83 -0
- package/src/proto/gen/google/protobuf.ts +9 -2
- package/src/proto/gen/index.ts +18 -5
- package/src/proto/substitutions.ts +3 -1
- package/src/protocol-factory.ts +1 -1
- package/src/signal/in-memory-signal-manager.ts +38 -13
- package/src/signal/index.ts +1 -2
- package/src/signal/integration.test.ts +117 -0
- package/src/signal/message-router.test.ts +169 -58
- package/src/signal/message-router.ts +120 -27
- package/src/signal/signal-client.test.ts +70 -90
- package/src/signal/signal-client.ts +120 -87
- package/src/signal/signal-manager-impl.ts +166 -0
- package/src/signal/signal-manager.ts +12 -12
- package/src/signal/signal-rpc-client.test.ts +86 -0
- package/src/signal/signal-rpc-client.ts +121 -0
- package/src/swarm/connection.ts +6 -9
- package/src/swarm/swarm.test.ts +208 -167
- package/src/swarm/swarm.ts +26 -22
- package/src/testing/test-protocol.ts +1 -1
- package/src/topology/fully-connected-topology.ts +2 -10
- package/src/topology/mmst-topology.ts +2 -10
- package/src/topology/star-topology.ts +2 -8
- package/src/topology/topology.ts +0 -7
- package/src/transport/in-memory-transport.ts +3 -3
- package/src/transport/transport.ts +3 -3
- package/src/transport/webrtc-transport.ts +4 -4
- package/dist/src/signal/websocket-rpc.d.ts +0 -30
- package/dist/src/signal/websocket-rpc.d.ts.map +0 -1
- package/dist/src/signal/websocket-rpc.js +0 -203
- package/dist/src/signal/websocket-rpc.js.map +0 -1
- package/dist/src/signal/websocket-signal-manager.d.ts.map +0 -1
- package/dist/src/signal/websocket-signal-manager.js +0 -134
- package/dist/src/signal/websocket-signal-manager.js.map +0 -1
- package/src/signal/websocket-rpc.ts +0 -208
- package/src/signal/websocket-signal-manager.ts +0 -158
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { Protocol } from '@dxos/mesh-protocol';
|
|
|
12
12
|
import { PublicKey } from '@dxos/protocols';
|
|
13
13
|
import { afterTest } from '@dxos/testutils';
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { SignalMessage } from '../proto/gen/dxos/mesh/signalMessage';
|
|
16
16
|
import { SignalMessaging } from '../signal';
|
|
17
17
|
import { MessageRouter } from '../signal/message-router';
|
|
18
18
|
import { FullyConnectedTopology } from '../topology';
|
|
@@ -21,173 +21,214 @@ import { Swarm } from './swarm';
|
|
|
21
21
|
|
|
22
22
|
const log = debug('dxos:network-manager:swarm:test');
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
describe('Swarm', () => {
|
|
25
|
+
class MockSignalConnection implements SignalMessaging {
|
|
26
|
+
constructor (
|
|
27
|
+
readonly _swarm: () => Swarm,
|
|
28
|
+
readonly _delay = 10
|
|
29
|
+
) {}
|
|
30
|
+
|
|
31
|
+
async offer (msg: SignalMessage) {
|
|
32
|
+
await sleep(this._delay);
|
|
33
|
+
return this._swarm().onOffer(msg);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async signal (msg: SignalMessage) {
|
|
37
|
+
await sleep(this._delay);
|
|
38
|
+
await this._swarm().onSignal(msg);
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
42
|
+
const setup = ({ router = false } = {}) => {
|
|
43
|
+
const topic = PublicKey.random();
|
|
44
|
+
const peerId1 = PublicKey.random();
|
|
45
|
+
const peerId2 = PublicKey.random();
|
|
46
|
+
// eslint-disable-next-line prefer-const
|
|
47
|
+
let swarm1: Swarm;
|
|
48
|
+
// eslint-disable-next-line prefer-const
|
|
49
|
+
let swarm2: Swarm;
|
|
50
|
+
|
|
51
|
+
const mr1: MessageRouter = new MessageRouter({
|
|
52
|
+
sendMessage: msg => mr2.receiveMessage(msg),
|
|
53
|
+
onSignal: msg => swarm1.onSignal(msg),
|
|
54
|
+
onOffer: msg => swarm1.onOffer(msg)
|
|
55
|
+
});
|
|
56
|
+
afterTest(() => mr1.destroy());
|
|
57
|
+
|
|
58
|
+
const mr2: MessageRouter = new MessageRouter({
|
|
59
|
+
sendMessage: msg => mr1.receiveMessage(msg),
|
|
60
|
+
onSignal: msg => swarm2.onSignal(msg),
|
|
61
|
+
onOffer: msg => swarm2.onOffer(msg)
|
|
62
|
+
});
|
|
63
|
+
afterTest(() => mr2.destroy());
|
|
64
|
+
|
|
65
|
+
const sm1: SignalMessaging = router ? mr1 : new MockSignalConnection(() => swarm2);
|
|
66
|
+
|
|
67
|
+
const sm2: SignalMessaging = router ? mr2 : new MockSignalConnection(() => swarm1);
|
|
68
|
+
|
|
69
|
+
swarm1 = new Swarm(
|
|
70
|
+
topic,
|
|
71
|
+
peerId1,
|
|
72
|
+
new FullyConnectedTopology(),
|
|
73
|
+
() => new Protocol(),
|
|
74
|
+
sm1,
|
|
75
|
+
createWebRTCTransportFactory(),
|
|
76
|
+
undefined
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
swarm2 = new Swarm(
|
|
80
|
+
topic,
|
|
81
|
+
peerId2,
|
|
82
|
+
new FullyConnectedTopology(),
|
|
83
|
+
() => new Protocol(),
|
|
84
|
+
sm2,
|
|
85
|
+
createWebRTCTransportFactory(),
|
|
86
|
+
undefined
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
afterTest(async () => {
|
|
90
|
+
await swarm1.destroy();
|
|
91
|
+
await swarm2.destroy();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return { swarm1, swarm2, peerId1, peerId2 };
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
test('connects two peers in a swarm', async () => {
|
|
98
|
+
const { swarm1, swarm2, peerId1, peerId2 } = setup();
|
|
99
|
+
|
|
100
|
+
expect(swarm1.connections.length).toEqual(0);
|
|
101
|
+
expect(swarm2.connections.length).toEqual(0);
|
|
102
|
+
|
|
103
|
+
const promise = Promise.all([
|
|
104
|
+
promiseTimeout(swarm1.connected.waitForCount(1), 3000, new Error('Swarm1 connect timeout.')),
|
|
105
|
+
promiseTimeout(swarm2.connected.waitForCount(1), 3000, new Error('Swarm2 connect timeout.'))
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
// Behavior of the Signal Server.
|
|
109
|
+
swarm1.onSwarmEvent({
|
|
110
|
+
peerAvailable: {
|
|
111
|
+
peer: peerId1.asUint8Array(),
|
|
112
|
+
since: new Date()
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
swarm1.onSwarmEvent({
|
|
117
|
+
peerAvailable: {
|
|
118
|
+
peer: peerId2.asUint8Array(),
|
|
119
|
+
since: new Date()
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
log('Candidates changed');
|
|
124
|
+
await promise;
|
|
125
|
+
log('Swarms connected');
|
|
126
|
+
|
|
127
|
+
const swarm1Connection = swarm1.connections[0];
|
|
128
|
+
const swarm2Connection = swarm2.connections[0];
|
|
129
|
+
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
130
|
+
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
131
|
+
|
|
132
|
+
const data = Buffer.from('1234');
|
|
133
|
+
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
134
|
+
await waitForExpect(() => {
|
|
135
|
+
expect(onData).toHaveBeenCalledWith([data]);
|
|
136
|
+
});
|
|
137
|
+
}).timeout(5_000);
|
|
138
|
+
|
|
139
|
+
test('two peers try to originate connections to each other simultaneously', async () => {
|
|
140
|
+
const { swarm1, swarm2, peerId1, peerId2 } = setup();
|
|
141
|
+
|
|
142
|
+
expect(swarm1.connections.length).toEqual(0);
|
|
143
|
+
expect(swarm2.connections.length).toEqual(0);
|
|
144
|
+
|
|
145
|
+
swarm1.onSwarmEvent({
|
|
146
|
+
peerAvailable: {
|
|
147
|
+
peer: peerId2.asUint8Array(),
|
|
148
|
+
since: new Date()
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
swarm2.onSwarmEvent({
|
|
153
|
+
peerAvailable: {
|
|
154
|
+
peer: peerId1.asUint8Array(),
|
|
155
|
+
since: new Date()
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
await Promise.all([
|
|
160
|
+
swarm1.connected.waitForCount(1),
|
|
161
|
+
swarm2.connected.waitForCount(1)
|
|
162
|
+
]);
|
|
163
|
+
}).timeout(5_000);
|
|
164
|
+
|
|
165
|
+
test('second peer discovered after delay', async () => {
|
|
166
|
+
const { swarm1, swarm2, peerId1, peerId2 } = setup();
|
|
167
|
+
|
|
168
|
+
expect(swarm1.connections.length).toEqual(0);
|
|
169
|
+
expect(swarm2.connections.length).toEqual(0);
|
|
170
|
+
|
|
171
|
+
swarm1.onSwarmEvent({
|
|
172
|
+
peerAvailable: {
|
|
173
|
+
peer: peerId2.asUint8Array(),
|
|
174
|
+
since: new Date()
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
await sleep(15);
|
|
178
|
+
swarm2.onSwarmEvent({
|
|
179
|
+
peerAvailable: {
|
|
180
|
+
peer: peerId1.asUint8Array(),
|
|
181
|
+
since: new Date()
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await Promise.all([
|
|
186
|
+
swarm1.connected.waitForCount(1),
|
|
187
|
+
swarm1.connected.waitForCount(1)
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
const swarm1Connection = swarm1.connections[0];
|
|
191
|
+
const swarm2Connection = swarm2.connections[0];
|
|
192
|
+
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
193
|
+
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
194
|
+
|
|
195
|
+
const data = Buffer.from('1234');
|
|
196
|
+
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
197
|
+
await waitForExpect(() => {
|
|
198
|
+
expect(onData).toHaveBeenCalledWith([data]);
|
|
199
|
+
});
|
|
200
|
+
}).timeout(5_000);
|
|
201
|
+
|
|
202
|
+
test('swarming with message router', async () => {
|
|
203
|
+
const { swarm1, swarm2, peerId2 } = setup({ router: true });
|
|
204
|
+
|
|
205
|
+
const promise = Promise.all([
|
|
206
|
+
promiseTimeout(swarm1.connected.waitForCount(1), 3000, new Error('Swarm1 connect timeout.')),
|
|
207
|
+
promiseTimeout(swarm2.connected.waitForCount(1), 3000, new Error('Swarm2 connect timeout.'))
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
swarm1.onSwarmEvent({
|
|
211
|
+
peerAvailable: {
|
|
212
|
+
peer: peerId2.asUint8Array(),
|
|
213
|
+
since: new Date()
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
log('Candidates changed');
|
|
218
|
+
await promise;
|
|
219
|
+
log('Swarms connected');
|
|
220
|
+
|
|
221
|
+
const swarm1Connection = swarm1.connections[0];
|
|
222
|
+
const swarm2Connection = swarm2.connections[0];
|
|
223
|
+
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
224
|
+
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
225
|
+
|
|
226
|
+
const data = Buffer.from('1234');
|
|
227
|
+
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
228
|
+
await waitForExpect(() => {
|
|
229
|
+
expect(onData).toHaveBeenCalledWith([data]);
|
|
230
|
+
});
|
|
89
231
|
await swarm1.destroy();
|
|
90
232
|
await swarm2.destroy();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return { swarm1, swarm2, peerId1, peerId2 };
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
test('connects two peers in a swarm', async () => {
|
|
97
|
-
const { swarm1, swarm2, peerId2 } = setup();
|
|
98
|
-
|
|
99
|
-
expect(swarm1.connections.length).toEqual(0);
|
|
100
|
-
expect(swarm2.connections.length).toEqual(0);
|
|
101
|
-
|
|
102
|
-
const promise = Promise.all([
|
|
103
|
-
promiseTimeout(swarm1.connected.waitForCount(1), 3000, new Error('Swarm1 connect timeout.')),
|
|
104
|
-
promiseTimeout(swarm2.connected.waitForCount(1), 3000, new Error('Swarm2 connect timeout.'))
|
|
105
|
-
]);
|
|
106
|
-
|
|
107
|
-
swarm1.onPeerCandidatesChanged([peerId2]);
|
|
108
|
-
|
|
109
|
-
log('Candidates changed');
|
|
110
|
-
await promise;
|
|
111
|
-
log('Swarms connected');
|
|
112
|
-
|
|
113
|
-
const swarm1Connection = swarm1.connections[0];
|
|
114
|
-
const swarm2Connection = swarm2.connections[0];
|
|
115
|
-
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
116
|
-
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
117
|
-
|
|
118
|
-
const data = Buffer.from('1234');
|
|
119
|
-
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
120
|
-
await waitForExpect(() => {
|
|
121
|
-
expect(onData).toHaveBeenCalledWith([data]);
|
|
122
|
-
});
|
|
123
|
-
}).timeout(5_000);
|
|
124
|
-
|
|
125
|
-
test('two peers try to originate connections to each other simultaneously', async () => {
|
|
126
|
-
const { swarm1, swarm2, peerId1, peerId2 } = setup();
|
|
127
|
-
|
|
128
|
-
expect(swarm1.connections.length).toEqual(0);
|
|
129
|
-
expect(swarm2.connections.length).toEqual(0);
|
|
130
|
-
|
|
131
|
-
swarm1.onPeerCandidatesChanged([peerId2]);
|
|
132
|
-
swarm2.onPeerCandidatesChanged([peerId1]);
|
|
133
|
-
|
|
134
|
-
await Promise.all([
|
|
135
|
-
swarm1.connected.waitForCount(1),
|
|
136
|
-
swarm2.connected.waitForCount(1)
|
|
137
|
-
]);
|
|
138
|
-
}).timeout(5_000);
|
|
139
|
-
|
|
140
|
-
test('second peer discovered after delay', async () => {
|
|
141
|
-
const { swarm1, swarm2, peerId1, peerId2 } = setup();
|
|
142
|
-
|
|
143
|
-
expect(swarm1.connections.length).toEqual(0);
|
|
144
|
-
expect(swarm2.connections.length).toEqual(0);
|
|
145
|
-
|
|
146
|
-
swarm1.onPeerCandidatesChanged([peerId2]);
|
|
147
|
-
await sleep(15);
|
|
148
|
-
swarm2.onPeerCandidatesChanged([peerId1]);
|
|
149
|
-
|
|
150
|
-
await Promise.all([
|
|
151
|
-
swarm1.connected.waitForCount(1),
|
|
152
|
-
swarm1.connected.waitForCount(1)
|
|
153
|
-
]);
|
|
154
|
-
|
|
155
|
-
const swarm1Connection = swarm1.connections[0];
|
|
156
|
-
const swarm2Connection = swarm2.connections[0];
|
|
157
|
-
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
158
|
-
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
159
|
-
|
|
160
|
-
const data = Buffer.from('1234');
|
|
161
|
-
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
162
|
-
await waitForExpect(() => {
|
|
163
|
-
expect(onData).toHaveBeenCalledWith([data]);
|
|
164
|
-
});
|
|
165
|
-
}).timeout(5_000);
|
|
166
|
-
|
|
167
|
-
test('swarming with message router', async () => {
|
|
168
|
-
const { swarm1, swarm2, peerId2 } = setup({ router: true });
|
|
169
|
-
|
|
170
|
-
const promise = Promise.all([
|
|
171
|
-
promiseTimeout(swarm1.connected.waitForCount(1), 3000, new Error('Swarm1 connect timeout.')),
|
|
172
|
-
promiseTimeout(swarm2.connected.waitForCount(1), 3000, new Error('Swarm2 connect timeout.'))
|
|
173
|
-
]);
|
|
174
|
-
|
|
175
|
-
swarm1.onPeerCandidatesChanged([peerId2]);
|
|
176
|
-
|
|
177
|
-
log('Candidates changed');
|
|
178
|
-
await promise;
|
|
179
|
-
log('Swarms connected');
|
|
180
|
-
|
|
181
|
-
const swarm1Connection = swarm1.connections[0];
|
|
182
|
-
const swarm2Connection = swarm2.connections[0];
|
|
183
|
-
const onData = mockFn<(data: Buffer) => void>().returns(undefined);
|
|
184
|
-
(swarm2Connection.transport as WebRTCTransport).peer!.on('data', onData);
|
|
185
|
-
|
|
186
|
-
const data = Buffer.from('1234');
|
|
187
|
-
(swarm1Connection.transport as WebRTCTransport).peer!.send(data);
|
|
188
|
-
await waitForExpect(() => {
|
|
189
|
-
expect(onData).toHaveBeenCalledWith([data]);
|
|
190
|
-
});
|
|
191
|
-
await swarm1.destroy();
|
|
192
|
-
await swarm2.destroy();
|
|
193
|
-
}).timeout(5_000);
|
|
233
|
+
}).timeout(5_000);
|
|
234
|
+
});
|
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';
|
|
@@ -12,7 +12,8 @@ import { PublicKey } from '@dxos/protocols';
|
|
|
12
12
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
13
13
|
|
|
14
14
|
import { ProtocolProvider } from '../network-manager';
|
|
15
|
-
import {
|
|
15
|
+
import { SwarmEvent } from '../proto/gen/dxos/mesh/signal';
|
|
16
|
+
import { Answer, SignalMessage } from '../proto/gen/dxos/mesh/signalMessage';
|
|
16
17
|
import { SignalMessaging } from '../signal';
|
|
17
18
|
import { SwarmController, Topology } from '../topology';
|
|
18
19
|
import { TransportFactory } from '../transport';
|
|
@@ -34,7 +35,6 @@ export class Swarm {
|
|
|
34
35
|
|
|
35
36
|
private readonly _connections = new ComplexMap<PublicKey, Connection>(x => x.toHex());
|
|
36
37
|
private readonly _discoveredPeers = new ComplexSet<PublicKey>(x => x.toHex());
|
|
37
|
-
private readonly _peerCandidatesUpdated = new Event();
|
|
38
38
|
|
|
39
39
|
get connections () {
|
|
40
40
|
return Array.from(this._connections.values());
|
|
@@ -64,7 +64,6 @@ export class Swarm {
|
|
|
64
64
|
private _topology: Topology,
|
|
65
65
|
private readonly _protocolProvider: ProtocolProvider,
|
|
66
66
|
private readonly _signalMessaging: SignalMessaging,
|
|
67
|
-
private readonly _lookupPeers: (topic: PublicKey) => void,
|
|
68
67
|
private readonly _transportFactory: TransportFactory,
|
|
69
68
|
private readonly _label: string | undefined
|
|
70
69
|
) {
|
|
@@ -87,26 +86,33 @@ export class Swarm {
|
|
|
87
86
|
return this._topic;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
log(`
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
onSwarmEvent (swarmEvent: SwarmEvent) {
|
|
90
|
+
log(`Swarm event ${JSON.stringify(swarmEvent)}`);
|
|
91
|
+
if (swarmEvent.peerAvailable) {
|
|
92
|
+
const peerId = PublicKey.from(swarmEvent.peerAvailable.peer);
|
|
93
|
+
log(`New peer for ${this._topic} ${peerId}`);
|
|
94
|
+
if (!peerId.equals(this._ownPeerId)) {
|
|
95
|
+
this._discoveredPeers.add(peerId);
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
} else if (swarmEvent.peerLeft) {
|
|
98
|
+
this._discoveredPeers.delete(PublicKey.from(swarmEvent.peerLeft.peer));
|
|
98
99
|
}
|
|
99
|
-
this._peerCandidatesUpdated.emit();
|
|
100
100
|
this._topology.update();
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
async onOffer (message:
|
|
104
|
-
log(`Offer from ${message
|
|
103
|
+
async onOffer (message: SignalMessage): Promise<Answer> {
|
|
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;
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
if (!message.remoteId?.equals(this._ownPeerId)) {
|
|
109
|
+
log(`Rejecting offer with incorrect peerId: ${message.remoteId}`);
|
|
110
|
+
return { accept: false };
|
|
111
|
+
}
|
|
112
|
+
if (!message.topic?.equals(this._topic)) {
|
|
113
|
+
log(`Rejecting offer with incorrect topic: ${message.topic}`);
|
|
114
|
+
return { accept: false };
|
|
115
|
+
}
|
|
110
116
|
|
|
111
117
|
// Check if we are already trying to connect to that peer.
|
|
112
118
|
if (this._connections.has(remoteId)) {
|
|
@@ -140,7 +146,7 @@ export class Swarm {
|
|
|
140
146
|
return { accept };
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
async onSignal (message:
|
|
149
|
+
async onSignal (message: SignalMessage): Promise<void> {
|
|
144
150
|
log(`Signal ${this._topic} ${JSON.stringify(message)}`);
|
|
145
151
|
assert(message.remoteId?.equals(this._ownPeerId), `Invalid signal peer id expected=${this.ownPeerId}, actual=${message.remoteId}`);
|
|
146
152
|
assert(message.topic?.equals(this._topic));
|
|
@@ -186,9 +192,6 @@ export class Swarm {
|
|
|
186
192
|
this.errors.raise(err);
|
|
187
193
|
}
|
|
188
194
|
this._topology.update();
|
|
189
|
-
},
|
|
190
|
-
lookup: () => {
|
|
191
|
-
this._lookupPeers(this._topic);
|
|
192
195
|
}
|
|
193
196
|
};
|
|
194
197
|
}
|
|
@@ -201,6 +204,7 @@ export class Swarm {
|
|
|
201
204
|
|
|
202
205
|
const sessionId = PublicKey.random();
|
|
203
206
|
|
|
207
|
+
log(`Initiate connection: topic=${this._topic} peerId=${remoteId} sessionId=${sessionId}`);
|
|
204
208
|
const connection = this._createConnection(true, remoteId, sessionId);
|
|
205
209
|
this._signalMessaging.offer({
|
|
206
210
|
id: this._ownPeerId,
|
|
@@ -236,7 +240,7 @@ export class Swarm {
|
|
|
236
240
|
}
|
|
237
241
|
|
|
238
242
|
private _createConnection (initiator: boolean, remoteId: PublicKey, sessionId: PublicKey) {
|
|
239
|
-
log(`Create connection topic=${this._topic} remoteId=${remoteId} initiator=${initiator}`);
|
|
243
|
+
log(`Create connection topic=${this._topic} ownId=${this._ownPeerId} remoteId=${remoteId} initiator=${initiator}`);
|
|
240
244
|
assert(!this._connections.has(remoteId), 'Peer already connected.');
|
|
241
245
|
|
|
242
246
|
const connection = new Connection(
|
|
@@ -245,7 +249,7 @@ export class Swarm {
|
|
|
245
249
|
remoteId,
|
|
246
250
|
sessionId,
|
|
247
251
|
initiator,
|
|
248
|
-
(msg:
|
|
252
|
+
(msg: SignalMessage) => this._signalMessaging.signal(msg),
|
|
249
253
|
this._protocolProvider({ channel: discoveryKey(this._topic), initiator }),
|
|
250
254
|
this._transportFactory
|
|
251
255
|
);
|
|
@@ -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
|
|
|
@@ -11,15 +11,9 @@ import { SwarmController, Topology } from './topology';
|
|
|
11
11
|
export class FullyConnectedTopology implements Topology {
|
|
12
12
|
private _controller?: SwarmController;
|
|
13
13
|
|
|
14
|
-
private _intervalId?: NodeJS.Timeout;
|
|
15
|
-
|
|
16
14
|
init (controller: SwarmController): void {
|
|
17
15
|
assert(!this._controller, 'Already initialized');
|
|
18
16
|
this._controller = controller;
|
|
19
|
-
|
|
20
|
-
this._intervalId = setInterval(() => {
|
|
21
|
-
controller.lookup();
|
|
22
|
-
}, 10_000);
|
|
23
17
|
}
|
|
24
18
|
|
|
25
19
|
update (): void {
|
|
@@ -35,9 +29,7 @@ export class FullyConnectedTopology implements Topology {
|
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
async destroy (): Promise<void> {
|
|
38
|
-
|
|
39
|
-
clearInterval(this._intervalId);
|
|
40
|
-
}
|
|
32
|
+
// Nothing to do.
|
|
41
33
|
}
|
|
42
34
|
|
|
43
35
|
toString () {
|
|
@@ -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';
|
|
@@ -36,8 +36,6 @@ export class MMSTTopology implements Topology {
|
|
|
36
36
|
|
|
37
37
|
private _controller?: SwarmController;
|
|
38
38
|
|
|
39
|
-
private _lookupIntervalId?: NodeJS.Timeout;
|
|
40
|
-
|
|
41
39
|
private _sampleCollected = false;
|
|
42
40
|
|
|
43
41
|
constructor ({
|
|
@@ -53,10 +51,6 @@ export class MMSTTopology implements Topology {
|
|
|
53
51
|
init (controller: SwarmController): void {
|
|
54
52
|
assert(!this._controller, 'Already initialized');
|
|
55
53
|
this._controller = controller;
|
|
56
|
-
|
|
57
|
-
this._lookupIntervalId = setInterval(() => {
|
|
58
|
-
controller.lookup();
|
|
59
|
-
}, 10_000);
|
|
60
54
|
}
|
|
61
55
|
|
|
62
56
|
update (): void {
|
|
@@ -79,9 +73,7 @@ export class MMSTTopology implements Topology {
|
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
async destroy (): Promise<void> {
|
|
82
|
-
|
|
83
|
-
clearInterval(this._lookupIntervalId);
|
|
84
|
-
}
|
|
76
|
+
// Nothing to do.
|
|
85
77
|
}
|
|
86
78
|
|
|
87
79
|
private _runAlgorithm () {
|
|
@@ -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
|
|
|
@@ -13,7 +13,6 @@ const log = debug('dxos:network-manager:topology:star');
|
|
|
13
13
|
|
|
14
14
|
export class StarTopology implements Topology {
|
|
15
15
|
private _controller?: SwarmController;
|
|
16
|
-
private _intervalId?: NodeJS.Timeout;
|
|
17
16
|
|
|
18
17
|
constructor (
|
|
19
18
|
private readonly _centralPeer: PublicKey
|
|
@@ -26,9 +25,6 @@ export class StarTopology implements Topology {
|
|
|
26
25
|
init (controller: SwarmController): void {
|
|
27
26
|
assert(!this._controller, 'Already initialized.');
|
|
28
27
|
this._controller = controller;
|
|
29
|
-
this._intervalId = setInterval(() => {
|
|
30
|
-
controller.lookup();
|
|
31
|
-
}, 10_000);
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
update (): void {
|
|
@@ -62,8 +58,6 @@ export class StarTopology implements Topology {
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
async destroy (): Promise<void> {
|
|
65
|
-
|
|
66
|
-
clearInterval(this._intervalId);
|
|
67
|
-
}
|
|
61
|
+
// Nothing to do.
|
|
68
62
|
}
|
|
69
63
|
}
|
package/src/topology/topology.ts
CHANGED
|
@@ -19,13 +19,6 @@ export interface SwarmController {
|
|
|
19
19
|
* Disconnect from a peer.
|
|
20
20
|
*/
|
|
21
21
|
disconnect(peer: PublicKey): void;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Trigger a lookup of any other peers swarming on this topic.
|
|
25
|
-
*
|
|
26
|
-
* Updates will be propagated through `update` method.
|
|
27
|
-
*/
|
|
28
|
-
lookup(): void;
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
export interface SwarmState {
|
|
@@ -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';
|
|
@@ -11,7 +11,7 @@ import { ErrorStream } from '@dxos/debug';
|
|
|
11
11
|
import { PublicKey } from '@dxos/protocols';
|
|
12
12
|
import { ComplexMap } from '@dxos/util';
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { SignalMessage } from '../proto/gen/dxos/mesh/signalMessage';
|
|
15
15
|
import { Transport, TransportFactory } from './transport';
|
|
16
16
|
|
|
17
17
|
const log = debug('dxos:network-manager:swarm:transport:in-memory-transport');
|
|
@@ -79,7 +79,7 @@ export class InMemoryTransport implements Transport {
|
|
|
79
79
|
return this._sessionId;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
async signal (msg:
|
|
82
|
+
async signal (msg: SignalMessage) {
|
|
83
83
|
// No-op.
|
|
84
84
|
}
|
|
85
85
|
|