@dxos/network-manager 0.8.4-main.fffef41 → 0.8.4-staging.60fe92afc8
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/{chunk-E3P563GT.mjs → chunk-ERB3AQAF.mjs} +424 -1897
- package/dist/lib/browser/chunk-ERB3AQAF.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +198 -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 +10 -34
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/transport/tcp/index.mjs +2 -33
- 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 +125 -0
- package/dist/lib/browser/transport/tcp/tcp-transport.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-PKBROUZV.mjs → chunk-KYLPLEZQ.mjs} +424 -1897
- package/dist/lib/node-esm/chunk-KYLPLEZQ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +198 -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 +10 -34
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/transport/tcp/index.mjs +2 -157
- 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 +125 -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 +6 -6
- 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/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 +7 -7
- package/dist/types/src/signal/swarm-messenger.d.ts.map +1 -1
- package/dist/types/src/swarm/connection-limiter.d.ts.map +1 -1
- package/dist/types/src/swarm/connection.d.ts +2 -2
- package/dist/types/src/swarm/connection.d.ts.map +1 -1
- package/dist/types/src/swarm/peer.d.ts +4 -3
- package/dist/types/src/swarm/peer.d.ts.map +1 -1
- package/dist/types/src/swarm/swarm-mapper.d.ts.map +1 -1
- package/dist/types/src/swarm/swarm.d.ts +3 -5
- package/dist/types/src/swarm/swarm.d.ts.map +1 -1
- package/dist/types/src/testing/test-builder.d.ts.map +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/tests/utils.d.ts.map +1 -1
- package/dist/types/src/topology/fully-connected-topology.d.ts.map +1 -1
- package/dist/types/src/topology/mmst-topology.d.ts.map +1 -1
- package/dist/types/src/topology/star-topology.d.ts.map +1 -1
- package/dist/types/src/transport/memory-transport.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/tcp/tcp-transport.browser.d.ts.map +1 -1
- package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +4 -4
- 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.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.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/test-utils.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/utils.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 +33 -33
- package/src/network-manager.ts +24 -22
- package/src/signal/integration.node.test.ts +11 -10
- package/src/signal/signal-connection.ts +3 -2
- package/src/signal/signal-messenger.ts +3 -2
- package/src/signal/swarm-messenger.node.test.ts +25 -24
- package/src/signal/swarm-messenger.ts +65 -55
- package/src/swarm/connection.test.ts +6 -7
- package/src/swarm/connection.ts +15 -22
- package/src/swarm/peer.ts +7 -7
- package/src/swarm/swarm.test.ts +2 -3
- package/src/swarm/swarm.ts +10 -17
- package/src/testing/test-builder.ts +4 -4
- package/src/tests/basic-test-suite.ts +0 -1
- package/src/tests/memory-transport.test.ts +0 -2
- package/src/tests/property-test-suite.ts +4 -3
- package/src/tests/tcp-transport.node.test.ts +0 -2
- package/src/tests/webrtc-transport.test.ts +0 -1
- package/src/transport/tcp/index.ts +1 -1
- package/src/transport/webrtc/rtc-peer-connection.ts +1 -2
- package/src/transport/webrtc/rtc-transport-channel.test.ts +0 -2
- package/src/transport/webrtc/rtc-transport-channel.ts +1 -2
- package/src/transport/webrtc/rtc-transport-factory.ts +0 -1
- package/src/transport/webrtc/rtc-transport-proxy.test.ts +0 -2
- package/src/transport/webrtc/rtc-transport-proxy.ts +6 -4
- package/src/transport/webrtc/rtc-transport-service.ts +0 -1
- package/src/transport/webrtc/rtc-transport.test.ts +0 -1
- package/src/wire-protocol.ts +6 -6
- package/dist/lib/browser/chunk-E3P563GT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-PKBROUZV.mjs.map +0 -7
|
@@ -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
|
}
|
|
@@ -10,7 +10,6 @@ import { PublicKey } from '@dxos/keys';
|
|
|
10
10
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
11
11
|
import { createRtcTransportFactory } from '../transport';
|
|
12
12
|
import { chooseInitiatorPeer } from '../transport/webrtc/utils';
|
|
13
|
-
|
|
14
13
|
import { Connection } from './connection';
|
|
15
14
|
|
|
16
15
|
// Segfault in node-datachannel.
|
|
@@ -44,9 +43,9 @@ describe.skip('Connection', () => {
|
|
|
44
43
|
sessionId,
|
|
45
44
|
true,
|
|
46
45
|
{
|
|
47
|
-
offer: async (
|
|
48
|
-
signal: async (msg) => {
|
|
49
|
-
await fastConnection.signal(msg);
|
|
46
|
+
offer: async (_ctx, _msg) => ({ accept: true }),
|
|
47
|
+
signal: async (ctx, msg) => {
|
|
48
|
+
await fastConnection.signal(ctx, msg);
|
|
50
49
|
},
|
|
51
50
|
},
|
|
52
51
|
slowPeerProtocol.factory({
|
|
@@ -66,9 +65,9 @@ describe.skip('Connection', () => {
|
|
|
66
65
|
sessionId,
|
|
67
66
|
false,
|
|
68
67
|
{
|
|
69
|
-
offer: async (
|
|
70
|
-
signal: async (msg) => {
|
|
71
|
-
await slowConnection.signal(msg);
|
|
68
|
+
offer: async (_ctx, _msg) => ({ accept: true }),
|
|
69
|
+
signal: async (ctx, msg) => {
|
|
70
|
+
await slowConnection.signal(ctx, msg);
|
|
72
71
|
},
|
|
73
72
|
},
|
|
74
73
|
fastPeerProtocol.factory({
|
package/src/swarm/connection.ts
CHANGED
|
@@ -9,14 +9,7 @@ import { invariant } from '@dxos/invariant';
|
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { log, logInfo } from '@dxos/log';
|
|
11
11
|
import { type PeerInfo } from '@dxos/messaging';
|
|
12
|
-
import {
|
|
13
|
-
CancelledError,
|
|
14
|
-
ConnectionResetError,
|
|
15
|
-
ConnectivityError,
|
|
16
|
-
ProtocolError,
|
|
17
|
-
TimeoutError,
|
|
18
|
-
trace,
|
|
19
|
-
} from '@dxos/protocols';
|
|
12
|
+
import { CancelledError, ConnectionResetError, ConnectivityError, ProtocolError, TimeoutError } from '@dxos/protocols';
|
|
20
13
|
import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
21
14
|
|
|
22
15
|
import { type SignalMessage, type SignalMessenger } from '../signal';
|
|
@@ -113,12 +106,10 @@ export class Connection {
|
|
|
113
106
|
readonly stateChanged = new Event<ConnectionState>();
|
|
114
107
|
readonly errors = new ErrorStream();
|
|
115
108
|
|
|
116
|
-
public _instanceId = PublicKey.random().toHex();
|
|
117
|
-
|
|
118
109
|
public readonly transportStats = new Event<TransportStats>();
|
|
119
110
|
|
|
120
111
|
private readonly _signalSendTask = new DeferredTask(this._ctx, async () => {
|
|
121
|
-
await this._flushSignalBuffer();
|
|
112
|
+
await this._flushSignalBuffer(this._ctx);
|
|
122
113
|
});
|
|
123
114
|
|
|
124
115
|
private _signallingDelay = STARTING_SIGNALLING_DELAY;
|
|
@@ -165,7 +156,7 @@ export class Connection {
|
|
|
165
156
|
*/
|
|
166
157
|
async openConnection(): Promise<void> {
|
|
167
158
|
invariant(this._state === ConnectionState.INITIAL, 'Invalid state.');
|
|
168
|
-
log
|
|
159
|
+
log('opening connection');
|
|
169
160
|
log.trace('dxos.mesh.connection.open', {
|
|
170
161
|
sessionId: this.sessionId,
|
|
171
162
|
topic: this.topic,
|
|
@@ -185,16 +176,18 @@ export class Connection {
|
|
|
185
176
|
this._protocol.stream.on('close', () => {
|
|
186
177
|
log('protocol stream closed');
|
|
187
178
|
this._protocolClosed.wake();
|
|
188
|
-
this.close({ error: new ProtocolError('protocol stream closed') }).catch((err) =>
|
|
179
|
+
this.close({ error: new ProtocolError({ message: 'protocol stream closed' }) }).catch((err) =>
|
|
180
|
+
this.errors.raise(err),
|
|
181
|
+
);
|
|
189
182
|
});
|
|
190
183
|
|
|
191
184
|
scheduleTask(
|
|
192
185
|
this.connectedTimeoutContext,
|
|
193
186
|
async () => {
|
|
194
187
|
log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect, aborting`);
|
|
195
|
-
await this.abort(
|
|
196
|
-
(
|
|
197
|
-
);
|
|
188
|
+
await this.abort(
|
|
189
|
+
new TimeoutError({ message: `${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect` }),
|
|
190
|
+
).catch((err) => this.errors.raise(err));
|
|
198
191
|
},
|
|
199
192
|
TRANSPORT_CONNECTION_TIMEOUT,
|
|
200
193
|
);
|
|
@@ -255,7 +248,7 @@ export class Connection {
|
|
|
255
248
|
|
|
256
249
|
this._incomingSignalBuffer = [];
|
|
257
250
|
|
|
258
|
-
log
|
|
251
|
+
log('opened connection');
|
|
259
252
|
}
|
|
260
253
|
|
|
261
254
|
@synchronized
|
|
@@ -364,21 +357,21 @@ export class Connection {
|
|
|
364
357
|
this._signalSendTask.schedule();
|
|
365
358
|
}
|
|
366
359
|
|
|
367
|
-
private async _flushSignalBuffer(): Promise<void> {
|
|
360
|
+
private async _flushSignalBuffer(ctx: Context): Promise<void> {
|
|
368
361
|
if (this._outgoingSignalBuffer.length === 0) {
|
|
369
362
|
return;
|
|
370
363
|
}
|
|
371
364
|
|
|
372
365
|
try {
|
|
373
366
|
if (process.env.NODE_ENV !== 'test') {
|
|
374
|
-
await cancelWithContext(
|
|
367
|
+
await cancelWithContext(ctx, sleep(this._signallingDelay));
|
|
375
368
|
this._signallingDelay = Math.min(this._signallingDelay * 2, MAX_SIGNALLING_DELAY);
|
|
376
369
|
}
|
|
377
370
|
|
|
378
371
|
const signals = [...this._outgoingSignalBuffer];
|
|
379
372
|
this._outgoingSignalBuffer.length = 0;
|
|
380
373
|
|
|
381
|
-
await this._signalMessaging.signal({
|
|
374
|
+
await this._signalMessaging.signal(ctx, {
|
|
382
375
|
author: this.localInfo,
|
|
383
376
|
recipient: this.remoteInfo,
|
|
384
377
|
sessionId: this.sessionId,
|
|
@@ -397,14 +390,14 @@ export class Connection {
|
|
|
397
390
|
|
|
398
391
|
// If signal fails treat connection as failed
|
|
399
392
|
log.info('signal message failed to deliver', { err });
|
|
400
|
-
await this.close({ error: new ConnectivityError('signal message failed to deliver', err) });
|
|
393
|
+
await this.close({ error: new ConnectivityError({ message: 'signal message failed to deliver', cause: err }) });
|
|
401
394
|
}
|
|
402
395
|
}
|
|
403
396
|
|
|
404
397
|
/**
|
|
405
398
|
* Receive a signal from the remote peer.
|
|
406
399
|
*/
|
|
407
|
-
async signal(msg: SignalMessage): Promise<void> {
|
|
400
|
+
async signal(_ctx: Context, msg: SignalMessage): Promise<void> {
|
|
408
401
|
invariant(msg.sessionId);
|
|
409
402
|
if (!msg.sessionId.equals(this.sessionId)) {
|
|
410
403
|
log('dropping signal for incorrect session id');
|
package/src/swarm/peer.ts
CHANGED
|
@@ -14,13 +14,12 @@ import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
|
14
14
|
import { type OfferMessage, type SignalMessage, type SignalMessenger } from '../signal';
|
|
15
15
|
import { type TransportFactory } from '../transport';
|
|
16
16
|
import { type WireProtocolProvider } from '../wire-protocol';
|
|
17
|
-
|
|
18
17
|
import { Connection, ConnectionState } from './connection';
|
|
19
18
|
import { type ConnectionLimiter } from './connection-limiter';
|
|
20
19
|
|
|
21
20
|
export class ConnectionDisplacedError extends SystemError {
|
|
22
21
|
constructor() {
|
|
23
|
-
super('Connection displaced by remote initiator.');
|
|
22
|
+
super({ message: 'Connection displaced by remote initiator.' });
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
|
|
@@ -106,7 +105,7 @@ export class Peer {
|
|
|
106
105
|
/**
|
|
107
106
|
* Respond to remote offer.
|
|
108
107
|
*/
|
|
109
|
-
async onOffer(message: OfferMessage): Promise<Answer> {
|
|
108
|
+
async onOffer(_ctx: Context, message: OfferMessage): Promise<Answer> {
|
|
110
109
|
const remote = message.author;
|
|
111
110
|
|
|
112
111
|
if (
|
|
@@ -162,13 +161,14 @@ export class Peer {
|
|
|
162
161
|
return { accept: true };
|
|
163
162
|
}
|
|
164
163
|
}
|
|
164
|
+
|
|
165
165
|
return { accept: false };
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* Initiate a connection to the remote peer.
|
|
170
170
|
*/
|
|
171
|
-
async initiateConnection(): Promise<void> {
|
|
171
|
+
async initiateConnection(ctx: Context): Promise<void> {
|
|
172
172
|
invariant(!this.initiating, 'Initiation in progress.');
|
|
173
173
|
invariant(!this.connection, 'Already connected.');
|
|
174
174
|
const sessionId = PublicKey.random();
|
|
@@ -182,7 +182,7 @@ export class Peer {
|
|
|
182
182
|
await this._connectionLimiter.connecting(sessionId);
|
|
183
183
|
connection.initiate();
|
|
184
184
|
|
|
185
|
-
answer = await this._signalMessaging.offer({
|
|
185
|
+
answer = await this._signalMessaging.offer(ctx, {
|
|
186
186
|
author: this.localInfo,
|
|
187
187
|
recipient: this.remoteInfo,
|
|
188
188
|
sessionId,
|
|
@@ -377,13 +377,13 @@ export class Peer {
|
|
|
377
377
|
log('closed', { peerId: this.remoteInfo, sessionId: connection.sessionId });
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
async onSignal(message: SignalMessage): Promise<void> {
|
|
380
|
+
async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
|
|
381
381
|
if (!this.connection) {
|
|
382
382
|
log('dropping signal message for non-existent connection', { message });
|
|
383
383
|
return;
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
-
await this.connection.signal(message);
|
|
386
|
+
await this.connection.signal(ctx, message);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
@synchronized
|
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -18,7 +18,6 @@ import { ComplexSet } from '@dxos/util';
|
|
|
18
18
|
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
19
19
|
import { FullyConnectedTopology } from '../topology';
|
|
20
20
|
import { createRtcTransportFactory } from '../transport';
|
|
21
|
-
|
|
22
21
|
import { ConnectionState } from './connection';
|
|
23
22
|
import { ConnectionLimiter } from './connection-limiter';
|
|
24
23
|
import { Swarm } from './swarm';
|
|
@@ -159,9 +158,9 @@ describe.skip('Swarm', () => {
|
|
|
159
158
|
const messages = new ComplexSet<{ author: PeerInfo; recipient: PeerInfo }>(
|
|
160
159
|
({ author, recipient }) => author.peerKey + recipient.peerKey,
|
|
161
160
|
);
|
|
162
|
-
signalManager.sendMessage = async (message) => {
|
|
161
|
+
signalManager.sendMessage = async (ctx, message) => {
|
|
163
162
|
messages.add({ author: message.author, recipient: message.recipient });
|
|
164
|
-
return sendOriginal(message);
|
|
163
|
+
return sendOriginal(ctx, message);
|
|
165
164
|
};
|
|
166
165
|
// Stop signaling to stop connection in initiation state.
|
|
167
166
|
signalManager.freeze();
|
package/src/swarm/swarm.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { invariant } from '@dxos/invariant';
|
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { log, logInfo } from '@dxos/log';
|
|
11
11
|
import { type ListeningHandle, type Messenger, type PeerInfo, PeerInfoHash, type SwarmEvent } from '@dxos/messaging';
|
|
12
|
-
import { trace } from '@dxos/protocols';
|
|
13
12
|
import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
|
|
14
13
|
import { ComplexMap, isNonNullable } from '@dxos/util';
|
|
15
14
|
|
|
@@ -18,7 +17,6 @@ import { type SwarmController, type Topology } from '../topology';
|
|
|
18
17
|
import { type TransportFactory } from '../transport';
|
|
19
18
|
import { type Topic } from '../types';
|
|
20
19
|
import { type WireProtocolProvider } from '../wire-protocol';
|
|
21
|
-
|
|
22
20
|
import { type Connection, ConnectionState } from './connection';
|
|
23
21
|
import { type ConnectionLimiter } from './connection-limiter';
|
|
24
22
|
import { Peer } from './peer';
|
|
@@ -86,20 +84,15 @@ export class Swarm {
|
|
|
86
84
|
private readonly _connectionLimiter: ConnectionLimiter,
|
|
87
85
|
private readonly _initiationDelay = INITIATION_DELAY,
|
|
88
86
|
) {
|
|
89
|
-
log.
|
|
90
|
-
'dxos.mesh.swarm.constructor',
|
|
91
|
-
trace.begin({ id: this._instanceId, data: { topic: this._topic.toHex(), peer: this._ownPeer } }),
|
|
92
|
-
);
|
|
93
|
-
log('creating swarm', { peerId: _ownPeer });
|
|
87
|
+
log('creating swarm', { topic: this._topic.toHex(), peer: this._ownPeer });
|
|
94
88
|
_topology.init(this._getSwarmController());
|
|
95
89
|
|
|
96
90
|
this._swarmMessenger = new SwarmMessenger({
|
|
97
|
-
sendMessage: async (msg) => await this._messenger.sendMessage(msg),
|
|
98
|
-
onSignal: async (msg) => await this.onSignal(msg),
|
|
99
|
-
onOffer: async (msg) => await this.onOffer(msg),
|
|
91
|
+
sendMessage: async (ctx, msg) => await this._messenger.sendMessage(ctx, msg),
|
|
92
|
+
onSignal: async (ctx, msg) => await this.onSignal(ctx, msg),
|
|
93
|
+
onOffer: async (ctx, msg) => await this.onOffer(ctx, msg),
|
|
100
94
|
topic: this._topic,
|
|
101
95
|
});
|
|
102
|
-
log.trace('dxos.mesh.swarm.constructor', trace.end({ id: this._instanceId }));
|
|
103
96
|
}
|
|
104
97
|
|
|
105
98
|
get connections() {
|
|
@@ -136,7 +129,7 @@ export class Swarm {
|
|
|
136
129
|
payloadType: 'dxos.mesh.swarm.SwarmMessage',
|
|
137
130
|
onMessage: async (message) => {
|
|
138
131
|
await this._swarmMessenger
|
|
139
|
-
.receiveMessage(message)
|
|
132
|
+
.receiveMessage(this._ctx, message)
|
|
140
133
|
// TODO(nf): discriminate between errors
|
|
141
134
|
.catch((err) => log.info('Error while receiving message', { err }));
|
|
142
135
|
},
|
|
@@ -205,7 +198,7 @@ export class Swarm {
|
|
|
205
198
|
}
|
|
206
199
|
|
|
207
200
|
@synchronized
|
|
208
|
-
async onOffer(message: OfferMessage): Promise<Answer> {
|
|
201
|
+
async onOffer(ctx: Context, message: OfferMessage): Promise<Answer> {
|
|
209
202
|
log('offer', { message });
|
|
210
203
|
if (this._ctx.disposed) {
|
|
211
204
|
log('ignored for disposed swarm');
|
|
@@ -224,7 +217,7 @@ export class Swarm {
|
|
|
224
217
|
}
|
|
225
218
|
|
|
226
219
|
const peer = this._getOfferSenderPeer(message.author);
|
|
227
|
-
const answer = await peer.onOffer(message);
|
|
220
|
+
const answer = await peer.onOffer(ctx, message);
|
|
228
221
|
this._topology.update();
|
|
229
222
|
return answer;
|
|
230
223
|
}
|
|
@@ -243,7 +236,7 @@ export class Swarm {
|
|
|
243
236
|
return peer;
|
|
244
237
|
}
|
|
245
238
|
|
|
246
|
-
async onSignal(message: SignalMessage): Promise<void> {
|
|
239
|
+
async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
|
|
247
240
|
log('signal', { message });
|
|
248
241
|
if (this._ctx.disposed) {
|
|
249
242
|
log.info('ignored for offline swarm');
|
|
@@ -257,7 +250,7 @@ export class Swarm {
|
|
|
257
250
|
invariant(message.author);
|
|
258
251
|
|
|
259
252
|
const peer = this._getOrCreatePeer(message.author);
|
|
260
|
-
await peer.onSignal(message);
|
|
253
|
+
await peer.onSignal(ctx, message);
|
|
261
254
|
}
|
|
262
255
|
|
|
263
256
|
// For debug purposes
|
|
@@ -404,7 +397,7 @@ export class Swarm {
|
|
|
404
397
|
}
|
|
405
398
|
|
|
406
399
|
log('initiating connection...', { remotePeer });
|
|
407
|
-
await peer.initiateConnection();
|
|
400
|
+
await peer.initiateConnection(ctx);
|
|
408
401
|
this._topology.update();
|
|
409
402
|
log('initiated', { remotePeer });
|
|
410
403
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Context } from '@dxos/context';
|
|
5
6
|
import { PublicKey } from '@dxos/keys';
|
|
6
7
|
import { log } from '@dxos/log';
|
|
7
8
|
import {
|
|
@@ -28,7 +29,6 @@ import {
|
|
|
28
29
|
TransportKind,
|
|
29
30
|
createRtcTransportFactory,
|
|
30
31
|
} from '../transport';
|
|
31
|
-
|
|
32
32
|
import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
|
|
33
33
|
|
|
34
34
|
// Signal server will be started by the setup script.
|
|
@@ -169,7 +169,7 @@ export class TestPeer {
|
|
|
169
169
|
|
|
170
170
|
await this._proxy?.close();
|
|
171
171
|
await this._service?.close();
|
|
172
|
-
await this._networkManager.close();
|
|
172
|
+
await this._networkManager.close(Context.default());
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
getSwarm(topic: PublicKey): TestSwarmConnection {
|
|
@@ -218,7 +218,7 @@ export class TestSwarmConnection {
|
|
|
218
218
|
// TODO(burdon): Need to create new plugin instance per swarm?
|
|
219
219
|
// If so, then perhaps joinSwarm should return swarm object with access to plugins.
|
|
220
220
|
async join(topology = new FullyConnectedTopology()): Promise<this> {
|
|
221
|
-
await this.peer._networkManager.joinSwarm({
|
|
221
|
+
await this.peer._networkManager.joinSwarm(Context.default(), {
|
|
222
222
|
topic: this.topic,
|
|
223
223
|
peerInfo: { peerKey: this.peer.peerId.toHex(), identityKey: this.peer.peerId.toHex() },
|
|
224
224
|
protocolProvider: this.protocol.factory,
|
|
@@ -229,7 +229,7 @@ export class TestSwarmConnection {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
async leave(): Promise<this> {
|
|
232
|
-
await this.peer._networkManager.leaveSwarm(this.topic);
|
|
232
|
+
await this.peer._networkManager.leaveSwarm(Context.default(), this.topic);
|
|
233
233
|
return this;
|
|
234
234
|
}
|
|
235
235
|
}
|
|
@@ -11,7 +11,6 @@ import { range } from '@dxos/util';
|
|
|
11
11
|
|
|
12
12
|
import { type TestBuilder } from '../testing';
|
|
13
13
|
import { FullyConnectedTopology, StarTopology } from '../topology';
|
|
14
|
-
|
|
15
14
|
import { exchangeMessages, joinSwarm, leaveSwarm, openAndCloseAfterTest } from './utils';
|
|
16
15
|
|
|
17
16
|
// TODO(burdon): Use PublicKey throughout (remove conversion to strings, from buffers, etc.)
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { randomBytes } from 'node:crypto';
|
|
6
|
-
|
|
7
6
|
import { describe, test } from 'vitest';
|
|
8
7
|
|
|
9
8
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -11,7 +10,6 @@ import { range } from '@dxos/util';
|
|
|
11
10
|
|
|
12
11
|
import { TestBuilder } from '../testing';
|
|
13
12
|
import { FullyConnectedTopology } from '../topology';
|
|
14
|
-
|
|
15
13
|
import { basicTestSuite } from './basic-test-suite';
|
|
16
14
|
import { exchangeMessages, joinSwarm, leaveSwarm, openAndCloseAfterTest } from './utils';
|
|
17
15
|
|
|
@@ -6,6 +6,7 @@ import * as fc from 'fast-check';
|
|
|
6
6
|
import { type ModelRunSetup } from 'fast-check';
|
|
7
7
|
import { test } from 'vitest';
|
|
8
8
|
|
|
9
|
+
import { Context } from '@dxos/context';
|
|
9
10
|
import { todo } from '@dxos/debug';
|
|
10
11
|
import { PublicKey } from '@dxos/keys';
|
|
11
12
|
import { ComplexMap, ComplexSet, range } from '@dxos/util';
|
|
@@ -97,7 +98,7 @@ export const propertyTestSuite = () => {
|
|
|
97
98
|
model.joinedPeers.delete(this.peerId);
|
|
98
99
|
|
|
99
100
|
const peer = real.peers.get(this.peerId);
|
|
100
|
-
await peer!.networkManager.close();
|
|
101
|
+
await peer!.networkManager.close(Context.default());
|
|
101
102
|
real.peers.delete(this.peerId);
|
|
102
103
|
|
|
103
104
|
await assertState(model, real);
|
|
@@ -119,7 +120,7 @@ export const propertyTestSuite = () => {
|
|
|
119
120
|
// afterTest(() => presence.stop());
|
|
120
121
|
// const protocol = createProtocolFactory(model.topic, this.peerId, [presence]);
|
|
121
122
|
|
|
122
|
-
await peer.networkManager.joinSwarm({
|
|
123
|
+
await peer.networkManager.joinSwarm(Context.default(), {
|
|
123
124
|
peerInfo: {
|
|
124
125
|
peerKey: this.peerId.toHex(),
|
|
125
126
|
identityKey: this.peerId.toHex(),
|
|
@@ -146,7 +147,7 @@ export const propertyTestSuite = () => {
|
|
|
146
147
|
model.joinedPeers.delete(this.peerId);
|
|
147
148
|
|
|
148
149
|
const peer = real.peers.get(this.peerId)!;
|
|
149
|
-
await peer.networkManager.leaveSwarm(model.topic);
|
|
150
|
+
await peer.networkManager.leaveSwarm(Context.default(), model.topic);
|
|
150
151
|
peer.presence = undefined;
|
|
151
152
|
|
|
152
153
|
await assertState(model, real);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { randomBytes } from 'node:crypto';
|
|
6
|
-
|
|
7
6
|
import { describe, test } from 'vitest';
|
|
8
7
|
|
|
9
8
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -12,7 +11,6 @@ import { range } from '@dxos/util';
|
|
|
12
11
|
import { TestBuilder } from '../testing';
|
|
13
12
|
import { FullyConnectedTopology } from '../topology';
|
|
14
13
|
import { TransportKind } from '../transport';
|
|
15
|
-
|
|
16
14
|
import { basicTestSuite } from './basic-test-suite';
|
|
17
15
|
import { exchangeMessages, joinSwarm, leaveSwarm, openAndCloseAfterTest } from './utils';
|
|
18
16
|
|