@dxos/network-manager 0.8.4-main.b97322e → 0.8.4-main.bcb3aa67d6
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-2XXESTV3.mjs → chunk-WMCWASCJ.mjs} +770 -999
- package/dist/lib/browser/chunk-WMCWASCJ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +342 -4
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +78 -49
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/transport/tcp/index.mjs +2 -35
- package/dist/lib/browser/transport/tcp/index.mjs.map +4 -4
- package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs +36 -0
- package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs.map +7 -0
- package/dist/lib/browser/transport/tcp/tcp-transport.mjs +160 -0
- package/dist/lib/browser/transport/tcp/tcp-transport.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-RPB6YS7U.mjs → chunk-AL2EW6AJ.mjs} +770 -999
- package/dist/lib/node-esm/chunk-AL2EW6AJ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +342 -4
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +78 -49
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/transport/tcp/index.mjs +2 -156
- package/dist/lib/node-esm/transport/tcp/index.mjs.map +4 -4
- package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs +36 -0
- package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs.map +7 -0
- package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs +160 -0
- package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs.map +7 -0
- package/dist/types/src/connection-log.d.ts.map +1 -1
- package/dist/types/src/network-manager.d.ts +5 -4
- package/dist/types/src/network-manager.d.ts.map +1 -1
- package/dist/types/src/signal/signal-connection.d.ts +3 -2
- package/dist/types/src/signal/signal-connection.d.ts.map +1 -1
- package/dist/types/src/signal/signal-messenger.d.ts +3 -2
- package/dist/types/src/signal/signal-messenger.d.ts.map +1 -1
- package/dist/types/src/signal/swarm-messenger.d.ts +8 -8
- package/dist/types/src/signal/swarm-messenger.d.ts.map +1 -1
- package/dist/types/src/swarm/connection.d.ts +2 -1
- package/dist/types/src/swarm/connection.d.ts.map +1 -1
- package/dist/types/src/swarm/peer.d.ts +6 -5
- package/dist/types/src/swarm/peer.d.ts.map +1 -1
- package/dist/types/src/swarm/swarm.d.ts +6 -5
- package/dist/types/src/swarm/swarm.d.ts.map +1 -1
- package/dist/types/src/testing/test-builder.d.ts +1 -1
- package/dist/types/src/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-wire-protocol.d.ts +1 -1
- 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/transport/tcp/index.d.ts +1 -1
- package/dist/types/src/transport/tcp/index.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +2 -2
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +1 -1
- package/dist/types/src/wire-protocol.d.ts +5 -5
- package/dist/types/src/wire-protocol.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +37 -33
- package/src/connection-log.ts +1 -1
- package/src/network-manager.ts +20 -16
- package/src/signal/ice.test.ts +1 -1
- package/src/signal/integration.node.test.ts +13 -12
- package/src/signal/signal-connection.ts +3 -2
- package/src/signal/signal-messenger.ts +3 -2
- package/src/signal/swarm-messenger.node.test.ts +26 -25
- package/src/signal/swarm-messenger.ts +66 -56
- package/src/swarm/connection.test.ts +10 -8
- package/src/swarm/connection.ts +15 -13
- package/src/swarm/peer.ts +10 -8
- package/src/swarm/swarm-mapper.ts +1 -1
- package/src/swarm/swarm.test.ts +9 -7
- package/src/swarm/swarm.ts +14 -13
- package/src/testing/test-builder.ts +15 -7
- package/src/testing/test-wire-protocol.ts +2 -2
- package/src/tests/basic-test-suite.ts +3 -2
- package/src/tests/memory-transport.test.ts +4 -2
- package/src/tests/property-test-suite.ts +4 -3
- package/src/tests/tcp-transport.node.test.ts +4 -2
- package/src/tests/webrtc-transport.test.ts +6 -3
- package/src/transport/tcp/index.ts +1 -1
- package/src/transport/tcp/tcp-transport.ts +1 -1
- package/src/transport/webrtc/rtc-peer-connection.ts +5 -4
- package/src/transport/webrtc/rtc-transport-channel.test.ts +3 -1
- package/src/transport/webrtc/rtc-transport-channel.ts +3 -2
- package/src/transport/webrtc/rtc-transport-factory.ts +3 -2
- package/src/transport/webrtc/rtc-transport-proxy.test.ts +7 -4
- package/src/transport/webrtc/rtc-transport-proxy.ts +6 -4
- package/src/transport/webrtc/rtc-transport-service.ts +6 -5
- package/src/transport/webrtc/rtc-transport.test.ts +6 -4
- package/src/wire-protocol.ts +6 -6
- package/dist/lib/browser/chunk-2XXESTV3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RPB6YS7U.mjs.map +0 -7
|
@@ -7,7 +7,7 @@ import { Context } from '@dxos/context';
|
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
|
-
import { type
|
|
10
|
+
import { type Message, type PeerInfo } from '@dxos/messaging';
|
|
11
11
|
import { TimeoutError } from '@dxos/protocols';
|
|
12
12
|
import { schema } from '@dxos/protocols/proto';
|
|
13
13
|
import { type Answer, type SwarmMessage } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
@@ -20,9 +20,9 @@ interface OfferRecord {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export type SwarmMessengerOptions = {
|
|
23
|
-
sendMessage: (params: Message) => Promise<void>;
|
|
24
|
-
onOffer: (message: OfferMessage) => Promise<Answer>;
|
|
25
|
-
onSignal: (message: SignalMessage) => Promise<void>;
|
|
23
|
+
sendMessage: (ctx: Context, params: Message) => Promise<void>;
|
|
24
|
+
onOffer: (ctx: Context, message: OfferMessage) => Promise<Answer>;
|
|
25
|
+
onSignal: (ctx: Context, message: SignalMessage) => Promise<void>;
|
|
26
26
|
topic: PublicKey;
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -32,11 +32,9 @@ const SwarmMessage = schema.getCodecForType('dxos.mesh.swarm.SwarmMessage');
|
|
|
32
32
|
* Adds offer/answer and signal interfaces.
|
|
33
33
|
*/
|
|
34
34
|
export class SwarmMessenger implements SignalMessenger {
|
|
35
|
-
private readonly
|
|
36
|
-
|
|
37
|
-
private readonly
|
|
38
|
-
private readonly _onSignal: (message: SignalMessage) => Promise<void>;
|
|
39
|
-
private readonly _onOffer: (message: OfferMessage) => Promise<Answer>;
|
|
35
|
+
private readonly _sendMessage: SwarmMessengerOptions['sendMessage'];
|
|
36
|
+
private readonly _onSignal: SwarmMessengerOptions['onSignal'];
|
|
37
|
+
private readonly _onOffer: SwarmMessengerOptions['onOffer'];
|
|
40
38
|
private readonly _topic: PublicKey;
|
|
41
39
|
|
|
42
40
|
private readonly _offerRecords: ComplexMap<PublicKey, OfferRecord> = new ComplexMap((key) => key.toHex());
|
|
@@ -48,15 +46,18 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
48
46
|
this._topic = topic;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
async receiveMessage(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
async receiveMessage(
|
|
50
|
+
ctx: Context,
|
|
51
|
+
{
|
|
52
|
+
author,
|
|
53
|
+
recipient,
|
|
54
|
+
payload,
|
|
55
|
+
}: {
|
|
56
|
+
author: PeerInfo;
|
|
57
|
+
recipient: PeerInfo;
|
|
58
|
+
payload: Any;
|
|
59
|
+
},
|
|
60
|
+
): Promise<void> {
|
|
60
61
|
if (payload.type_url !== 'dxos.mesh.swarm.SwarmMessage') {
|
|
61
62
|
// Ignore not swarm messages.
|
|
62
63
|
return;
|
|
@@ -71,35 +72,35 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
71
72
|
log('received', { from: author, to: recipient, msg: message });
|
|
72
73
|
|
|
73
74
|
if (message.data?.offer) {
|
|
74
|
-
await this._handleOffer({ author, recipient, message });
|
|
75
|
+
await this._handleOffer(ctx, { author, recipient, message });
|
|
75
76
|
} else if (message.data?.answer) {
|
|
76
77
|
await this._resolveAnswers(message);
|
|
77
78
|
} else if (message.data?.signal) {
|
|
78
|
-
await this._handleSignal({ author, recipient, message });
|
|
79
|
+
await this._handleSignal(ctx, { author, recipient, message });
|
|
79
80
|
} else if (message.data?.signalBatch) {
|
|
80
|
-
await this._handleSignal({ author, recipient, message });
|
|
81
|
+
await this._handleSignal(ctx, { author, recipient, message });
|
|
81
82
|
} else {
|
|
82
83
|
log.warn('unknown message', { message });
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
async signal(message: SignalMessage): Promise<void> {
|
|
87
|
+
async signal(ctx: Context, message: SignalMessage): Promise<void> {
|
|
87
88
|
invariant(message.data?.signal || message.data?.signalBatch, 'Invalid message');
|
|
88
|
-
await this._sendReliableMessage({
|
|
89
|
+
await this._sendReliableMessage(ctx, {
|
|
89
90
|
author: message.author,
|
|
90
91
|
recipient: message.recipient,
|
|
91
92
|
message,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
async offer(message: OfferMessage): Promise<Answer> {
|
|
96
|
+
async offer(ctx: Context, message: OfferMessage): Promise<Answer> {
|
|
96
97
|
const networkMessage: SwarmMessage = {
|
|
97
98
|
...message,
|
|
98
99
|
messageId: PublicKey.random(),
|
|
99
100
|
};
|
|
100
101
|
return new Promise<Answer>((resolve, reject) => {
|
|
101
102
|
this._offerRecords.set(networkMessage.messageId!, { resolve });
|
|
102
|
-
this._sendReliableMessage({
|
|
103
|
+
this._sendReliableMessage(ctx, {
|
|
103
104
|
author: message.author,
|
|
104
105
|
recipient: message.recipient,
|
|
105
106
|
message: networkMessage,
|
|
@@ -107,15 +108,18 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
107
108
|
});
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
private async _sendReliableMessage(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
private async _sendReliableMessage(
|
|
112
|
+
ctx: Context,
|
|
113
|
+
{
|
|
114
|
+
author,
|
|
115
|
+
recipient,
|
|
116
|
+
message,
|
|
117
|
+
}: {
|
|
118
|
+
author: PeerInfo;
|
|
119
|
+
recipient: PeerInfo;
|
|
120
|
+
message: MakeOptional<SwarmMessage, 'messageId'>;
|
|
121
|
+
},
|
|
122
|
+
): Promise<void> {
|
|
119
123
|
const networkMessage: SwarmMessage = {
|
|
120
124
|
...message,
|
|
121
125
|
// Setting unique message_id if it not specified yet.
|
|
@@ -123,7 +127,7 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
123
127
|
};
|
|
124
128
|
|
|
125
129
|
log('sending', { from: author, to: recipient, msg: networkMessage });
|
|
126
|
-
await this._sendMessage({
|
|
130
|
+
await this._sendMessage(ctx, {
|
|
127
131
|
author,
|
|
128
132
|
recipient,
|
|
129
133
|
payload: {
|
|
@@ -144,15 +148,18 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
|
|
147
|
-
private async _handleOffer(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
private async _handleOffer(
|
|
152
|
+
ctx: Context,
|
|
153
|
+
{
|
|
154
|
+
author,
|
|
155
|
+
recipient,
|
|
156
|
+
message,
|
|
157
|
+
}: {
|
|
158
|
+
author: PeerInfo;
|
|
159
|
+
recipient: PeerInfo;
|
|
160
|
+
message: SwarmMessage;
|
|
161
|
+
},
|
|
162
|
+
): Promise<void> {
|
|
156
163
|
invariant(message.data.offer, 'No offer');
|
|
157
164
|
const offerMessage: OfferMessage = {
|
|
158
165
|
author,
|
|
@@ -160,10 +167,10 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
160
167
|
...message,
|
|
161
168
|
data: { offer: message.data.offer },
|
|
162
169
|
};
|
|
163
|
-
const answer = await this._onOffer(offerMessage);
|
|
170
|
+
const answer = await this._onOffer(ctx, offerMessage);
|
|
164
171
|
answer.offerMessageId = message.messageId;
|
|
165
172
|
try {
|
|
166
|
-
await this._sendReliableMessage({
|
|
173
|
+
await this._sendReliableMessage(ctx, {
|
|
167
174
|
author: recipient,
|
|
168
175
|
recipient: author,
|
|
169
176
|
message: {
|
|
@@ -181,15 +188,18 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
181
188
|
}
|
|
182
189
|
}
|
|
183
190
|
|
|
184
|
-
private async _handleSignal(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
private async _handleSignal(
|
|
192
|
+
ctx: Context,
|
|
193
|
+
{
|
|
194
|
+
author,
|
|
195
|
+
recipient,
|
|
196
|
+
message,
|
|
197
|
+
}: {
|
|
198
|
+
author: PeerInfo;
|
|
199
|
+
recipient: PeerInfo;
|
|
200
|
+
message: SwarmMessage;
|
|
201
|
+
},
|
|
202
|
+
): Promise<void> {
|
|
193
203
|
invariant(message.messageId);
|
|
194
204
|
invariant(message.data.signal || message.data.signalBatch, 'Invalid message');
|
|
195
205
|
const signalMessage: SignalMessage = {
|
|
@@ -202,6 +212,6 @@ export class SwarmMessenger implements SignalMessenger {
|
|
|
202
212
|
},
|
|
203
213
|
};
|
|
204
214
|
|
|
205
|
-
await this._onSignal(signalMessage);
|
|
215
|
+
await this._onSignal(ctx, signalMessage);
|
|
206
216
|
}
|
|
207
217
|
}
|
|
@@ -7,12 +7,14 @@ import { describe, test } from 'vitest';
|
|
|
7
7
|
import { sleep } from '@dxos/async';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
9
|
|
|
10
|
-
import { Connection } from './connection';
|
|
11
10
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
12
11
|
import { createRtcTransportFactory } from '../transport';
|
|
13
12
|
import { chooseInitiatorPeer } from '../transport/webrtc/utils';
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
import { Connection } from './connection';
|
|
15
|
+
|
|
16
|
+
// Segfault in node-datachannel.
|
|
17
|
+
describe.skip('Connection', () => {
|
|
16
18
|
test('responder opens after initiator', async () => {
|
|
17
19
|
const { initiator, responder } = createPeerKeys();
|
|
18
20
|
await connectionTest({
|
|
@@ -42,9 +44,9 @@ describe('Connection', () => {
|
|
|
42
44
|
sessionId,
|
|
43
45
|
true,
|
|
44
46
|
{
|
|
45
|
-
offer: async (
|
|
46
|
-
signal: async (msg) => {
|
|
47
|
-
await fastConnection.signal(msg);
|
|
47
|
+
offer: async (_ctx, _msg) => ({ accept: true }),
|
|
48
|
+
signal: async (ctx, msg) => {
|
|
49
|
+
await fastConnection.signal(ctx, msg);
|
|
48
50
|
},
|
|
49
51
|
},
|
|
50
52
|
slowPeerProtocol.factory({
|
|
@@ -64,9 +66,9 @@ describe('Connection', () => {
|
|
|
64
66
|
sessionId,
|
|
65
67
|
false,
|
|
66
68
|
{
|
|
67
|
-
offer: async (
|
|
68
|
-
signal: async (msg) => {
|
|
69
|
-
await slowConnection.signal(msg);
|
|
69
|
+
offer: async (_ctx, _msg) => ({ accept: true }),
|
|
70
|
+
signal: async (ctx, msg) => {
|
|
71
|
+
await slowConnection.signal(ctx, msg);
|
|
70
72
|
},
|
|
71
73
|
},
|
|
72
74
|
fastPeerProtocol.factory({
|
package/src/swarm/connection.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { DeferredTask, Event,
|
|
6
|
-
import { Context,
|
|
5
|
+
import { DeferredTask, Event, Trigger, scheduleTask, scheduleTaskInterval, sleep, synchronized } from '@dxos/async';
|
|
6
|
+
import { Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
|
|
7
7
|
import { ErrorStream } from '@dxos/debug';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -11,9 +11,9 @@ import { log, logInfo } from '@dxos/log';
|
|
|
11
11
|
import { type PeerInfo } from '@dxos/messaging';
|
|
12
12
|
import {
|
|
13
13
|
CancelledError,
|
|
14
|
-
ProtocolError,
|
|
15
14
|
ConnectionResetError,
|
|
16
15
|
ConnectivityError,
|
|
16
|
+
ProtocolError,
|
|
17
17
|
TimeoutError,
|
|
18
18
|
trace,
|
|
19
19
|
} from '@dxos/protocols';
|
|
@@ -118,7 +118,7 @@ export class Connection {
|
|
|
118
118
|
public readonly transportStats = new Event<TransportStats>();
|
|
119
119
|
|
|
120
120
|
private readonly _signalSendTask = new DeferredTask(this._ctx, async () => {
|
|
121
|
-
await this._flushSignalBuffer();
|
|
121
|
+
await this._flushSignalBuffer(this._ctx);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
private _signallingDelay = STARTING_SIGNALLING_DELAY;
|
|
@@ -185,16 +185,18 @@ export class Connection {
|
|
|
185
185
|
this._protocol.stream.on('close', () => {
|
|
186
186
|
log('protocol stream closed');
|
|
187
187
|
this._protocolClosed.wake();
|
|
188
|
-
this.close({ error: new ProtocolError('protocol stream closed') }).catch((err) =>
|
|
188
|
+
this.close({ error: new ProtocolError({ message: 'protocol stream closed' }) }).catch((err) =>
|
|
189
|
+
this.errors.raise(err),
|
|
190
|
+
);
|
|
189
191
|
});
|
|
190
192
|
|
|
191
193
|
scheduleTask(
|
|
192
194
|
this.connectedTimeoutContext,
|
|
193
195
|
async () => {
|
|
194
196
|
log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect, aborting`);
|
|
195
|
-
await this.abort(
|
|
196
|
-
(
|
|
197
|
-
);
|
|
197
|
+
await this.abort(
|
|
198
|
+
new TimeoutError({ message: `${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect` }),
|
|
199
|
+
).catch((err) => this.errors.raise(err));
|
|
198
200
|
},
|
|
199
201
|
TRANSPORT_CONNECTION_TIMEOUT,
|
|
200
202
|
);
|
|
@@ -364,21 +366,21 @@ export class Connection {
|
|
|
364
366
|
this._signalSendTask.schedule();
|
|
365
367
|
}
|
|
366
368
|
|
|
367
|
-
private async _flushSignalBuffer(): Promise<void> {
|
|
369
|
+
private async _flushSignalBuffer(ctx: Context): Promise<void> {
|
|
368
370
|
if (this._outgoingSignalBuffer.length === 0) {
|
|
369
371
|
return;
|
|
370
372
|
}
|
|
371
373
|
|
|
372
374
|
try {
|
|
373
375
|
if (process.env.NODE_ENV !== 'test') {
|
|
374
|
-
await cancelWithContext(
|
|
376
|
+
await cancelWithContext(ctx, sleep(this._signallingDelay));
|
|
375
377
|
this._signallingDelay = Math.min(this._signallingDelay * 2, MAX_SIGNALLING_DELAY);
|
|
376
378
|
}
|
|
377
379
|
|
|
378
380
|
const signals = [...this._outgoingSignalBuffer];
|
|
379
381
|
this._outgoingSignalBuffer.length = 0;
|
|
380
382
|
|
|
381
|
-
await this._signalMessaging.signal({
|
|
383
|
+
await this._signalMessaging.signal(ctx, {
|
|
382
384
|
author: this.localInfo,
|
|
383
385
|
recipient: this.remoteInfo,
|
|
384
386
|
sessionId: this.sessionId,
|
|
@@ -397,14 +399,14 @@ export class Connection {
|
|
|
397
399
|
|
|
398
400
|
// If signal fails treat connection as failed
|
|
399
401
|
log.info('signal message failed to deliver', { err });
|
|
400
|
-
await this.close({ error: new ConnectivityError('signal message failed to deliver', err) });
|
|
402
|
+
await this.close({ error: new ConnectivityError({ message: 'signal message failed to deliver', cause: err }) });
|
|
401
403
|
}
|
|
402
404
|
}
|
|
403
405
|
|
|
404
406
|
/**
|
|
405
407
|
* Receive a signal from the remote peer.
|
|
406
408
|
*/
|
|
407
|
-
async signal(msg: SignalMessage): Promise<void> {
|
|
409
|
+
async signal(_ctx: Context, msg: SignalMessage): Promise<void> {
|
|
408
410
|
invariant(msg.sessionId);
|
|
409
411
|
if (!msg.sessionId.equals(this.sessionId)) {
|
|
410
412
|
log('dropping signal for incorrect session id');
|
package/src/swarm/peer.ts
CHANGED
|
@@ -11,15 +11,16 @@ import { type PeerInfo } from '@dxos/messaging';
|
|
|
11
11
|
import { CancelledError, SystemError } from '@dxos/protocols';
|
|
12
12
|
import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
13
13
|
|
|
14
|
-
import { Connection, ConnectionState } from './connection';
|
|
15
|
-
import { type ConnectionLimiter } from './connection-limiter';
|
|
16
14
|
import { type OfferMessage, type SignalMessage, type SignalMessenger } from '../signal';
|
|
17
15
|
import { type TransportFactory } from '../transport';
|
|
18
16
|
import { type WireProtocolProvider } from '../wire-protocol';
|
|
19
17
|
|
|
18
|
+
import { Connection, ConnectionState } from './connection';
|
|
19
|
+
import { type ConnectionLimiter } from './connection-limiter';
|
|
20
|
+
|
|
20
21
|
export class ConnectionDisplacedError extends SystemError {
|
|
21
22
|
constructor() {
|
|
22
|
-
super('Connection displaced by remote initiator.');
|
|
23
|
+
super({ message: 'Connection displaced by remote initiator.' });
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -105,7 +106,7 @@ export class Peer {
|
|
|
105
106
|
/**
|
|
106
107
|
* Respond to remote offer.
|
|
107
108
|
*/
|
|
108
|
-
async onOffer(message: OfferMessage): Promise<Answer> {
|
|
109
|
+
async onOffer(_ctx: Context, message: OfferMessage): Promise<Answer> {
|
|
109
110
|
const remote = message.author;
|
|
110
111
|
|
|
111
112
|
if (
|
|
@@ -161,13 +162,14 @@ export class Peer {
|
|
|
161
162
|
return { accept: true };
|
|
162
163
|
}
|
|
163
164
|
}
|
|
165
|
+
|
|
164
166
|
return { accept: false };
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
/**
|
|
168
170
|
* Initiate a connection to the remote peer.
|
|
169
171
|
*/
|
|
170
|
-
async initiateConnection(): Promise<void> {
|
|
172
|
+
async initiateConnection(ctx: Context): Promise<void> {
|
|
171
173
|
invariant(!this.initiating, 'Initiation in progress.');
|
|
172
174
|
invariant(!this.connection, 'Already connected.');
|
|
173
175
|
const sessionId = PublicKey.random();
|
|
@@ -181,7 +183,7 @@ export class Peer {
|
|
|
181
183
|
await this._connectionLimiter.connecting(sessionId);
|
|
182
184
|
connection.initiate();
|
|
183
185
|
|
|
184
|
-
answer = await this._signalMessaging.offer({
|
|
186
|
+
answer = await this._signalMessaging.offer(ctx, {
|
|
185
187
|
author: this.localInfo,
|
|
186
188
|
recipient: this.remoteInfo,
|
|
187
189
|
sessionId,
|
|
@@ -376,13 +378,13 @@ export class Peer {
|
|
|
376
378
|
log('closed', { peerId: this.remoteInfo, sessionId: connection.sessionId });
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
async onSignal(message: SignalMessage): Promise<void> {
|
|
381
|
+
async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
|
|
380
382
|
if (!this.connection) {
|
|
381
383
|
log('dropping signal message for non-existent connection', { message });
|
|
382
384
|
return;
|
|
383
385
|
}
|
|
384
386
|
|
|
385
|
-
await this.connection.signal(message);
|
|
387
|
+
await this.connection.signal(ctx, message);
|
|
386
388
|
}
|
|
387
389
|
|
|
388
390
|
@synchronized
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type CleanupFn, Event, SubscriptionList } from '@dxos/async';
|
|
6
6
|
import { PublicKey } from '@dxos/keys';
|
|
7
7
|
import { log } from '@dxos/log';
|
|
8
|
-
import {
|
|
8
|
+
import { type PeerInfo as MessagingPeer, PeerInfoHash } from '@dxos/messaging';
|
|
9
9
|
import { ComplexMap } from '@dxos/util';
|
|
10
10
|
|
|
11
11
|
import { type ConnectionState } from './connection';
|
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, sleep } from '@dxos/async';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -15,13 +15,14 @@ import {
|
|
|
15
15
|
} from '@dxos/messaging';
|
|
16
16
|
import { ComplexSet } from '@dxos/util';
|
|
17
17
|
|
|
18
|
-
import { ConnectionState } from './connection';
|
|
19
|
-
import { ConnectionLimiter } from './connection-limiter';
|
|
20
|
-
import { Swarm } from './swarm';
|
|
21
18
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
22
19
|
import { FullyConnectedTopology } from '../topology';
|
|
23
20
|
import { createRtcTransportFactory } from '../transport';
|
|
24
21
|
|
|
22
|
+
import { ConnectionState } from './connection';
|
|
23
|
+
import { ConnectionLimiter } from './connection-limiter';
|
|
24
|
+
import { Swarm } from './swarm';
|
|
25
|
+
|
|
25
26
|
type TestPeer = {
|
|
26
27
|
swarm: Swarm;
|
|
27
28
|
peer: PeerInfo;
|
|
@@ -30,7 +31,8 @@ type TestPeer = {
|
|
|
30
31
|
signalManager: SignalManager;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
// Segfault in node-datachannel.
|
|
35
|
+
describe.skip('Swarm', () => {
|
|
34
36
|
const context = new MemorySignalManagerContext();
|
|
35
37
|
|
|
36
38
|
const setupSwarm = async ({
|
|
@@ -157,9 +159,9 @@ describe('Swarm', () => {
|
|
|
157
159
|
const messages = new ComplexSet<{ author: PeerInfo; recipient: PeerInfo }>(
|
|
158
160
|
({ author, recipient }) => author.peerKey + recipient.peerKey,
|
|
159
161
|
);
|
|
160
|
-
signalManager.sendMessage = async (message) => {
|
|
162
|
+
signalManager.sendMessage = async (ctx, message) => {
|
|
161
163
|
messages.add({ author: message.author, recipient: message.recipient });
|
|
162
|
-
return sendOriginal(message);
|
|
164
|
+
return sendOriginal(ctx, message);
|
|
163
165
|
};
|
|
164
166
|
// Stop signaling to stop connection in initiation state.
|
|
165
167
|
signalManager.freeze();
|
package/src/swarm/swarm.ts
CHANGED
|
@@ -8,20 +8,21 @@ import { ErrorStream } from '@dxos/debug';
|
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { log, logInfo } from '@dxos/log';
|
|
11
|
-
import { type
|
|
11
|
+
import { type ListeningHandle, type Messenger, type PeerInfo, PeerInfoHash, type SwarmEvent } from '@dxos/messaging';
|
|
12
12
|
import { trace } from '@dxos/protocols';
|
|
13
13
|
import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
14
14
|
import { ComplexMap, isNonNullable } from '@dxos/util';
|
|
15
15
|
|
|
16
|
-
import { type Connection, ConnectionState } from './connection';
|
|
17
|
-
import { type ConnectionLimiter } from './connection-limiter';
|
|
18
|
-
import { Peer } from './peer';
|
|
19
16
|
import { type OfferMessage, type SignalMessage, SwarmMessenger } from '../signal';
|
|
20
17
|
import { type SwarmController, type Topology } from '../topology';
|
|
21
18
|
import { type TransportFactory } from '../transport';
|
|
22
19
|
import { type Topic } from '../types';
|
|
23
20
|
import { type WireProtocolProvider } from '../wire-protocol';
|
|
24
21
|
|
|
22
|
+
import { type Connection, ConnectionState } from './connection';
|
|
23
|
+
import { type ConnectionLimiter } from './connection-limiter';
|
|
24
|
+
import { Peer } from './peer';
|
|
25
|
+
|
|
25
26
|
const INITIATION_DELAY = 100;
|
|
26
27
|
|
|
27
28
|
// TODO(burdon): Factor out.
|
|
@@ -93,9 +94,9 @@ export class Swarm {
|
|
|
93
94
|
_topology.init(this._getSwarmController());
|
|
94
95
|
|
|
95
96
|
this._swarmMessenger = new SwarmMessenger({
|
|
96
|
-
sendMessage: async (msg) => await this._messenger.sendMessage(msg),
|
|
97
|
-
onSignal: async (msg) => await this.onSignal(msg),
|
|
98
|
-
onOffer: async (msg) => await this.onOffer(msg),
|
|
97
|
+
sendMessage: async (ctx, msg) => await this._messenger.sendMessage(ctx, msg),
|
|
98
|
+
onSignal: async (ctx, msg) => await this.onSignal(ctx, msg),
|
|
99
|
+
onOffer: async (ctx, msg) => await this.onOffer(ctx, msg),
|
|
99
100
|
topic: this._topic,
|
|
100
101
|
});
|
|
101
102
|
log.trace('dxos.mesh.swarm.constructor', trace.end({ id: this._instanceId }));
|
|
@@ -135,7 +136,7 @@ export class Swarm {
|
|
|
135
136
|
payloadType: 'dxos.mesh.swarm.SwarmMessage',
|
|
136
137
|
onMessage: async (message) => {
|
|
137
138
|
await this._swarmMessenger
|
|
138
|
-
.receiveMessage(message)
|
|
139
|
+
.receiveMessage(this._ctx, message)
|
|
139
140
|
// TODO(nf): discriminate between errors
|
|
140
141
|
.catch((err) => log.info('Error while receiving message', { err }));
|
|
141
142
|
},
|
|
@@ -204,7 +205,7 @@ export class Swarm {
|
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
@synchronized
|
|
207
|
-
async onOffer(message: OfferMessage): Promise<Answer> {
|
|
208
|
+
async onOffer(ctx: Context, message: OfferMessage): Promise<Answer> {
|
|
208
209
|
log('offer', { message });
|
|
209
210
|
if (this._ctx.disposed) {
|
|
210
211
|
log('ignored for disposed swarm');
|
|
@@ -223,7 +224,7 @@ export class Swarm {
|
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
const peer = this._getOfferSenderPeer(message.author);
|
|
226
|
-
const answer = await peer.onOffer(message);
|
|
227
|
+
const answer = await peer.onOffer(ctx, message);
|
|
227
228
|
this._topology.update();
|
|
228
229
|
return answer;
|
|
229
230
|
}
|
|
@@ -242,7 +243,7 @@ export class Swarm {
|
|
|
242
243
|
return peer;
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
async onSignal(message: SignalMessage): Promise<void> {
|
|
246
|
+
async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
|
|
246
247
|
log('signal', { message });
|
|
247
248
|
if (this._ctx.disposed) {
|
|
248
249
|
log.info('ignored for offline swarm');
|
|
@@ -256,7 +257,7 @@ export class Swarm {
|
|
|
256
257
|
invariant(message.author);
|
|
257
258
|
|
|
258
259
|
const peer = this._getOrCreatePeer(message.author);
|
|
259
|
-
await peer.onSignal(message);
|
|
260
|
+
await peer.onSignal(ctx, message);
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
// For debug purposes
|
|
@@ -403,7 +404,7 @@ export class Swarm {
|
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
log('initiating connection...', { remotePeer });
|
|
406
|
-
await peer.initiateConnection();
|
|
407
|
+
await peer.initiateConnection(ctx);
|
|
407
408
|
this._topology.update();
|
|
408
409
|
log('initiated', { remotePeer });
|
|
409
410
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { PublicKey } from '@dxos/keys';
|
|
6
6
|
import { log } from '@dxos/log';
|
|
7
|
+
import { Context } from '@dxos/context';
|
|
7
8
|
import {
|
|
8
9
|
MemorySignalManager,
|
|
9
10
|
MemorySignalManagerContext,
|
|
@@ -13,16 +14,23 @@ import {
|
|
|
13
14
|
import { schema } from '@dxos/protocols/proto';
|
|
14
15
|
import { ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
|
|
15
16
|
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
16
|
-
import { createLinkedPorts, createProtoRpcPeer
|
|
17
|
+
import { type ProtoRpcPeer, createLinkedPorts, createProtoRpcPeer } from '@dxos/rpc';
|
|
17
18
|
import { ComplexMap } from '@dxos/util';
|
|
18
19
|
|
|
19
20
|
import { TcpTransportFactory } from '#tcp-transport';
|
|
20
21
|
|
|
21
|
-
import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
|
|
22
22
|
import { SwarmNetworkManager } from '../network-manager';
|
|
23
23
|
import { FullyConnectedTopology } from '../topology';
|
|
24
|
-
import {
|
|
25
|
-
|
|
24
|
+
import {
|
|
25
|
+
MemoryTransportFactory,
|
|
26
|
+
RtcTransportProxyFactory,
|
|
27
|
+
RtcTransportService,
|
|
28
|
+
type TransportFactory,
|
|
29
|
+
TransportKind,
|
|
30
|
+
createRtcTransportFactory,
|
|
31
|
+
} from '../transport';
|
|
32
|
+
|
|
33
|
+
import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
|
|
26
34
|
|
|
27
35
|
// Signal server will be started by the setup script.
|
|
28
36
|
const port = process.env.SIGNAL_PORT ?? 4000;
|
|
@@ -162,7 +170,7 @@ export class TestPeer {
|
|
|
162
170
|
|
|
163
171
|
await this._proxy?.close();
|
|
164
172
|
await this._service?.close();
|
|
165
|
-
await this._networkManager.close();
|
|
173
|
+
await this._networkManager.close(Context.default());
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
getSwarm(topic: PublicKey): TestSwarmConnection {
|
|
@@ -211,7 +219,7 @@ export class TestSwarmConnection {
|
|
|
211
219
|
// TODO(burdon): Need to create new plugin instance per swarm?
|
|
212
220
|
// If so, then perhaps joinSwarm should return swarm object with access to plugins.
|
|
213
221
|
async join(topology = new FullyConnectedTopology()): Promise<this> {
|
|
214
|
-
await this.peer._networkManager.joinSwarm({
|
|
222
|
+
await this.peer._networkManager.joinSwarm(Context.default(), {
|
|
215
223
|
topic: this.topic,
|
|
216
224
|
peerInfo: { peerKey: this.peer.peerId.toHex(), identityKey: this.peer.peerId.toHex() },
|
|
217
225
|
protocolProvider: this.protocol.factory,
|
|
@@ -222,7 +230,7 @@ export class TestSwarmConnection {
|
|
|
222
230
|
}
|
|
223
231
|
|
|
224
232
|
async leave(): Promise<this> {
|
|
225
|
-
await this.peer._networkManager.leaveSwarm(this.topic);
|
|
233
|
+
await this.peer._networkManager.leaveSwarm(Context.default(), this.topic);
|
|
226
234
|
return this;
|
|
227
235
|
}
|
|
228
236
|
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Event, asyncTimeout } from '@dxos/async';
|
|
6
6
|
import { PublicKey } from '@dxos/keys';
|
|
7
7
|
import { log } from '@dxos/log';
|
|
8
8
|
import { TestExtension, TestExtensionWithStreams } from '@dxos/teleport';
|
|
9
|
-
import type {
|
|
9
|
+
import type { TeleportExtension, TestStreamStats } from '@dxos/teleport';
|
|
10
10
|
import { ComplexMap } from '@dxos/util';
|
|
11
11
|
|
|
12
12
|
import { createTeleportProtocolFactory } from '../wire-protocol';
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout } from '@dxos/async';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { range } from '@dxos/util';
|
|
11
11
|
|
|
12
|
-
import { exchangeMessages, joinSwarm, leaveSwarm, openAndCloseAfterTest } from './utils';
|
|
13
12
|
import { type TestBuilder } from '../testing';
|
|
14
13
|
import { FullyConnectedTopology, StarTopology } from '../topology';
|
|
15
14
|
|
|
15
|
+
import { exchangeMessages, joinSwarm, leaveSwarm, openAndCloseAfterTest } from './utils';
|
|
16
|
+
|
|
16
17
|
// TODO(burdon): Use PublicKey throughout (remove conversion to strings, from buffers, etc.)
|
|
17
18
|
|
|
18
19
|
/**
|