@dxos/network-manager 0.6.13 → 0.6.14-main.2b6a0f3
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/lib/browser/chunk-GW3YM55A.mjs +14 -0
- package/dist/lib/browser/chunk-GW3YM55A.mjs.map +7 -0
- package/dist/lib/browser/{chunk-XYSYUN63.mjs → chunk-V3IRGRVX.mjs} +1501 -1655
- package/dist/lib/browser/chunk-V3IRGRVX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +347 -22
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +22 -32
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/transport/tcp/index.mjs +39 -0
- package/dist/lib/browser/transport/tcp/index.mjs.map +7 -0
- package/dist/lib/node/{chunk-4YAYC7WN.cjs → chunk-4TTFBX3M.cjs} +1504 -1782
- package/dist/lib/node/chunk-4TTFBX3M.cjs.map +7 -0
- package/dist/lib/node/index.cjs +356 -37
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +24 -34
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/lib/node/transport/tcp/index.cjs +191 -0
- package/dist/lib/node/transport/tcp/index.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-6MN5JVRP.mjs +4035 -0
- package/dist/lib/node-esm/chunk-6MN5JVRP.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +382 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/testing/index.mjs +279 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/lib/node-esm/transport/tcp/index.mjs +159 -0
- package/dist/lib/node-esm/transport/tcp/index.mjs.map +7 -0
- package/dist/types/src/network-manager.d.ts +2 -1
- package/dist/types/src/network-manager.d.ts.map +1 -1
- package/dist/types/src/signal/ice.d.ts.map +1 -1
- package/dist/types/src/signal/integration.node.test.d.ts +2 -0
- package/dist/types/src/signal/integration.node.test.d.ts.map +1 -0
- package/dist/types/src/signal/swarm-messenger.node.test.d.ts +2 -0
- package/dist/types/src/signal/swarm-messenger.node.test.d.ts.map +1 -0
- package/dist/types/src/swarm/connection.d.ts.map +1 -1
- package/dist/types/src/swarm/swarm.d.ts +1 -1
- package/dist/types/src/testing/test-builder.d.ts +2 -2
- package/dist/types/src/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-wire-protocol.d.ts +1 -2
- package/dist/types/src/testing/test-wire-protocol.d.ts.map +1 -1
- package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
- package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
- package/dist/types/src/tests/tcp-transport.node.test.d.ts +2 -0
- package/dist/types/src/tests/tcp-transport.node.test.d.ts.map +1 -0
- package/dist/types/src/tests/utils.d.ts.map +1 -1
- package/dist/types/src/transport/index.d.ts +1 -5
- package/dist/types/src/transport/index.d.ts.map +1 -1
- package/dist/types/src/transport/memory-transport.d.ts +2 -2
- package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
- package/dist/types/src/transport/tcp/index.d.ts +2 -0
- package/dist/types/src/transport/tcp/index.d.ts.map +1 -0
- package/dist/types/src/transport/{tcp-transport.browser.d.ts → tcp/tcp-transport.browser.d.ts} +3 -3
- package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +1 -0
- package/dist/types/src/transport/{tcp-transport.d.ts → tcp/tcp-transport.d.ts} +3 -3
- package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +1 -0
- package/dist/types/src/transport/transport.d.ts +7 -6
- package/dist/types/src/transport/transport.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/index.d.ts +4 -0
- package/dist/types/src/transport/webrtc/index.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts +14 -0
- package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +68 -0
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +33 -0
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts +2 -0
- package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts +4 -0
- package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +1 -0
- package/dist/types/src/transport/{simplepeer-transport-proxy.d.ts → webrtc/rtc-transport-proxy.d.ts} +10 -12
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts +2 -0
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts.map +1 -0
- package/dist/types/src/transport/{simplepeer-transport-service.d.ts → webrtc/rtc-transport-service.d.ts} +9 -7
- package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts +4 -0
- package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts +2 -0
- package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/test-utils.d.ts +5 -0
- package/dist/types/src/transport/webrtc/test-utils.d.ts.map +1 -0
- package/dist/types/src/transport/webrtc/utils.d.ts +3 -0
- package/dist/types/src/transport/webrtc/utils.d.ts.map +1 -0
- package/package.json +56 -30
- package/src/network-manager.ts +5 -13
- package/src/signal/ice.test.ts +1 -3
- package/src/signal/ice.ts +6 -1
- package/src/signal/{integration.test.ts → integration.node.test.ts} +9 -15
- package/src/signal/{swarm-messenger.test.ts → swarm-messenger.node.test.ts} +13 -23
- package/src/swarm/connection-limiter.test.ts +3 -6
- package/src/swarm/connection.test.ts +63 -38
- package/src/swarm/connection.ts +5 -5
- package/src/swarm/swarm.test.ts +10 -12
- package/src/swarm/swarm.ts +1 -1
- package/src/testing/test-builder.ts +13 -29
- package/src/testing/test-wire-protocol.ts +1 -4
- package/src/tests/basic-test-suite.ts +34 -33
- package/src/tests/memory-transport.test.ts +40 -42
- package/src/tests/property-test-suite.ts +21 -22
- package/src/tests/tcp-transport.node.test.ts +65 -0
- package/src/tests/utils.ts +3 -2
- package/src/tests/webrtc-transport.test.ts +9 -9
- package/src/transport/index.ts +1 -5
- package/src/transport/memory-transport.ts +2 -0
- package/src/transport/tcp/index.ts +5 -0
- package/src/transport/{tcp-transport.browser.ts → tcp/tcp-transport.browser.ts} +7 -3
- package/src/transport/{tcp-transport.ts → tcp/tcp-transport.ts} +3 -1
- package/src/transport/transport.ts +8 -7
- package/src/transport/webrtc/index.ts +7 -0
- package/src/transport/webrtc/rtc-connection-factory.ts +82 -0
- package/src/transport/webrtc/rtc-peer-connection.ts +472 -0
- package/src/transport/webrtc/rtc-transport-channel.test.ts +176 -0
- package/src/transport/webrtc/rtc-transport-channel.ts +195 -0
- package/src/transport/webrtc/rtc-transport-factory.ts +28 -0
- package/src/transport/webrtc/rtc-transport-proxy.test.ts +413 -0
- package/src/transport/webrtc/rtc-transport-proxy.ts +264 -0
- package/src/transport/webrtc/rtc-transport-service.ts +192 -0
- package/src/transport/webrtc/rtc-transport-stats.ts +67 -0
- package/src/transport/webrtc/rtc-transport.test.ts +198 -0
- package/src/transport/webrtc/test-utils.ts +22 -0
- package/src/transport/webrtc/utils.ts +36 -0
- package/src/typings.d.ts +8 -2
- package/dist/lib/browser/chunk-XYSYUN63.mjs.map +0 -7
- package/dist/lib/node/chunk-4YAYC7WN.cjs.map +0 -7
- package/dist/types/src/signal/integration.test.d.ts +0 -2
- package/dist/types/src/signal/integration.test.d.ts.map +0 -1
- package/dist/types/src/signal/swarm-messenger.test.d.ts +0 -2
- package/dist/types/src/signal/swarm-messenger.test.d.ts.map +0 -1
- package/dist/types/src/tests/tcp-transport.test.d.ts +0 -2
- package/dist/types/src/tests/tcp-transport.test.d.ts.map +0 -1
- package/dist/types/src/transport/libdatachannel-transport.d.ts +0 -42
- package/dist/types/src/transport/libdatachannel-transport.d.ts.map +0 -1
- package/dist/types/src/transport/libdatachannel-transport.test.d.ts +0 -2
- package/dist/types/src/transport/libdatachannel-transport.test.d.ts.map +0 -1
- package/dist/types/src/transport/memory-transport.test.d.ts +0 -2
- package/dist/types/src/transport/memory-transport.test.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-simple-peer.d.ts +0 -2
- package/dist/types/src/transport/simplepeer-simple-peer.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts +0 -2
- package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-transport.d.ts +0 -36
- package/dist/types/src/transport/simplepeer-transport.d.ts.map +0 -1
- package/dist/types/src/transport/simplepeer-transport.test.d.ts +0 -2
- package/dist/types/src/transport/simplepeer-transport.test.d.ts.map +0 -1
- package/dist/types/src/transport/tcp-transport.browser.d.ts.map +0 -1
- package/dist/types/src/transport/tcp-transport.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc.d.ts +0 -6
- package/dist/types/src/transport/webrtc.d.ts.map +0 -1
- package/src/globals.d.ts +0 -7
- package/src/tests/tcp-transport.test.ts +0 -67
- package/src/transport/libdatachannel-transport.test.ts +0 -100
- package/src/transport/libdatachannel-transport.ts +0 -376
- package/src/transport/memory-transport.test.ts +0 -74
- package/src/transport/simplepeer-simple-peer.ts +0 -26
- package/src/transport/simplepeer-transport-proxy-test.ts +0 -181
- package/src/transport/simplepeer-transport-proxy.ts +0 -246
- package/src/transport/simplepeer-transport-service.ts +0 -160
- package/src/transport/simplepeer-transport.test.ts +0 -61
- package/src/transport/simplepeer-transport.ts +0 -250
- package/src/transport/webrtc.ts +0 -15
package/src/network-manager.ts
CHANGED
|
@@ -152,31 +152,23 @@ export class SwarmNetworkManager {
|
|
|
152
152
|
*/
|
|
153
153
|
@synchronized
|
|
154
154
|
async joinSwarm({
|
|
155
|
-
topic,
|
|
156
|
-
peerInfo,
|
|
155
|
+
topic, //
|
|
157
156
|
topology,
|
|
158
157
|
protocolProvider: protocol,
|
|
159
158
|
label,
|
|
160
159
|
}: SwarmOptions): Promise<SwarmConnection> {
|
|
161
160
|
invariant(PublicKey.isPublicKey(topic));
|
|
162
|
-
if (!peerInfo) {
|
|
163
|
-
peerInfo = {
|
|
164
|
-
peerKey: this._peerInfo?.peerKey ?? PublicKey.random().toHex(),
|
|
165
|
-
identityKey: this._peerInfo?.identityKey ?? PublicKey.random().toHex(),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
invariant(PublicKey.from(peerInfo.peerKey));
|
|
169
|
-
invariant(PublicKey.from(peerInfo.identityKey!));
|
|
170
161
|
invariant(topology);
|
|
162
|
+
invariant(this._peerInfo);
|
|
171
163
|
invariant(typeof protocol === 'function');
|
|
172
164
|
if (this._swarms.has(topic)) {
|
|
173
165
|
throw new Error(`Already connected to swarm: ${PublicKey.from(topic)}`);
|
|
174
166
|
}
|
|
175
167
|
|
|
176
|
-
log('joining', { topic: PublicKey.from(topic), peerInfo, topology: topology.toString() }); // TODO(burdon): Log peerId.
|
|
168
|
+
log('joining', { topic: PublicKey.from(topic), peerInfo: this._peerInfo, topology: topology.toString() }); // TODO(burdon): Log peerId.
|
|
177
169
|
const swarm = new Swarm(
|
|
178
170
|
topic,
|
|
179
|
-
|
|
171
|
+
this._peerInfo,
|
|
180
172
|
topology,
|
|
181
173
|
protocol,
|
|
182
174
|
this._messenger,
|
|
@@ -195,7 +187,7 @@ export class SwarmNetworkManager {
|
|
|
195
187
|
// Open before joining.
|
|
196
188
|
await swarm.open();
|
|
197
189
|
|
|
198
|
-
this._signalConnection.join({ topic, peer:
|
|
190
|
+
this._signalConnection.join({ topic, peer: this._peerInfo }).catch((error) => log.catch(error));
|
|
199
191
|
|
|
200
192
|
this.topicsUpdated.emit();
|
|
201
193
|
this._connectionLog?.joinedSwarm(swarm);
|
package/src/signal/ice.test.ts
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from 'chai';
|
|
6
5
|
import fetchMock from 'fetch-mock';
|
|
7
|
-
|
|
8
|
-
import { test, describe } from '@dxos/test';
|
|
6
|
+
import { afterEach, test, expect, describe } from 'vitest';
|
|
9
7
|
|
|
10
8
|
import { createIceProvider } from './ice';
|
|
11
9
|
|
package/src/signal/ice.ts
CHANGED
|
@@ -24,7 +24,12 @@ export const createIceProvider = (iceProviders: Runtime.Services.IceProvider[]):
|
|
|
24
24
|
iceProviders.map(({ urls }) =>
|
|
25
25
|
asyncTimeout(fetch(urls, { method: 'GET' }), 10_000)
|
|
26
26
|
.then((response) => response.json())
|
|
27
|
-
.catch((err) =>
|
|
27
|
+
.catch((err) => {
|
|
28
|
+
const isDev = typeof window !== 'undefined' && window.location.href.includes('localhost');
|
|
29
|
+
if (!isDev) {
|
|
30
|
+
log.error('Failed to fetch ICE servers from provider', { urls, err });
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
28
33
|
),
|
|
29
34
|
)
|
|
30
35
|
)
|
|
@@ -2,15 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { expect } from 'earljs';
|
|
8
|
-
import waitForExpect from 'wait-for-expect';
|
|
5
|
+
import { afterAll, onTestFinished, beforeAll, describe, expect, test } from 'vitest';
|
|
9
6
|
|
|
10
7
|
import { PublicKey } from '@dxos/keys';
|
|
11
8
|
import { Messenger, type PeerInfo, WebsocketSignalManager } from '@dxos/messaging';
|
|
12
9
|
import { runTestSignalServer, type SignalServerRunner } from '@dxos/signal';
|
|
13
|
-
import { afterAll, afterTest, beforeAll, describe, test } from '@dxos/test';
|
|
14
10
|
|
|
15
11
|
import { type SignalMessage } from './signal-messenger';
|
|
16
12
|
import { SwarmMessenger } from './swarm-messenger';
|
|
@@ -35,13 +31,15 @@ describe('Signal Integration Test', () => {
|
|
|
35
31
|
}) => {
|
|
36
32
|
const signalManager = new WebsocketSignalManager([{ server: broker.url() }]);
|
|
37
33
|
await signalManager.open();
|
|
38
|
-
|
|
34
|
+
onTestFinished(async () => {
|
|
35
|
+
await signalManager.close();
|
|
36
|
+
});
|
|
39
37
|
|
|
40
38
|
const messenger = new Messenger({
|
|
41
39
|
signalManager,
|
|
42
40
|
});
|
|
43
41
|
messenger.open();
|
|
44
|
-
|
|
42
|
+
onTestFinished(() => messenger.close());
|
|
45
43
|
await messenger.listen({
|
|
46
44
|
peer,
|
|
47
45
|
onMessage: async (message) => await messageRouter.receiveMessage(message),
|
|
@@ -96,7 +94,7 @@ describe('Signal Integration Test', () => {
|
|
|
96
94
|
offer: {},
|
|
97
95
|
},
|
|
98
96
|
}),
|
|
99
|
-
).
|
|
97
|
+
).toEqual(expect.objectContaining({ accept: true }));
|
|
100
98
|
|
|
101
99
|
expect(
|
|
102
100
|
await peerNetworking2.messageRouter.offer({
|
|
@@ -108,7 +106,7 @@ describe('Signal Integration Test', () => {
|
|
|
108
106
|
offer: {},
|
|
109
107
|
},
|
|
110
108
|
}),
|
|
111
|
-
).
|
|
109
|
+
).toEqual(expect.objectContaining({ accept: true }));
|
|
112
110
|
|
|
113
111
|
{
|
|
114
112
|
const message: SignalMessage = {
|
|
@@ -123,9 +121,7 @@ describe('Signal Integration Test', () => {
|
|
|
123
121
|
};
|
|
124
122
|
await peerNetworking1.messageRouter.signal(message);
|
|
125
123
|
|
|
126
|
-
await
|
|
127
|
-
expect(peerNetworking2.receivedSignals[0]).toBeAnObjectWith(message);
|
|
128
|
-
});
|
|
124
|
+
await expect.poll(() => peerNetworking2.receivedSignals[0]).toEqual(expect.objectContaining(message));
|
|
129
125
|
}
|
|
130
126
|
|
|
131
127
|
{
|
|
@@ -141,9 +137,7 @@ describe('Signal Integration Test', () => {
|
|
|
141
137
|
};
|
|
142
138
|
await peerNetworking2.messageRouter.signal(message);
|
|
143
139
|
|
|
144
|
-
await
|
|
145
|
-
expect(peerNetworking1.receivedSignals[0]).toBeAnObjectWith(message);
|
|
146
|
-
});
|
|
140
|
+
await expect.poll(() => peerNetworking1.receivedSignals[0]).toEqual(expect.objectContaining(message));
|
|
147
141
|
}
|
|
148
142
|
});
|
|
149
143
|
});
|
|
@@ -2,22 +2,18 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { expect } from 'earljs';
|
|
8
|
-
import waitForExpect from 'wait-for-expect';
|
|
5
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, test, onTestFinished } from 'vitest';
|
|
9
6
|
|
|
10
7
|
import { type Awaited } from '@dxos/async';
|
|
11
8
|
import { PublicKey } from '@dxos/keys';
|
|
12
9
|
import { Messenger, WebsocketSignalManager } from '@dxos/messaging';
|
|
13
10
|
import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
14
11
|
import { runTestSignalServer } from '@dxos/signal';
|
|
15
|
-
import { afterAll, beforeAll, describe, test, afterTest } from '@dxos/test';
|
|
16
12
|
|
|
17
13
|
import { type OfferMessage, type SignalMessage } from './signal-messenger';
|
|
18
14
|
import { SwarmMessenger } from './swarm-messenger';
|
|
19
15
|
|
|
20
|
-
describe('SwarmMessenger', () => {
|
|
16
|
+
describe('SwarmMessenger', { timeout: 7000 }, () => {
|
|
21
17
|
let topic: PublicKey;
|
|
22
18
|
|
|
23
19
|
let broker1: Awaited<ReturnType<typeof runTestSignalServer>>;
|
|
@@ -48,7 +44,9 @@ describe('SwarmMessenger', () => {
|
|
|
48
44
|
const peer = { peerKey: PublicKey.random().toHex() };
|
|
49
45
|
const signalManager = new WebsocketSignalManager([{ server: signalApiUrl }]);
|
|
50
46
|
await signalManager.open();
|
|
51
|
-
|
|
47
|
+
onTestFinished(async () => {
|
|
48
|
+
await signalManager.close();
|
|
49
|
+
});
|
|
52
50
|
|
|
53
51
|
const messenger = new Messenger({ signalManager });
|
|
54
52
|
await messenger.listen({
|
|
@@ -106,10 +104,8 @@ describe('SwarmMessenger', () => {
|
|
|
106
104
|
};
|
|
107
105
|
await router2.signal(msg);
|
|
108
106
|
|
|
109
|
-
await
|
|
110
|
-
|
|
111
|
-
}, 4_000);
|
|
112
|
-
}).timeout(5_000);
|
|
107
|
+
await expect.poll(() => received[0]).toEqual(expect.objectContaining(msg));
|
|
108
|
+
});
|
|
113
109
|
|
|
114
110
|
test('offer/answer', async () => {
|
|
115
111
|
const {
|
|
@@ -139,7 +135,7 @@ describe('SwarmMessenger', () => {
|
|
|
139
135
|
data: { offer: {} },
|
|
140
136
|
});
|
|
141
137
|
expect(answer.accept).toEqual(true);
|
|
142
|
-
})
|
|
138
|
+
});
|
|
143
139
|
|
|
144
140
|
test('signaling between 3 clients', async () => {
|
|
145
141
|
const received1: SignalMessage[] = [];
|
|
@@ -198,9 +194,7 @@ describe('SwarmMessenger', () => {
|
|
|
198
194
|
data: { signal: { payload: { msg: '1to3' } }, signalBatch: undefined },
|
|
199
195
|
};
|
|
200
196
|
await router1.signal(msg1to3);
|
|
201
|
-
await
|
|
202
|
-
expect(received3[0]).toBeAnObjectWith(msg1to3);
|
|
203
|
-
}, 4_000);
|
|
197
|
+
await expect.poll(() => received3[0]).toEqual(expect.objectContaining(msg1to3));
|
|
204
198
|
|
|
205
199
|
// sending signal from peer2 to peer3.
|
|
206
200
|
const msg2to3: SignalMessage = {
|
|
@@ -211,9 +205,7 @@ describe('SwarmMessenger', () => {
|
|
|
211
205
|
data: { signal: { payload: { msg: '2to3' } }, signalBatch: undefined },
|
|
212
206
|
};
|
|
213
207
|
await router2.signal(msg2to3);
|
|
214
|
-
await
|
|
215
|
-
expect(received3[1]).toBeAnObjectWith(msg2to3);
|
|
216
|
-
}, 4_000);
|
|
208
|
+
await expect.poll(() => received3[1]).toEqual(expect.objectContaining(msg2to3));
|
|
217
209
|
|
|
218
210
|
// sending signal from peer3 to peer1.
|
|
219
211
|
const msg3to1: SignalMessage = {
|
|
@@ -224,10 +216,8 @@ describe('SwarmMessenger', () => {
|
|
|
224
216
|
data: { signal: { payload: { msg: '3to1' } }, signalBatch: undefined },
|
|
225
217
|
};
|
|
226
218
|
await router3.signal(msg3to1);
|
|
227
|
-
await
|
|
228
|
-
|
|
229
|
-
}, 4_000);
|
|
230
|
-
}).timeout(5_000);
|
|
219
|
+
await expect.poll(() => received1[0]).toEqual(expect.objectContaining(msg3to1));
|
|
220
|
+
});
|
|
231
221
|
|
|
232
222
|
test('two offers', async () => {
|
|
233
223
|
const {
|
|
@@ -273,5 +263,5 @@ describe('SwarmMessenger', () => {
|
|
|
273
263
|
data: { offer: {} },
|
|
274
264
|
});
|
|
275
265
|
expect(answer2.accept).toEqual(true);
|
|
276
|
-
})
|
|
266
|
+
});
|
|
277
267
|
});
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
|
-
|
|
5
|
-
import
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout } from '@dxos/async';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
|
-
import { describe, test } from '@dxos/test';
|
|
10
9
|
|
|
11
10
|
import { ConnectionLimiter } from './connection-limiter';
|
|
12
11
|
|
|
13
|
-
chai.use(chaiAsPromised);
|
|
14
|
-
|
|
15
12
|
describe('ConnectionLimiter', () => {
|
|
16
13
|
function* setupPeers(
|
|
17
14
|
limiter: ConnectionLimiter,
|
|
@@ -37,7 +34,7 @@ describe('ConnectionLimiter', () => {
|
|
|
37
34
|
test('rejects if done is called', async () => {
|
|
38
35
|
const limiter = new ConnectionLimiter({ maxConcurrentInitConnections: 1 });
|
|
39
36
|
const [first] = setupPeers(limiter);
|
|
40
|
-
const testPromise = expect(first.connecting()).
|
|
37
|
+
const testPromise = expect(first.connecting()).rejects.toBeInstanceOf(Error);
|
|
41
38
|
first.doneConnecting();
|
|
42
39
|
await testPromise;
|
|
43
40
|
});
|
|
@@ -2,78 +2,103 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
5
7
|
import { sleep } from '@dxos/async';
|
|
6
8
|
import { PublicKey } from '@dxos/keys';
|
|
7
|
-
import { describe, test } from '@dxos/test';
|
|
8
9
|
|
|
9
10
|
import { Connection } from './connection';
|
|
10
11
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
11
|
-
import {
|
|
12
|
+
import { createRtcTransportFactory } from '../transport';
|
|
13
|
+
import { chooseInitiatorPeer } from '../transport/webrtc/utils';
|
|
12
14
|
|
|
13
15
|
describe('Connection', () => {
|
|
16
|
+
test('responder opens after initiator', async () => {
|
|
17
|
+
const { initiator, responder } = createPeerKeys();
|
|
18
|
+
await connectionTest({
|
|
19
|
+
fastConnectionKey: initiator,
|
|
20
|
+
slowConnectionKey: responder,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
14
24
|
test('initiator opens after responder', async () => {
|
|
25
|
+
const { initiator, responder } = createPeerKeys();
|
|
26
|
+
await connectionTest({
|
|
27
|
+
fastConnectionKey: responder,
|
|
28
|
+
slowConnectionKey: initiator,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const connectionTest = async (setup: { fastConnectionKey: PublicKey; slowConnectionKey: PublicKey }) => {
|
|
15
33
|
const [topic, sessionId] = PublicKey.randomSequence();
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const
|
|
34
|
+
const slowPeer = { peerKey: setup.slowConnectionKey.toHex() };
|
|
35
|
+
const fastPeer = { peerKey: setup.fastConnectionKey.toHex() };
|
|
36
|
+
|
|
37
|
+
const slowPeerProtocol = new TestWireProtocol();
|
|
38
|
+
const slowConnection = new Connection(
|
|
20
39
|
topic,
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
slowPeer,
|
|
41
|
+
fastPeer,
|
|
23
42
|
sessionId,
|
|
24
43
|
true,
|
|
25
44
|
{
|
|
26
|
-
offer: async (msg) => {
|
|
27
|
-
return { accept: true };
|
|
28
|
-
},
|
|
45
|
+
offer: async (msg) => ({ accept: true }),
|
|
29
46
|
signal: async (msg) => {
|
|
30
|
-
await
|
|
47
|
+
await fastConnection.signal(msg);
|
|
31
48
|
},
|
|
32
49
|
},
|
|
33
|
-
|
|
50
|
+
slowPeerProtocol.factory({
|
|
34
51
|
initiator: true,
|
|
35
|
-
localPeerId: PublicKey.from(
|
|
36
|
-
remotePeerId: PublicKey.from(
|
|
52
|
+
localPeerId: PublicKey.from(slowPeer.peerKey),
|
|
53
|
+
remotePeerId: PublicKey.from(fastPeer.peerKey),
|
|
37
54
|
topic,
|
|
38
55
|
}),
|
|
39
|
-
|
|
40
|
-
process.env.MOCHA_ENV === 'nodejs' ? createLibDataChannelTransportFactory() : createSimplePeerTransportFactory(),
|
|
56
|
+
createRtcTransportFactory(),
|
|
41
57
|
);
|
|
42
58
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
59
|
+
const fastPeerProtocol = new TestWireProtocol();
|
|
60
|
+
const fastConnection = new Connection(
|
|
45
61
|
topic,
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
fastPeer,
|
|
63
|
+
slowPeer,
|
|
48
64
|
sessionId,
|
|
49
65
|
false,
|
|
50
66
|
{
|
|
51
|
-
offer: async (msg) => {
|
|
52
|
-
return { accept: true };
|
|
53
|
-
},
|
|
67
|
+
offer: async (msg) => ({ accept: true }),
|
|
54
68
|
signal: async (msg) => {
|
|
55
|
-
await
|
|
69
|
+
await slowConnection.signal(msg);
|
|
56
70
|
},
|
|
57
71
|
},
|
|
58
|
-
|
|
72
|
+
fastPeerProtocol.factory({
|
|
59
73
|
initiator: false,
|
|
60
|
-
localPeerId: PublicKey.from(
|
|
61
|
-
remotePeerId: PublicKey.from(
|
|
74
|
+
localPeerId: PublicKey.from(fastPeer.peerKey),
|
|
75
|
+
remotePeerId: PublicKey.from(slowPeer.peerKey),
|
|
62
76
|
topic,
|
|
63
77
|
}),
|
|
64
|
-
|
|
65
|
-
process.env.MOCHA_ENV === 'nodejs' ? createLibDataChannelTransportFactory() : createSimplePeerTransportFactory(),
|
|
78
|
+
createRtcTransportFactory(),
|
|
66
79
|
);
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
await
|
|
70
|
-
await sleep(
|
|
81
|
+
fastConnection.initiate();
|
|
82
|
+
await fastConnection.openConnection();
|
|
83
|
+
await sleep(200);
|
|
84
|
+
|
|
85
|
+
slowConnection.initiate();
|
|
86
|
+
await slowConnection.openConnection();
|
|
71
87
|
|
|
72
|
-
connection1.initiate();
|
|
73
|
-
await connection1.openConnection();
|
|
74
88
|
await Promise.all([
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
slowPeerProtocol.testConnection(PublicKey.from(fastPeer.peerKey), 'test message 1'),
|
|
90
|
+
fastPeerProtocol.testConnection(PublicKey.from(slowPeer.peerKey), 'test message 2'),
|
|
77
91
|
]);
|
|
78
|
-
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const createPeerKeys = () => {
|
|
95
|
+
const peer1 = PublicKey.random();
|
|
96
|
+
const peer2 = PublicKey.random();
|
|
97
|
+
const initiator = PublicKey.fromHex(chooseInitiatorPeer(peer1.toHex(), peer2.toHex()));
|
|
98
|
+
if (initiator.equals(peer1)) {
|
|
99
|
+
return { initiator: peer1, responder: peer2 };
|
|
100
|
+
} else {
|
|
101
|
+
return { initiator: peer2, responder: peer1 };
|
|
102
|
+
}
|
|
103
|
+
};
|
|
79
104
|
});
|
package/src/swarm/connection.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
ConnectionResetError,
|
|
16
16
|
ConnectivityError,
|
|
17
17
|
TimeoutError,
|
|
18
|
-
UnknownProtocolError,
|
|
19
18
|
trace,
|
|
20
19
|
} from '@dxos/protocols';
|
|
21
20
|
import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
@@ -202,14 +201,15 @@ export class Connection {
|
|
|
202
201
|
|
|
203
202
|
invariant(!this._transport);
|
|
204
203
|
this._transport = this._transportFactory.createTransport({
|
|
204
|
+
ownPeerKey: this.localInfo.peerKey,
|
|
205
|
+
remotePeerKey: this.remoteInfo.peerKey,
|
|
206
|
+
topic: this.topic.toHex(),
|
|
205
207
|
initiator: this.initiator,
|
|
206
208
|
stream: this._protocol.stream,
|
|
207
209
|
sendSignal: async (signal) => this._sendSignal(signal),
|
|
208
210
|
sessionId: this.sessionId,
|
|
209
211
|
});
|
|
210
212
|
|
|
211
|
-
await this._transport.open();
|
|
212
|
-
|
|
213
213
|
this._transport.connected.once(async () => {
|
|
214
214
|
this._changeState(ConnectionState.CONNECTED);
|
|
215
215
|
await this.connectedTimeoutContext.dispose();
|
|
@@ -238,8 +238,6 @@ export class Connection {
|
|
|
238
238
|
} else if (err instanceof ConnectivityError) {
|
|
239
239
|
log.info('aborting due to transport ConnectivityError');
|
|
240
240
|
this.abort().catch((err) => this.errors.raise(err));
|
|
241
|
-
} else if (err instanceof UnknownProtocolError) {
|
|
242
|
-
log.warn('unsure what to do with UnknownProtocolError, will keep on truckin', { err });
|
|
243
241
|
}
|
|
244
242
|
|
|
245
243
|
if (this._state !== ConnectionState.CLOSED && this._state !== ConnectionState.CLOSING) {
|
|
@@ -248,6 +246,8 @@ export class Connection {
|
|
|
248
246
|
}
|
|
249
247
|
});
|
|
250
248
|
|
|
249
|
+
await this._transport.open();
|
|
250
|
+
|
|
251
251
|
// Replay signals that were received before transport was created.
|
|
252
252
|
for (const signal of this._incomingSignalBuffer) {
|
|
253
253
|
void this._transport.onSignal(signal); // TODO(burdon): Remove async?
|
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { onTestFinished, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, sleep } from '@dxos/async';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
type PeerInfo,
|
|
14
14
|
type SignalManager,
|
|
15
15
|
} from '@dxos/messaging';
|
|
16
|
-
import { afterTest, describe, test } from '@dxos/test';
|
|
17
16
|
import { ComplexSet } from '@dxos/util';
|
|
18
17
|
|
|
19
18
|
import { ConnectionState } from './connection';
|
|
@@ -21,7 +20,7 @@ import { ConnectionLimiter } from './connection-limiter';
|
|
|
21
20
|
import { Swarm } from './swarm';
|
|
22
21
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
23
22
|
import { FullyConnectedTopology } from '../topology';
|
|
24
|
-
import {
|
|
23
|
+
import { createRtcTransportFactory } from '../transport';
|
|
25
24
|
|
|
26
25
|
type TestPeer = {
|
|
27
26
|
swarm: Swarm;
|
|
@@ -47,21 +46,20 @@ describe('Swarm', () => {
|
|
|
47
46
|
signalManager?: SignalManager;
|
|
48
47
|
initiationDelay?: number;
|
|
49
48
|
}): Promise<TestPeer> => {
|
|
50
|
-
const protocol = new TestWireProtocol(
|
|
49
|
+
const protocol = new TestWireProtocol();
|
|
51
50
|
const swarm = new Swarm(
|
|
52
51
|
topic,
|
|
53
52
|
peer,
|
|
54
53
|
new FullyConnectedTopology(),
|
|
55
54
|
protocol.factory,
|
|
56
55
|
new Messenger({ signalManager }),
|
|
57
|
-
|
|
58
|
-
process.env.MOCHA_ENV === 'nodejs' ? createLibDataChannelTransportFactory() : createSimplePeerTransportFactory(),
|
|
56
|
+
createRtcTransportFactory(),
|
|
59
57
|
undefined,
|
|
60
58
|
connectionLimiter,
|
|
61
59
|
initiationDelay,
|
|
62
60
|
);
|
|
63
61
|
|
|
64
|
-
|
|
62
|
+
onTestFinished(async () => {
|
|
65
63
|
await swarm.destroy();
|
|
66
64
|
await signalManager.close();
|
|
67
65
|
});
|
|
@@ -81,7 +79,7 @@ describe('Swarm', () => {
|
|
|
81
79
|
expect(peer2.swarm.connections.length).to.equal(0);
|
|
82
80
|
|
|
83
81
|
await connectSwarms(peer1, peer2);
|
|
84
|
-
})
|
|
82
|
+
});
|
|
85
83
|
|
|
86
84
|
test('two peers try to originate connections to each other simultaneously', async () => {
|
|
87
85
|
const topic = PublicKey.random();
|
|
@@ -93,7 +91,7 @@ describe('Swarm', () => {
|
|
|
93
91
|
expect(peer2.swarm.connections.length).to.equal(0);
|
|
94
92
|
|
|
95
93
|
await connectSwarms(peer1, peer2);
|
|
96
|
-
})
|
|
94
|
+
});
|
|
97
95
|
|
|
98
96
|
test('with simultaneous connections one of the peers drops initiated connection', async () => {
|
|
99
97
|
const topic = PublicKey.random();
|
|
@@ -111,9 +109,9 @@ describe('Swarm', () => {
|
|
|
111
109
|
|
|
112
110
|
await connectSwarms(peer1, peer2);
|
|
113
111
|
await asyncTimeout(connectionDisplaced!, 1000);
|
|
114
|
-
})
|
|
112
|
+
});
|
|
115
113
|
|
|
116
|
-
test('second peer discovered after delay', async () => {
|
|
114
|
+
test('second peer discovered after delay', { timeout: 10_000 }, async () => {
|
|
117
115
|
const topic = PublicKey.random();
|
|
118
116
|
|
|
119
117
|
const peer1 = await setupSwarm({ topic });
|
|
@@ -126,7 +124,7 @@ describe('Swarm', () => {
|
|
|
126
124
|
expect(peer2.swarm.connections.length).to.equal(0);
|
|
127
125
|
|
|
128
126
|
await connectSwarms(peer1, peer2, () => sleep(15));
|
|
129
|
-
})
|
|
127
|
+
});
|
|
130
128
|
|
|
131
129
|
test('connection limiter', async () => {
|
|
132
130
|
// remotePeer1 <--> peer (connectionLimiter: max = 1) <--> remotePeer2
|
package/src/swarm/swarm.ts
CHANGED
|
@@ -29,7 +29,7 @@ const getClassName = (obj: any) => Object.getPrototypeOf(obj).constructor.name;
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* A single peer's view of the swarm.
|
|
32
|
-
* Manages a set of
|
|
32
|
+
* Manages a set of peers subscribed on the same topic.
|
|
33
33
|
* Routes signal events and maintains swarm topology.
|
|
34
34
|
*/
|
|
35
35
|
export class Swarm {
|
|
@@ -16,19 +16,12 @@ import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
|
16
16
|
import { createLinkedPorts, createProtoRpcPeer, type ProtoRpcPeer } from '@dxos/rpc';
|
|
17
17
|
import { ComplexMap } from '@dxos/util';
|
|
18
18
|
|
|
19
|
+
import { TcpTransportFactory } from '#tcp-transport';
|
|
19
20
|
import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
|
|
20
21
|
import { SwarmNetworkManager } from '../network-manager';
|
|
21
22
|
import { FullyConnectedTopology } from '../topology';
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
createSimplePeerTransportFactory,
|
|
25
|
-
MemoryTransportFactory,
|
|
26
|
-
SimplePeerTransportProxyFactory,
|
|
27
|
-
SimplePeerTransportService,
|
|
28
|
-
type TransportFactory,
|
|
29
|
-
TransportKind,
|
|
30
|
-
} from '../transport';
|
|
31
|
-
import { TcpTransportFactory } from '../transport/tcp-transport';
|
|
23
|
+
import { MemoryTransportFactory, type TransportFactory, TransportKind } from '../transport';
|
|
24
|
+
import { createRtcTransportFactory, RtcTransportProxyFactory, RtcTransportService } from '../transport';
|
|
32
25
|
|
|
33
26
|
// Signal server will be started by the setup script.
|
|
34
27
|
const port = process.env.SIGNAL_PORT ?? 4000;
|
|
@@ -85,18 +78,12 @@ export class TestPeer {
|
|
|
85
78
|
constructor(
|
|
86
79
|
private readonly testBuilder: TestBuilder,
|
|
87
80
|
public readonly peerId: PublicKey,
|
|
88
|
-
public readonly transport
|
|
81
|
+
public readonly transport: TransportKind = testBuilder.options.signalHosts
|
|
82
|
+
? TransportKind.WEB_RTC
|
|
83
|
+
: TransportKind.MEMORY,
|
|
89
84
|
) {
|
|
90
85
|
this._signalManager = this.testBuilder.createSignalManager();
|
|
91
|
-
|
|
92
|
-
if (this.testBuilder.options.signalHosts) {
|
|
93
|
-
// TODO(nf): configure better
|
|
94
|
-
transport = process.env.MOCHA_ENV === 'nodejs' ? TransportKind.LIBDATACHANNEL : TransportKind.SIMPLE_PEER;
|
|
95
|
-
} else {
|
|
96
|
-
transport = TransportKind.MEMORY;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
this._networkManager = this.createNetworkManager(transport);
|
|
86
|
+
this._networkManager = this.createNetworkManager(this.transport);
|
|
100
87
|
}
|
|
101
88
|
|
|
102
89
|
// TODO(burdon): Move to TestBuilder.
|
|
@@ -110,13 +97,10 @@ export class TestPeer {
|
|
|
110
97
|
case TransportKind.TCP:
|
|
111
98
|
transportFactory = TcpTransportFactory;
|
|
112
99
|
break;
|
|
113
|
-
case TransportKind.
|
|
114
|
-
transportFactory =
|
|
115
|
-
break;
|
|
116
|
-
case TransportKind.LIBDATACHANNEL:
|
|
117
|
-
transportFactory = createLibDataChannelTransportFactory();
|
|
100
|
+
case TransportKind.WEB_RTC:
|
|
101
|
+
transportFactory = createRtcTransportFactory();
|
|
118
102
|
break;
|
|
119
|
-
case TransportKind.
|
|
103
|
+
case TransportKind.WEB_RTC_PROXY:
|
|
120
104
|
{
|
|
121
105
|
// Simulates bridge to shared worker.
|
|
122
106
|
const [proxyPort, servicePort] = createLinkedPorts();
|
|
@@ -137,14 +121,14 @@ export class TestPeer {
|
|
|
137
121
|
exposed: {
|
|
138
122
|
BridgeService: schema.getService('dxos.mesh.bridge.BridgeService'),
|
|
139
123
|
},
|
|
140
|
-
handlers: { BridgeService: new
|
|
124
|
+
handlers: { BridgeService: new RtcTransportService() },
|
|
141
125
|
noHandshake: true,
|
|
142
126
|
encodingOptions: {
|
|
143
127
|
preserveAny: true,
|
|
144
128
|
},
|
|
145
129
|
});
|
|
146
130
|
|
|
147
|
-
transportFactory = new
|
|
131
|
+
transportFactory = new RtcTransportProxyFactory().setBridgeService(this._proxy.rpc.BridgeService);
|
|
148
132
|
}
|
|
149
133
|
break;
|
|
150
134
|
default:
|
|
@@ -219,7 +203,7 @@ export class TestSwarmConnection {
|
|
|
219
203
|
) {
|
|
220
204
|
// TODO(burdon): Configure plugins.
|
|
221
205
|
// TODO(burdon): Prevent reuse?
|
|
222
|
-
this.protocol = new TestWireProtocol(this.
|
|
206
|
+
this.protocol = new TestWireProtocol(this.extensionFactory);
|
|
223
207
|
}
|
|
224
208
|
|
|
225
209
|
// TODO(burdon): Need to create new plugin instance per swarm?
|
|
@@ -29,10 +29,7 @@ export class TestWireProtocol {
|
|
|
29
29
|
({ remotePeerId, extension }) => remotePeerId.toHex() + extension,
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
constructor(
|
|
33
|
-
public readonly peerId: PublicKey,
|
|
34
|
-
private readonly _extensionFactory: TestTeleportExtensionFactory = () => [],
|
|
35
|
-
) {}
|
|
32
|
+
constructor(private readonly _extensionFactory: TestTeleportExtensionFactory = () => []) {}
|
|
36
33
|
|
|
37
34
|
readonly factory = createTeleportProtocolFactory(async (teleport) => {
|
|
38
35
|
log('create', { remotePeerId: teleport.remotePeerId });
|