@dxos/network-manager 2.31.6 → 2.31.8-dev.47b118c8
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 +48 -49
- package/dist/src/network-manager.blueprint-test.d.ts.map +1 -1
- package/dist/src/network-manager.blueprint-test.js +29 -31
- package/dist/src/network-manager.blueprint-test.js.map +1 -1
- package/dist/src/network-manager.d.ts +2 -2
- package/dist/src/network-manager.d.ts.map +1 -1
- package/dist/src/network-manager.js +12 -8
- package/dist/src/network-manager.js.map +1 -1
- package/dist/src/swarm/swarm.d.ts.map +1 -1
- package/dist/src/swarm/swarm.js +1 -0
- package/dist/src/swarm/swarm.js.map +1 -1
- package/dist/src/transport/in-memory-transport.d.ts.map +1 -1
- package/dist/src/transport/in-memory-transport.js +5 -2
- package/dist/src/transport/in-memory-transport.js.map +1 -1
- package/dist/src/transport/in-memory-transport.test.js.map +1 -1
- package/dist/src/transport/webrtc-transport.d.ts +1 -1
- package/dist/src/transport/webrtc-transport.d.ts.map +1 -1
- package/dist/src/transport/webrtc-transport.js +2 -2
- package/dist/src/transport/webrtc-transport.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
- package/src/network-manager.blueprint-test.ts +31 -33
- package/src/network-manager.ts +34 -25
- package/src/swarm/swarm.ts +1 -0
- package/src/transport/in-memory-transport.test.ts +2 -0
- package/src/transport/in-memory-transport.ts +9 -6
- package/src/transport/webrtc-transport.ts +2 -2
|
@@ -276,6 +276,8 @@ export function inMemoryTests () {
|
|
|
276
276
|
peers: ComplexSet<PublicKey>
|
|
277
277
|
joinedPeers: ComplexSet<PublicKey>
|
|
278
278
|
}
|
|
279
|
+
|
|
280
|
+
// TODO(burdon): Name?
|
|
279
281
|
interface Real {
|
|
280
282
|
peers: ComplexMap<PublicKey, {
|
|
281
283
|
networkManager: NetworkManager
|
|
@@ -283,11 +285,11 @@ export function inMemoryTests () {
|
|
|
283
285
|
}>
|
|
284
286
|
}
|
|
285
287
|
|
|
286
|
-
async function assertState (
|
|
288
|
+
async function assertState (model: Model, real: Real) {
|
|
287
289
|
await waitForExpect(() => {
|
|
288
|
-
for (const peer of
|
|
290
|
+
for (const peer of real.peers.values()) {
|
|
289
291
|
if (peer.presence) {
|
|
290
|
-
for (const expectedJoinedPeer of
|
|
292
|
+
for (const expectedJoinedPeer of model.joinedPeers) {
|
|
291
293
|
if (expectedJoinedPeer.equals(peer.presence.peerId)) {
|
|
292
294
|
continue;
|
|
293
295
|
}
|
|
@@ -301,7 +303,7 @@ export function inMemoryTests () {
|
|
|
301
303
|
}
|
|
302
304
|
}, 5_000);
|
|
303
305
|
|
|
304
|
-
|
|
306
|
+
real.peers.forEach(peer => peer.networkManager.topics.forEach(topic => {
|
|
305
307
|
peer.networkManager.getSwarm(topic)!.errors.assertNoUnhandledErrors();
|
|
306
308
|
}));
|
|
307
309
|
}
|
|
@@ -309,19 +311,19 @@ export function inMemoryTests () {
|
|
|
309
311
|
class CreatePeerCommand implements fc.AsyncCommand<Model, Real> {
|
|
310
312
|
constructor (readonly peerId: PublicKey) {}
|
|
311
313
|
|
|
312
|
-
check = (
|
|
314
|
+
check = (model: Model) => !model.peers.has(this.peerId);
|
|
313
315
|
|
|
314
|
-
async run (
|
|
315
|
-
|
|
316
|
+
async run (model: Model, real: Real) {
|
|
317
|
+
model.peers.add(this.peerId);
|
|
316
318
|
|
|
317
319
|
const networkManager = new NetworkManager();
|
|
318
320
|
afterTest(() => networkManager.destroy());
|
|
319
321
|
|
|
320
|
-
|
|
322
|
+
real.peers.set(this.peerId, {
|
|
321
323
|
networkManager
|
|
322
324
|
});
|
|
323
325
|
|
|
324
|
-
await assertState(
|
|
326
|
+
await assertState(model, real);
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
toString = () => `CreatePeer(${this.peerId})`;
|
|
@@ -330,17 +332,17 @@ export function inMemoryTests () {
|
|
|
330
332
|
class RemovePeerCommand implements fc.AsyncCommand<Model, Real> {
|
|
331
333
|
constructor (readonly peerId: PublicKey) {}
|
|
332
334
|
|
|
333
|
-
check = (
|
|
335
|
+
check = (model: Model) => model.peers.has(this.peerId);
|
|
334
336
|
|
|
335
|
-
async run (
|
|
336
|
-
|
|
337
|
-
|
|
337
|
+
async run (model: Model, real: Real) {
|
|
338
|
+
model.peers.delete(this.peerId);
|
|
339
|
+
model.joinedPeers.delete(this.peerId);
|
|
338
340
|
|
|
339
|
-
const peer =
|
|
341
|
+
const peer = real.peers.get(this.peerId);
|
|
340
342
|
await peer!.networkManager.destroy();
|
|
341
|
-
|
|
343
|
+
real.peers.delete(this.peerId);
|
|
342
344
|
|
|
343
|
-
await assertState(
|
|
345
|
+
await assertState(model, real);
|
|
344
346
|
}
|
|
345
347
|
|
|
346
348
|
toString = () => `RemovePeer(${this.peerId})`;
|
|
@@ -349,22 +351,20 @@ export function inMemoryTests () {
|
|
|
349
351
|
class JoinTopicCommand implements fc.AsyncCommand<Model, Real> {
|
|
350
352
|
constructor (readonly peerId: PublicKey) {}
|
|
351
353
|
|
|
352
|
-
check = (
|
|
353
|
-
m.peers.has(this.peerId) &&
|
|
354
|
-
!m.joinedPeers.has(this.peerId);
|
|
354
|
+
check = (model: Model) => model.peers.has(this.peerId) && !model.joinedPeers.has(this.peerId);
|
|
355
355
|
|
|
356
|
-
async run (
|
|
357
|
-
|
|
356
|
+
async run (model: Model, real: Real) {
|
|
357
|
+
model.joinedPeers.add(this.peerId);
|
|
358
358
|
|
|
359
|
-
const peer =
|
|
359
|
+
const peer = real.peers.get(this.peerId)!;
|
|
360
360
|
|
|
361
361
|
const presence = new PresencePlugin(this.peerId.asBuffer());
|
|
362
362
|
afterTest(() => presence.stop());
|
|
363
|
-
const protocol = createProtocolFactory(
|
|
363
|
+
const protocol = createProtocolFactory(model.topic, this.peerId, [presence]);
|
|
364
364
|
|
|
365
365
|
peer.networkManager.joinProtocolSwarm({
|
|
366
366
|
peerId: this.peerId, // TODO(burdon): `this`?
|
|
367
|
-
topic:
|
|
367
|
+
topic: model.topic,
|
|
368
368
|
protocol,
|
|
369
369
|
topology: new FullyConnectedTopology(),
|
|
370
370
|
presence
|
|
@@ -372,7 +372,7 @@ export function inMemoryTests () {
|
|
|
372
372
|
|
|
373
373
|
peer.presence = presence;
|
|
374
374
|
|
|
375
|
-
await assertState(
|
|
375
|
+
await assertState(model, real);
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
toString = () => `JoinTopic(peerId=${this.peerId})`;
|
|
@@ -381,19 +381,17 @@ export function inMemoryTests () {
|
|
|
381
381
|
class LeaveTopicCommand implements fc.AsyncCommand<Model, Real> {
|
|
382
382
|
constructor (readonly peerId: PublicKey) {}
|
|
383
383
|
|
|
384
|
-
check = (
|
|
385
|
-
m.peers.has(this.peerId) &&
|
|
386
|
-
m.joinedPeers.has(this.peerId);
|
|
384
|
+
check = (model: Model) => model.peers.has(this.peerId) && model.joinedPeers.has(this.peerId);
|
|
387
385
|
|
|
388
|
-
async run (
|
|
389
|
-
|
|
386
|
+
async run (model: Model, real: Real) {
|
|
387
|
+
model.joinedPeers.delete(this.peerId);
|
|
390
388
|
|
|
391
|
-
const peer =
|
|
389
|
+
const peer = real.peers.get(this.peerId)!;
|
|
392
390
|
|
|
393
|
-
await peer.networkManager.leaveProtocolSwarm(
|
|
391
|
+
await peer.networkManager.leaveProtocolSwarm(model.topic);
|
|
394
392
|
peer.presence = undefined;
|
|
395
393
|
|
|
396
|
-
await assertState(
|
|
394
|
+
await assertState(model, real);
|
|
397
395
|
}
|
|
398
396
|
|
|
399
397
|
toString = () => `LeaveTopic(peerId=${this.peerId})`;
|
package/src/network-manager.ts
CHANGED
|
@@ -35,35 +35,24 @@ const log = debug('dxos:network-manager');
|
|
|
35
35
|
*/
|
|
36
36
|
export class NetworkManager {
|
|
37
37
|
private readonly _ice?: any[];
|
|
38
|
-
private readonly _swarms = new ComplexMap<PublicKey, Swarm>(
|
|
39
|
-
private readonly _maps = new ComplexMap<PublicKey, SwarmMapper>(
|
|
38
|
+
private readonly _swarms = new ComplexMap<PublicKey, Swarm>(key => key.toHex());
|
|
39
|
+
private readonly _maps = new ComplexMap<PublicKey, SwarmMapper>(key => key.toHex());
|
|
40
40
|
private readonly _signal: SignalManager;
|
|
41
41
|
private readonly _connectionLog?: ConnectionLog;
|
|
42
42
|
|
|
43
43
|
public readonly topicsUpdated = new Event<void>();
|
|
44
44
|
|
|
45
|
-
get signal () {
|
|
46
|
-
return this._signal;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
get topics () {
|
|
50
|
-
return Array.from(this._swarms.keys());
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get connectionLog () {
|
|
54
|
-
return this._connectionLog;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
45
|
constructor (options: NetworkManagerOptions = {}) {
|
|
58
46
|
this._ice = options.ice ?? [];
|
|
59
47
|
|
|
60
|
-
const onOffer = async (
|
|
61
|
-
|
|
48
|
+
const onOffer = async (message: SignalApi.SignalMessage) =>
|
|
49
|
+
await this._swarms.get(message.topic)?.onOffer(message) ?? { accept: false };
|
|
62
50
|
this._signal = options.signal
|
|
63
51
|
? new WebsocketSignalManager(options.signal, onOffer)
|
|
64
52
|
: new InMemorySignalManager(onOffer);
|
|
65
53
|
|
|
66
|
-
this._signal.peerCandidatesChanged.on(([topic, candidates]) =>
|
|
54
|
+
this._signal.peerCandidatesChanged.on(([topic, candidates]) =>
|
|
55
|
+
this._swarms.get(topic)?.onPeerCandidatesChanged(candidates));
|
|
67
56
|
this._signal.onSignal.on(msg => this._swarms.get(msg.topic)?.onSignal(msg));
|
|
68
57
|
|
|
69
58
|
if (options.log) {
|
|
@@ -71,6 +60,18 @@ export class NetworkManager {
|
|
|
71
60
|
}
|
|
72
61
|
}
|
|
73
62
|
|
|
63
|
+
get signal () {
|
|
64
|
+
return this._signal;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get topics () {
|
|
68
|
+
return Array.from(this._swarms.keys());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get connectionLog () {
|
|
72
|
+
return this._connectionLog;
|
|
73
|
+
}
|
|
74
|
+
|
|
74
75
|
getSwarmMap (topic: PublicKey): SwarmMapper | undefined {
|
|
75
76
|
return this._maps.get(topic);
|
|
76
77
|
}
|
|
@@ -80,29 +81,36 @@ export class NetworkManager {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
joinProtocolSwarm (options: SwarmOptions) {
|
|
84
|
+
// TODO(burdon): Use TS to constrain properties.
|
|
83
85
|
assert(typeof options === 'object', 'Incorrect arguments format.');
|
|
84
86
|
const { topic, peerId, topology, protocol, presence } = options;
|
|
85
87
|
assert(PublicKey.isPublicKey(topic), 'Incorrect arguments format.');
|
|
86
88
|
assert(PublicKey.isPublicKey(peerId), 'Incorrect arguments format.');
|
|
87
89
|
assert(topology, 'Incorrect arguments format.');
|
|
88
90
|
assert(typeof protocol === 'function', 'Incorrect arguments format.');
|
|
89
|
-
log(`Join ${options.topic} as ${options.peerId} with ${options.topology.toString()} topology.`);
|
|
90
91
|
|
|
92
|
+
log(`Join ${options.topic} as ${options.peerId} with ${options.topology.toString()} topology.`);
|
|
91
93
|
if (this._swarms.has(topic)) {
|
|
92
|
-
throw new ERR_EXTENSION_RESPONSE_FAILED(
|
|
94
|
+
throw new ERR_EXTENSION_RESPONSE_FAILED(
|
|
95
|
+
GreetingCommandPlugin.EXTENSION_NAME, ERR_GREET_ALREADY_CONNECTED_TO_SWARM, `Already connected to swarm ${topic}`);
|
|
93
96
|
}
|
|
94
97
|
|
|
98
|
+
// TODO(burdon): Bundle common transport related classes.
|
|
99
|
+
const transportFactory = this._signal instanceof InMemorySignalManager
|
|
100
|
+
? inMemoryTransportFactory : createWebRtcTransportFactory({ iceServers: this._ice });
|
|
101
|
+
|
|
95
102
|
const swarm = new Swarm(
|
|
96
103
|
topic,
|
|
97
104
|
peerId,
|
|
98
105
|
topology,
|
|
99
106
|
protocol,
|
|
107
|
+
|
|
108
|
+
// TODO(burdon): Merge.
|
|
100
109
|
async offer => this._signal.offer(offer),
|
|
101
110
|
async msg => this._signal.signal(msg),
|
|
102
|
-
() =>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this._signal instanceof InMemorySignalManager ? inMemoryTransportFactory : createWebRtcTransportFactory({ iceServers: this._ice }),
|
|
111
|
+
() => this._signal.lookup(topic),
|
|
112
|
+
|
|
113
|
+
transportFactory,
|
|
106
114
|
options.label
|
|
107
115
|
);
|
|
108
116
|
|
|
@@ -144,10 +152,10 @@ export class NetworkManager {
|
|
|
144
152
|
await this.topicsUpdated.emit();
|
|
145
153
|
}
|
|
146
154
|
|
|
147
|
-
// TODO(marik-d): Remove.
|
|
148
155
|
/**
|
|
149
|
-
* @
|
|
156
|
+
* @deprecated
|
|
150
157
|
*/
|
|
158
|
+
// TODO(marik-d): Remove.
|
|
151
159
|
async start () {
|
|
152
160
|
console.warn('NetworkManger.start is deprecated.');
|
|
153
161
|
}
|
|
@@ -159,6 +167,7 @@ export class NetworkManager {
|
|
|
159
167
|
log(err);
|
|
160
168
|
});
|
|
161
169
|
}
|
|
170
|
+
|
|
162
171
|
await this._signal.destroy();
|
|
163
172
|
}
|
|
164
173
|
}
|
package/src/swarm/swarm.ts
CHANGED
|
@@ -32,6 +32,7 @@ function createPair () {
|
|
|
32
32
|
topic,
|
|
33
33
|
protocolProvider1({ channel: discoveryKey(topic), initiator: true }).stream
|
|
34
34
|
);
|
|
35
|
+
|
|
35
36
|
afterTest(() => connection1.close());
|
|
36
37
|
afterTest(() => connection1.errors.assertNoUnhandledErrors());
|
|
37
38
|
|
|
@@ -44,6 +45,7 @@ function createPair () {
|
|
|
44
45
|
topic,
|
|
45
46
|
protocolProvider2({ channel: discoveryKey(topic), initiator: false }).stream
|
|
46
47
|
);
|
|
48
|
+
|
|
47
49
|
afterTest(() => connection2.close());
|
|
48
50
|
afterTest(() => connection2.errors.assertNoUnhandledErrors());
|
|
49
51
|
|
|
@@ -16,17 +16,20 @@ import { Transport, TransportFactory } from './transport';
|
|
|
16
16
|
|
|
17
17
|
const log = debug('dxos:network-manager:swarm:transport:in-memory-transport');
|
|
18
18
|
|
|
19
|
-
type ConnectionKey = [topic: PublicKey, nodeId: PublicKey, remoteId: PublicKey]
|
|
19
|
+
type ConnectionKey = [topic: PublicKey, nodeId: PublicKey, remoteId: PublicKey]
|
|
20
20
|
|
|
21
21
|
// Delay (in milliseconds) for data being sent through in-memory connections to simulate network latency.
|
|
22
22
|
const IN_MEMORY_TRANSPORT_DELAY = 1;
|
|
23
23
|
|
|
24
|
+
// TODO(burdon): Rename.
|
|
24
25
|
export class InMemoryTransport implements Transport {
|
|
25
|
-
|
|
26
|
+
|
|
27
|
+
// TODO(burdon): Remove global properties.
|
|
28
|
+
private static readonly _connections = new ComplexMap<ConnectionKey, InMemoryTransport>(
|
|
29
|
+
([topic, nodeId, remoteId]) => topic.toHex() + nodeId.toHex() + remoteId.toHex());
|
|
26
30
|
|
|
27
31
|
public readonly closed = new Event<void>();
|
|
28
32
|
public readonly connected = new Event<void>();
|
|
29
|
-
|
|
30
33
|
public readonly errors = new ErrorStream();
|
|
31
34
|
|
|
32
35
|
private readonly _ownKey: ConnectionKey;
|
|
@@ -99,7 +102,6 @@ export class InMemoryTransport implements Transport {
|
|
|
99
102
|
this._incomingDelay.unpipe();
|
|
100
103
|
|
|
101
104
|
this._remoteConnection.closed.emit();
|
|
102
|
-
|
|
103
105
|
this._remoteConnection._remoteConnection = undefined;
|
|
104
106
|
this._remoteConnection = undefined;
|
|
105
107
|
}
|
|
@@ -109,6 +111,7 @@ export class InMemoryTransport implements Transport {
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
// TODO(burdon): Remove.
|
|
112
115
|
export const inMemoryTransportFactory: TransportFactory = opts => new InMemoryTransport(
|
|
113
116
|
opts.ownId,
|
|
114
117
|
opts.remoteId,
|
|
@@ -120,11 +123,11 @@ export const inMemoryTransportFactory: TransportFactory = opts => new InMemoryTr
|
|
|
120
123
|
/**
|
|
121
124
|
* Creates a binary stream that delays data being sent through the stream by the specified amount of time.
|
|
122
125
|
*/
|
|
123
|
-
|
|
126
|
+
const createStreamDelay = (delay: number): NodeJS.ReadWriteStream => {
|
|
124
127
|
return new Transform({
|
|
125
128
|
objectMode: true,
|
|
126
129
|
transform: (chunk, enc, cb) => {
|
|
127
130
|
setTimeout(() => cb(null, chunk), delay);
|
|
128
131
|
}
|
|
129
132
|
});
|
|
130
|
-
}
|
|
133
|
+
};
|
|
@@ -105,7 +105,7 @@ export class WebrtcTransport implements Transport {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
export
|
|
108
|
+
export const createWebRtcTransportFactory = (webrtcConfig?: any): TransportFactory => {
|
|
109
109
|
return opts => new WebrtcTransport(
|
|
110
110
|
opts.initiator,
|
|
111
111
|
opts.stream,
|
|
@@ -116,4 +116,4 @@ export function createWebRtcTransportFactory (webrtcConfig?: any): TransportFact
|
|
|
116
116
|
opts.sendSignal,
|
|
117
117
|
webrtcConfig
|
|
118
118
|
);
|
|
119
|
-
}
|
|
119
|
+
};
|