@dxos/network-manager 0.6.12-staging.e11e696 → 0.6.12
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-YOKKEU6T.mjs → chunk-XYSYUN63.mjs} +998 -1192
- package/dist/lib/browser/chunk-XYSYUN63.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +19 -10
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +27 -18
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-7ZWQLO5T.cjs → chunk-4YAYC7WN.cjs} +1166 -1233
- package/dist/lib/node/chunk-4YAYC7WN.cjs.map +7 -0
- package/dist/lib/node/index.cjs +37 -27
- package/dist/lib/node/index.cjs.map +2 -2
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +29 -20
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/types/src/signal/integration.test.d.ts +2 -0
- package/dist/types/src/signal/integration.test.d.ts.map +1 -0
- package/dist/types/src/signal/swarm-messenger.test.d.ts +2 -0
- package/dist/types/src/signal/swarm-messenger.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/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.test.d.ts +2 -0
- package/dist/types/src/tests/tcp-transport.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 +5 -1
- package/dist/types/src/transport/index.d.ts.map +1 -1
- package/dist/types/src/transport/libdatachannel-transport.d.ts +42 -0
- package/dist/types/src/transport/libdatachannel-transport.d.ts.map +1 -0
- package/dist/types/src/transport/libdatachannel-transport.test.d.ts +2 -0
- package/dist/types/src/transport/libdatachannel-transport.test.d.ts.map +1 -0
- 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/memory-transport.test.d.ts +2 -0
- package/dist/types/src/transport/memory-transport.test.d.ts.map +1 -0
- package/dist/types/src/transport/simplepeer-simple-peer.d.ts +2 -0
- package/dist/types/src/transport/simplepeer-simple-peer.d.ts.map +1 -0
- package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts +2 -0
- package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts.map +1 -0
- package/dist/types/src/transport/{webrtc/rtc-transport-proxy.d.ts → simplepeer-transport-proxy.d.ts} +12 -10
- package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +1 -0
- package/dist/types/src/transport/{webrtc/rtc-transport-service.d.ts → simplepeer-transport-service.d.ts} +7 -9
- package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +1 -0
- package/dist/types/src/transport/simplepeer-transport.d.ts +36 -0
- package/dist/types/src/transport/simplepeer-transport.d.ts.map +1 -0
- package/dist/types/src/transport/simplepeer-transport.test.d.ts +2 -0
- package/dist/types/src/transport/simplepeer-transport.test.d.ts.map +1 -0
- package/dist/types/src/transport/{tcp/tcp-transport.browser.d.ts → tcp-transport.browser.d.ts} +3 -3
- package/dist/types/src/transport/tcp-transport.browser.d.ts.map +1 -0
- package/dist/types/src/transport/{tcp/tcp-transport.d.ts → tcp-transport.d.ts} +3 -3
- package/dist/types/src/transport/tcp-transport.d.ts.map +1 -0
- package/dist/types/src/transport/transport.d.ts +6 -7
- package/dist/types/src/transport/transport.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc.d.ts +6 -0
- package/dist/types/src/transport/webrtc.d.ts.map +1 -0
- package/package.json +30 -53
- package/src/globals.d.ts +7 -0
- package/src/signal/ice.test.ts +3 -1
- package/src/signal/{integration.node.test.ts → integration.test.ts} +15 -9
- package/src/signal/{swarm-messenger.node.test.ts → swarm-messenger.test.ts} +23 -13
- package/src/swarm/connection-limiter.test.ts +6 -3
- package/src/swarm/connection.test.ts +38 -63
- package/src/swarm/connection.ts +5 -5
- package/src/swarm/swarm.test.ts +11 -9
- package/src/swarm/swarm.ts +1 -1
- package/src/testing/test-builder.ts +28 -12
- package/src/tests/basic-test-suite.ts +33 -34
- package/src/tests/memory-transport.test.ts +42 -40
- package/src/tests/property-test-suite.ts +22 -21
- package/src/tests/tcp-transport.test.ts +67 -0
- package/src/tests/utils.ts +2 -3
- package/src/tests/webrtc-transport.test.ts +9 -9
- package/src/transport/index.ts +5 -1
- package/src/transport/libdatachannel-transport.test.ts +100 -0
- package/src/transport/libdatachannel-transport.ts +376 -0
- package/src/transport/memory-transport.test.ts +74 -0
- package/src/transport/memory-transport.ts +0 -2
- package/src/transport/simplepeer-simple-peer.ts +26 -0
- package/src/transport/simplepeer-transport-proxy-test.ts +181 -0
- package/src/transport/simplepeer-transport-proxy.ts +246 -0
- package/src/transport/simplepeer-transport-service.ts +160 -0
- package/src/transport/simplepeer-transport.test.ts +61 -0
- package/src/transport/simplepeer-transport.ts +250 -0
- package/src/transport/{tcp/tcp-transport.browser.ts → tcp-transport.browser.ts} +3 -7
- package/src/transport/{tcp/tcp-transport.ts → tcp-transport.ts} +1 -3
- package/src/transport/transport.ts +7 -8
- package/src/transport/webrtc.ts +15 -0
- package/src/typings.d.ts +2 -8
- package/dist/lib/browser/chunk-GW3YM55A.mjs +0 -14
- package/dist/lib/browser/chunk-GW3YM55A.mjs.map +0 -7
- package/dist/lib/browser/chunk-YOKKEU6T.mjs.map +0 -7
- package/dist/lib/browser/transport/tcp/index.mjs +0 -39
- package/dist/lib/browser/transport/tcp/index.mjs.map +0 -7
- package/dist/lib/node/chunk-7ZWQLO5T.cjs.map +0 -7
- package/dist/lib/node/transport/tcp/index.cjs +0 -191
- package/dist/lib/node/transport/tcp/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-4VO725JT.mjs +0 -4383
- package/dist/lib/node-esm/chunk-4VO725JT.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -50
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -280
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/transport/tcp/index.mjs +0 -159
- package/dist/lib/node-esm/transport/tcp/index.mjs.map +0 -7
- package/dist/types/src/signal/integration.node.test.d.ts +0 -2
- package/dist/types/src/signal/integration.node.test.d.ts.map +0 -1
- package/dist/types/src/signal/swarm-messenger.node.test.d.ts +0 -2
- package/dist/types/src/signal/swarm-messenger.node.test.d.ts.map +0 -1
- package/dist/types/src/tests/tcp-transport.node.test.d.ts +0 -2
- package/dist/types/src/tests/tcp-transport.node.test.d.ts.map +0 -1
- package/dist/types/src/transport/tcp/index.d.ts +0 -2
- package/dist/types/src/transport/tcp/index.d.ts.map +0 -1
- package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +0 -1
- package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/index.d.ts +0 -4
- package/dist/types/src/transport/webrtc/index.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts +0 -14
- package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +0 -68
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +0 -33
- package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts +0 -2
- package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts +0 -4
- package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts +0 -2
- package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts +0 -4
- package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts +0 -2
- package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/test-utils.d.ts +0 -5
- package/dist/types/src/transport/webrtc/test-utils.d.ts.map +0 -1
- package/dist/types/src/transport/webrtc/utils.d.ts +0 -3
- package/dist/types/src/transport/webrtc/utils.d.ts.map +0 -1
- package/src/tests/tcp-transport.node.test.ts +0 -65
- package/src/transport/tcp/index.ts +0 -5
- package/src/transport/webrtc/index.ts +0 -7
- package/src/transport/webrtc/rtc-connection-factory.ts +0 -82
- package/src/transport/webrtc/rtc-peer-connection.ts +0 -472
- package/src/transport/webrtc/rtc-transport-channel.test.ts +0 -176
- package/src/transport/webrtc/rtc-transport-channel.ts +0 -195
- package/src/transport/webrtc/rtc-transport-factory.ts +0 -28
- package/src/transport/webrtc/rtc-transport-proxy.test.ts +0 -413
- package/src/transport/webrtc/rtc-transport-proxy.ts +0 -264
- package/src/transport/webrtc/rtc-transport-service.ts +0 -192
- package/src/transport/webrtc/rtc-transport-stats.ts +0 -67
- package/src/transport/webrtc/rtc-transport.test.ts +0 -198
- package/src/transport/webrtc/test-utils.ts +0 -22
- package/src/transport/webrtc/utils.ts +0 -36
|
@@ -1,4383 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
|
|
3
|
-
// packages/core/mesh/network-manager/src/swarm/connection.ts
|
|
4
|
-
import { DeferredTask, Event, sleep, scheduleTask, scheduleTaskInterval, synchronized, Trigger } from "@dxos/async";
|
|
5
|
-
import { Context, cancelWithContext, ContextDisposedError } from "@dxos/context";
|
|
6
|
-
import { ErrorStream } from "@dxos/debug";
|
|
7
|
-
import { invariant } from "@dxos/invariant";
|
|
8
|
-
import { PublicKey } from "@dxos/keys";
|
|
9
|
-
import { log, logInfo } from "@dxos/log";
|
|
10
|
-
import { CancelledError, ProtocolError, ConnectionResetError, ConnectivityError, TimeoutError, trace } from "@dxos/protocols";
|
|
11
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
12
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
13
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
14
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
15
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
16
|
-
}
|
|
17
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/connection.ts";
|
|
18
|
-
var STARTING_SIGNALLING_DELAY = 10;
|
|
19
|
-
var TRANSPORT_CONNECTION_TIMEOUT = 1e4;
|
|
20
|
-
var TRANSPORT_STATS_INTERVAL = 5e3;
|
|
21
|
-
var MAX_SIGNALLING_DELAY = 300;
|
|
22
|
-
var ConnectionState;
|
|
23
|
-
(function(ConnectionState5) {
|
|
24
|
-
ConnectionState5["CREATED"] = "CREATED";
|
|
25
|
-
ConnectionState5["INITIAL"] = "INITIAL";
|
|
26
|
-
ConnectionState5["CONNECTING"] = "CONNECTING";
|
|
27
|
-
ConnectionState5["CONNECTED"] = "CONNECTED";
|
|
28
|
-
ConnectionState5["CLOSING"] = "CLOSING";
|
|
29
|
-
ConnectionState5["CLOSED"] = "CLOSED";
|
|
30
|
-
ConnectionState5["ABORTING"] = "ABORTING";
|
|
31
|
-
ConnectionState5["ABORTED"] = "ABORTED";
|
|
32
|
-
})(ConnectionState || (ConnectionState = {}));
|
|
33
|
-
var Connection = class {
|
|
34
|
-
constructor(topic, localInfo, remoteInfo, sessionId, initiator, _signalMessaging, _protocol, _transportFactory, _callbacks) {
|
|
35
|
-
this.topic = topic;
|
|
36
|
-
this.localInfo = localInfo;
|
|
37
|
-
this.remoteInfo = remoteInfo;
|
|
38
|
-
this.sessionId = sessionId;
|
|
39
|
-
this.initiator = initiator;
|
|
40
|
-
this._signalMessaging = _signalMessaging;
|
|
41
|
-
this._protocol = _protocol;
|
|
42
|
-
this._transportFactory = _transportFactory;
|
|
43
|
-
this._callbacks = _callbacks;
|
|
44
|
-
this._ctx = new Context(void 0, {
|
|
45
|
-
F: __dxlog_file,
|
|
46
|
-
L: 100
|
|
47
|
-
});
|
|
48
|
-
this.connectedTimeoutContext = new Context(void 0, {
|
|
49
|
-
F: __dxlog_file,
|
|
50
|
-
L: 101
|
|
51
|
-
});
|
|
52
|
-
this._protocolClosed = new Trigger();
|
|
53
|
-
this._transportClosed = new Trigger();
|
|
54
|
-
this._state = "CREATED";
|
|
55
|
-
this._incomingSignalBuffer = [];
|
|
56
|
-
this._outgoingSignalBuffer = [];
|
|
57
|
-
this.stateChanged = new Event();
|
|
58
|
-
this.errors = new ErrorStream();
|
|
59
|
-
this._instanceId = PublicKey.random().toHex();
|
|
60
|
-
this.transportStats = new Event();
|
|
61
|
-
this._signalSendTask = new DeferredTask(this._ctx, async () => {
|
|
62
|
-
await this._flushSignalBuffer();
|
|
63
|
-
});
|
|
64
|
-
this._signallingDelay = STARTING_SIGNALLING_DELAY;
|
|
65
|
-
log.trace("dxos.mesh.connection.construct", {
|
|
66
|
-
sessionId: this.sessionId,
|
|
67
|
-
topic: this.topic,
|
|
68
|
-
localPeer: this.localInfo,
|
|
69
|
-
remotePeer: this.remoteInfo,
|
|
70
|
-
initiator: this.initiator
|
|
71
|
-
}, {
|
|
72
|
-
F: __dxlog_file,
|
|
73
|
-
L: 137,
|
|
74
|
-
S: this,
|
|
75
|
-
C: (f, a) => f(...a)
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
get sessionIdString() {
|
|
79
|
-
return this.sessionId.truncate();
|
|
80
|
-
}
|
|
81
|
-
get state() {
|
|
82
|
-
return this._state;
|
|
83
|
-
}
|
|
84
|
-
get transport() {
|
|
85
|
-
return this._transport;
|
|
86
|
-
}
|
|
87
|
-
get protocol() {
|
|
88
|
-
return this._protocol;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Create an underlying transport and prepares it for the connection.
|
|
92
|
-
*/
|
|
93
|
-
async openConnection() {
|
|
94
|
-
invariant(this._state === "INITIAL", "Invalid state.", {
|
|
95
|
-
F: __dxlog_file,
|
|
96
|
-
L: 167,
|
|
97
|
-
S: this,
|
|
98
|
-
A: [
|
|
99
|
-
"this._state === ConnectionState.INITIAL",
|
|
100
|
-
"'Invalid state.'"
|
|
101
|
-
]
|
|
102
|
-
});
|
|
103
|
-
log.trace("dxos.mesh.connection.open-connection", trace.begin({
|
|
104
|
-
id: this._instanceId
|
|
105
|
-
}), {
|
|
106
|
-
F: __dxlog_file,
|
|
107
|
-
L: 168,
|
|
108
|
-
S: this,
|
|
109
|
-
C: (f, a) => f(...a)
|
|
110
|
-
});
|
|
111
|
-
log.trace("dxos.mesh.connection.open", {
|
|
112
|
-
sessionId: this.sessionId,
|
|
113
|
-
topic: this.topic,
|
|
114
|
-
localPeerId: this.localInfo,
|
|
115
|
-
remotePeerId: this.remoteInfo,
|
|
116
|
-
initiator: this.initiator
|
|
117
|
-
}, {
|
|
118
|
-
F: __dxlog_file,
|
|
119
|
-
L: 169,
|
|
120
|
-
S: this,
|
|
121
|
-
C: (f, a) => f(...a)
|
|
122
|
-
});
|
|
123
|
-
this._changeState("CONNECTING");
|
|
124
|
-
this._protocol.open(this.sessionId).catch((err) => {
|
|
125
|
-
this.errors.raise(err);
|
|
126
|
-
});
|
|
127
|
-
this._protocol.stream.on("close", () => {
|
|
128
|
-
log("protocol stream closed", void 0, {
|
|
129
|
-
F: __dxlog_file,
|
|
130
|
-
L: 186,
|
|
131
|
-
S: this,
|
|
132
|
-
C: (f, a) => f(...a)
|
|
133
|
-
});
|
|
134
|
-
this._protocolClosed.wake();
|
|
135
|
-
this.close(new ProtocolError("protocol stream closed")).catch((err) => this.errors.raise(err));
|
|
136
|
-
});
|
|
137
|
-
scheduleTask(this.connectedTimeoutContext, async () => {
|
|
138
|
-
log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1e3}s for transport to connect, aborting`, void 0, {
|
|
139
|
-
F: __dxlog_file,
|
|
140
|
-
L: 194,
|
|
141
|
-
S: this,
|
|
142
|
-
C: (f, a) => f(...a)
|
|
143
|
-
});
|
|
144
|
-
await this.abort(new TimeoutError(`${TRANSPORT_CONNECTION_TIMEOUT / 1e3}s for transport to connect`)).catch((err) => this.errors.raise(err));
|
|
145
|
-
}, TRANSPORT_CONNECTION_TIMEOUT);
|
|
146
|
-
invariant(!this._transport, void 0, {
|
|
147
|
-
F: __dxlog_file,
|
|
148
|
-
L: 202,
|
|
149
|
-
S: this,
|
|
150
|
-
A: [
|
|
151
|
-
"!this._transport",
|
|
152
|
-
""
|
|
153
|
-
]
|
|
154
|
-
});
|
|
155
|
-
this._transport = this._transportFactory.createTransport({
|
|
156
|
-
ownPeerKey: this.localInfo.peerKey,
|
|
157
|
-
remotePeerKey: this.remoteInfo.peerKey,
|
|
158
|
-
topic: this.topic.toHex(),
|
|
159
|
-
initiator: this.initiator,
|
|
160
|
-
stream: this._protocol.stream,
|
|
161
|
-
sendSignal: async (signal) => this._sendSignal(signal),
|
|
162
|
-
sessionId: this.sessionId
|
|
163
|
-
});
|
|
164
|
-
this._transport.connected.once(async () => {
|
|
165
|
-
this._changeState("CONNECTED");
|
|
166
|
-
await this.connectedTimeoutContext.dispose();
|
|
167
|
-
this._callbacks?.onConnected?.();
|
|
168
|
-
scheduleTaskInterval(this._ctx, async () => this._emitTransportStats(), TRANSPORT_STATS_INTERVAL);
|
|
169
|
-
});
|
|
170
|
-
this._transport.closed.once(() => {
|
|
171
|
-
this._transport = void 0;
|
|
172
|
-
this._transportClosed.wake();
|
|
173
|
-
log("abort triggered by transport close", void 0, {
|
|
174
|
-
F: __dxlog_file,
|
|
175
|
-
L: 224,
|
|
176
|
-
S: this,
|
|
177
|
-
C: (f, a) => f(...a)
|
|
178
|
-
});
|
|
179
|
-
this.abort().catch((err) => this.errors.raise(err));
|
|
180
|
-
});
|
|
181
|
-
this._transport.errors.handle(async (err) => {
|
|
182
|
-
log("transport error:", {
|
|
183
|
-
err
|
|
184
|
-
}, {
|
|
185
|
-
F: __dxlog_file,
|
|
186
|
-
L: 229,
|
|
187
|
-
S: this,
|
|
188
|
-
C: (f, a) => f(...a)
|
|
189
|
-
});
|
|
190
|
-
if (!this.closeReason) {
|
|
191
|
-
this.closeReason = err?.message;
|
|
192
|
-
}
|
|
193
|
-
if (err instanceof ConnectionResetError) {
|
|
194
|
-
log.info("aborting due to transport ConnectionResetError", void 0, {
|
|
195
|
-
F: __dxlog_file,
|
|
196
|
-
L: 236,
|
|
197
|
-
S: this,
|
|
198
|
-
C: (f, a) => f(...a)
|
|
199
|
-
});
|
|
200
|
-
this.abort().catch((err2) => this.errors.raise(err2));
|
|
201
|
-
} else if (err instanceof ConnectivityError) {
|
|
202
|
-
log.info("aborting due to transport ConnectivityError", void 0, {
|
|
203
|
-
F: __dxlog_file,
|
|
204
|
-
L: 239,
|
|
205
|
-
S: this,
|
|
206
|
-
C: (f, a) => f(...a)
|
|
207
|
-
});
|
|
208
|
-
this.abort().catch((err2) => this.errors.raise(err2));
|
|
209
|
-
}
|
|
210
|
-
if (this._state !== "CLOSED" && this._state !== "CLOSING") {
|
|
211
|
-
await this.connectedTimeoutContext.dispose();
|
|
212
|
-
this.errors.raise(err);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
await this._transport.open();
|
|
216
|
-
for (const signal of this._incomingSignalBuffer) {
|
|
217
|
-
void this._transport.onSignal(signal);
|
|
218
|
-
}
|
|
219
|
-
this._incomingSignalBuffer = [];
|
|
220
|
-
log.trace("dxos.mesh.connection.open-connection", trace.end({
|
|
221
|
-
id: this._instanceId
|
|
222
|
-
}), {
|
|
223
|
-
F: __dxlog_file,
|
|
224
|
-
L: 258,
|
|
225
|
-
S: this,
|
|
226
|
-
C: (f, a) => f(...a)
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
async abort(err) {
|
|
230
|
-
log("aborting...", {
|
|
231
|
-
err
|
|
232
|
-
}, {
|
|
233
|
-
F: __dxlog_file,
|
|
234
|
-
L: 265,
|
|
235
|
-
S: this,
|
|
236
|
-
C: (f, a) => f(...a)
|
|
237
|
-
});
|
|
238
|
-
if (this._state === "CLOSED" || this._state === "ABORTED") {
|
|
239
|
-
log(`abort ignored: already ${this._state}`, this.closeReason, {
|
|
240
|
-
F: __dxlog_file,
|
|
241
|
-
L: 267,
|
|
242
|
-
S: this,
|
|
243
|
-
C: (f, a) => f(...a)
|
|
244
|
-
});
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
await this.connectedTimeoutContext.dispose();
|
|
248
|
-
this._changeState("ABORTING");
|
|
249
|
-
if (!this.closeReason) {
|
|
250
|
-
this.closeReason = err?.message;
|
|
251
|
-
}
|
|
252
|
-
await this._ctx.dispose();
|
|
253
|
-
try {
|
|
254
|
-
await this._closeProtocol({
|
|
255
|
-
abort: true
|
|
256
|
-
});
|
|
257
|
-
} catch (err2) {
|
|
258
|
-
log.catch(err2, void 0, {
|
|
259
|
-
F: __dxlog_file,
|
|
260
|
-
L: 283,
|
|
261
|
-
S: this,
|
|
262
|
-
C: (f, a) => f(...a)
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
try {
|
|
266
|
-
await this._closeTransport();
|
|
267
|
-
} catch (err2) {
|
|
268
|
-
log.catch(err2, void 0, {
|
|
269
|
-
F: __dxlog_file,
|
|
270
|
-
L: 290,
|
|
271
|
-
S: this,
|
|
272
|
-
C: (f, a) => f(...a)
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
this._callbacks?.onClosed?.(err);
|
|
277
|
-
} catch (err2) {
|
|
278
|
-
log.catch(err2, void 0, {
|
|
279
|
-
F: __dxlog_file,
|
|
280
|
-
L: 296,
|
|
281
|
-
S: this,
|
|
282
|
-
C: (f, a) => f(...a)
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
this._changeState("ABORTED");
|
|
286
|
-
}
|
|
287
|
-
async close(err) {
|
|
288
|
-
if (!this.closeReason) {
|
|
289
|
-
this.closeReason = err?.message;
|
|
290
|
-
} else {
|
|
291
|
-
this.closeReason += `; ${err?.message}`;
|
|
292
|
-
}
|
|
293
|
-
if (this._state === "CLOSED" || this._state === "ABORTING" || this._state === "ABORTED") {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const lastState = this._state;
|
|
297
|
-
this._changeState("CLOSING");
|
|
298
|
-
await this.connectedTimeoutContext.dispose();
|
|
299
|
-
await this._ctx.dispose();
|
|
300
|
-
log("closing...", {
|
|
301
|
-
peerId: this.localInfo
|
|
302
|
-
}, {
|
|
303
|
-
F: __dxlog_file,
|
|
304
|
-
L: 321,
|
|
305
|
-
S: this,
|
|
306
|
-
C: (f, a) => f(...a)
|
|
307
|
-
});
|
|
308
|
-
let abortProtocol = false;
|
|
309
|
-
if (lastState !== "CONNECTED") {
|
|
310
|
-
log(`graceful close requested when we were in ${lastState} state? aborting`, void 0, {
|
|
311
|
-
F: __dxlog_file,
|
|
312
|
-
L: 325,
|
|
313
|
-
S: this,
|
|
314
|
-
C: (f, a) => f(...a)
|
|
315
|
-
});
|
|
316
|
-
abortProtocol = true;
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
await this._closeProtocol({
|
|
320
|
-
abort: abortProtocol
|
|
321
|
-
});
|
|
322
|
-
} catch (err2) {
|
|
323
|
-
log.catch(err2, void 0, {
|
|
324
|
-
F: __dxlog_file,
|
|
325
|
-
L: 331,
|
|
326
|
-
S: this,
|
|
327
|
-
C: (f, a) => f(...a)
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
await this._closeTransport();
|
|
332
|
-
} catch (err2) {
|
|
333
|
-
log.catch(err2, void 0, {
|
|
334
|
-
F: __dxlog_file,
|
|
335
|
-
L: 337,
|
|
336
|
-
S: this,
|
|
337
|
-
C: (f, a) => f(...a)
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
log("closed", {
|
|
341
|
-
peerId: this.localInfo
|
|
342
|
-
}, {
|
|
343
|
-
F: __dxlog_file,
|
|
344
|
-
L: 340,
|
|
345
|
-
S: this,
|
|
346
|
-
C: (f, a) => f(...a)
|
|
347
|
-
});
|
|
348
|
-
this._changeState("CLOSED");
|
|
349
|
-
this._callbacks?.onClosed?.(err);
|
|
350
|
-
}
|
|
351
|
-
async _closeProtocol(options) {
|
|
352
|
-
log("closing protocol", options, {
|
|
353
|
-
F: __dxlog_file,
|
|
354
|
-
L: 346,
|
|
355
|
-
S: this,
|
|
356
|
-
C: (f, a) => f(...a)
|
|
357
|
-
});
|
|
358
|
-
await Promise.race([
|
|
359
|
-
options?.abort ? this._protocol.abort() : this._protocol.close(),
|
|
360
|
-
this._protocolClosed.wait()
|
|
361
|
-
]);
|
|
362
|
-
log("protocol closed", options, {
|
|
363
|
-
F: __dxlog_file,
|
|
364
|
-
L: 348,
|
|
365
|
-
S: this,
|
|
366
|
-
C: (f, a) => f(...a)
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
async _closeTransport() {
|
|
370
|
-
log("closing transport", void 0, {
|
|
371
|
-
F: __dxlog_file,
|
|
372
|
-
L: 352,
|
|
373
|
-
S: this,
|
|
374
|
-
C: (f, a) => f(...a)
|
|
375
|
-
});
|
|
376
|
-
await Promise.race([
|
|
377
|
-
this._transport?.close(),
|
|
378
|
-
this._transportClosed.wait()
|
|
379
|
-
]);
|
|
380
|
-
log("transport closed", void 0, {
|
|
381
|
-
F: __dxlog_file,
|
|
382
|
-
L: 354,
|
|
383
|
-
S: this,
|
|
384
|
-
C: (f, a) => f(...a)
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
_sendSignal(signal) {
|
|
388
|
-
this._outgoingSignalBuffer.push(signal);
|
|
389
|
-
this._signalSendTask.schedule();
|
|
390
|
-
}
|
|
391
|
-
async _flushSignalBuffer() {
|
|
392
|
-
if (this._outgoingSignalBuffer.length === 0) {
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
try {
|
|
396
|
-
if (process.env.NODE_ENV !== "test") {
|
|
397
|
-
await cancelWithContext(this._ctx, sleep(this._signallingDelay));
|
|
398
|
-
this._signallingDelay = Math.min(this._signallingDelay * 2, MAX_SIGNALLING_DELAY);
|
|
399
|
-
}
|
|
400
|
-
const signals = [
|
|
401
|
-
...this._outgoingSignalBuffer
|
|
402
|
-
];
|
|
403
|
-
this._outgoingSignalBuffer.length = 0;
|
|
404
|
-
await this._signalMessaging.signal({
|
|
405
|
-
author: this.localInfo,
|
|
406
|
-
recipient: this.remoteInfo,
|
|
407
|
-
sessionId: this.sessionId,
|
|
408
|
-
topic: this.topic,
|
|
409
|
-
data: {
|
|
410
|
-
signalBatch: {
|
|
411
|
-
signals
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
} catch (err) {
|
|
416
|
-
if (err instanceof CancelledError || err instanceof ContextDisposedError || err instanceof Error && err.message?.includes("CANCELLED")) {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
log.info("signal message failed to deliver", {
|
|
420
|
-
err
|
|
421
|
-
}, {
|
|
422
|
-
F: __dxlog_file,
|
|
423
|
-
L: 394,
|
|
424
|
-
S: this,
|
|
425
|
-
C: (f, a) => f(...a)
|
|
426
|
-
});
|
|
427
|
-
await this.close(new ConnectivityError("signal message failed to deliver", err));
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Receive a signal from the remote peer.
|
|
432
|
-
*/
|
|
433
|
-
async signal(msg) {
|
|
434
|
-
invariant(msg.sessionId, void 0, {
|
|
435
|
-
F: __dxlog_file,
|
|
436
|
-
L: 403,
|
|
437
|
-
S: this,
|
|
438
|
-
A: [
|
|
439
|
-
"msg.sessionId",
|
|
440
|
-
""
|
|
441
|
-
]
|
|
442
|
-
});
|
|
443
|
-
if (!msg.sessionId.equals(this.sessionId)) {
|
|
444
|
-
log("dropping signal for incorrect session id", void 0, {
|
|
445
|
-
F: __dxlog_file,
|
|
446
|
-
L: 405,
|
|
447
|
-
S: this,
|
|
448
|
-
C: (f, a) => f(...a)
|
|
449
|
-
});
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
invariant(msg.data.signal || msg.data.signalBatch, void 0, {
|
|
453
|
-
F: __dxlog_file,
|
|
454
|
-
L: 408,
|
|
455
|
-
S: this,
|
|
456
|
-
A: [
|
|
457
|
-
"msg.data.signal || msg.data.signalBatch",
|
|
458
|
-
""
|
|
459
|
-
]
|
|
460
|
-
});
|
|
461
|
-
invariant(msg.author.peerKey === this.remoteInfo.peerKey, void 0, {
|
|
462
|
-
F: __dxlog_file,
|
|
463
|
-
L: 409,
|
|
464
|
-
S: this,
|
|
465
|
-
A: [
|
|
466
|
-
"msg.author.peerKey === this.remoteInfo.peerKey",
|
|
467
|
-
""
|
|
468
|
-
]
|
|
469
|
-
});
|
|
470
|
-
invariant(msg.recipient.peerKey === this.localInfo.peerKey, void 0, {
|
|
471
|
-
F: __dxlog_file,
|
|
472
|
-
L: 410,
|
|
473
|
-
S: this,
|
|
474
|
-
A: [
|
|
475
|
-
"msg.recipient.peerKey === this.localInfo.peerKey",
|
|
476
|
-
""
|
|
477
|
-
]
|
|
478
|
-
});
|
|
479
|
-
const signals = msg.data.signalBatch ? msg.data.signalBatch.signals ?? [] : [
|
|
480
|
-
msg.data.signal
|
|
481
|
-
];
|
|
482
|
-
for (const signal of signals) {
|
|
483
|
-
if (!signal) {
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
if ([
|
|
487
|
-
"CREATED",
|
|
488
|
-
"INITIAL"
|
|
489
|
-
].includes(this.state)) {
|
|
490
|
-
log("buffered signal", {
|
|
491
|
-
peerId: this.localInfo,
|
|
492
|
-
remoteId: this.remoteInfo,
|
|
493
|
-
msg: msg.data
|
|
494
|
-
}, {
|
|
495
|
-
F: __dxlog_file,
|
|
496
|
-
L: 419,
|
|
497
|
-
S: this,
|
|
498
|
-
C: (f, a) => f(...a)
|
|
499
|
-
});
|
|
500
|
-
this._incomingSignalBuffer.push(signal);
|
|
501
|
-
} else {
|
|
502
|
-
invariant(this._transport, "Connection not ready to accept signals.", {
|
|
503
|
-
F: __dxlog_file,
|
|
504
|
-
L: 422,
|
|
505
|
-
S: this,
|
|
506
|
-
A: [
|
|
507
|
-
"this._transport",
|
|
508
|
-
"'Connection not ready to accept signals.'"
|
|
509
|
-
]
|
|
510
|
-
});
|
|
511
|
-
log("received signal", {
|
|
512
|
-
peerId: this.localInfo,
|
|
513
|
-
remoteId: this.remoteInfo,
|
|
514
|
-
msg: msg.data
|
|
515
|
-
}, {
|
|
516
|
-
F: __dxlog_file,
|
|
517
|
-
L: 423,
|
|
518
|
-
S: this,
|
|
519
|
-
C: (f, a) => f(...a)
|
|
520
|
-
});
|
|
521
|
-
await this._transport.onSignal(signal);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
initiate() {
|
|
526
|
-
this._changeState("INITIAL");
|
|
527
|
-
}
|
|
528
|
-
_changeState(state) {
|
|
529
|
-
log("stateChanged", {
|
|
530
|
-
from: this._state,
|
|
531
|
-
to: state,
|
|
532
|
-
peerId: this.localInfo
|
|
533
|
-
}, {
|
|
534
|
-
F: __dxlog_file,
|
|
535
|
-
L: 434,
|
|
536
|
-
S: this,
|
|
537
|
-
C: (f, a) => f(...a)
|
|
538
|
-
});
|
|
539
|
-
invariant(state !== this._state, "Already in this state.", {
|
|
540
|
-
F: __dxlog_file,
|
|
541
|
-
L: 435,
|
|
542
|
-
S: this,
|
|
543
|
-
A: [
|
|
544
|
-
"state !== this._state",
|
|
545
|
-
"'Already in this state.'"
|
|
546
|
-
]
|
|
547
|
-
});
|
|
548
|
-
this._state = state;
|
|
549
|
-
this.stateChanged.emit(state);
|
|
550
|
-
}
|
|
551
|
-
async _emitTransportStats() {
|
|
552
|
-
const stats = await this.transport?.getStats();
|
|
553
|
-
if (stats) {
|
|
554
|
-
this.transportStats.emit(stats);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
_ts_decorate([
|
|
559
|
-
logInfo
|
|
560
|
-
], Connection.prototype, "sessionIdString", null);
|
|
561
|
-
_ts_decorate([
|
|
562
|
-
synchronized
|
|
563
|
-
], Connection.prototype, "abort", null);
|
|
564
|
-
_ts_decorate([
|
|
565
|
-
synchronized
|
|
566
|
-
], Connection.prototype, "close", null);
|
|
567
|
-
|
|
568
|
-
// packages/core/mesh/network-manager/src/signal/ice.ts
|
|
569
|
-
import { asyncTimeout } from "@dxos/async";
|
|
570
|
-
import { log as log2 } from "@dxos/log";
|
|
571
|
-
import { isNotNullOrUndefined } from "@dxos/util";
|
|
572
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/signal/ice.ts";
|
|
573
|
-
var createIceProvider = (iceProviders) => {
|
|
574
|
-
let cachedIceServers;
|
|
575
|
-
return {
|
|
576
|
-
getIceServers: async () => {
|
|
577
|
-
if (cachedIceServers) {
|
|
578
|
-
return cachedIceServers;
|
|
579
|
-
}
|
|
580
|
-
cachedIceServers = (await Promise.all(iceProviders.map(({ urls }) => asyncTimeout(fetch(urls, {
|
|
581
|
-
method: "GET"
|
|
582
|
-
}), 1e4).then((response) => response.json()).catch((err) => log2.error("Failed to fetch ICE servers from provider", {
|
|
583
|
-
urls,
|
|
584
|
-
err
|
|
585
|
-
}, {
|
|
586
|
-
F: __dxlog_file2,
|
|
587
|
-
L: 27,
|
|
588
|
-
S: void 0,
|
|
589
|
-
C: (f, a) => f(...a)
|
|
590
|
-
}))))).filter(isNotNullOrUndefined).map(({ iceServers }) => iceServers).flat();
|
|
591
|
-
return cachedIceServers;
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
// packages/core/mesh/network-manager/src/signal/swarm-messenger.ts
|
|
597
|
-
import { Context as Context2 } from "@dxos/context";
|
|
598
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
599
|
-
import { PublicKey as PublicKey2 } from "@dxos/keys";
|
|
600
|
-
import { log as log3 } from "@dxos/log";
|
|
601
|
-
import { TimeoutError as TimeoutError2 } from "@dxos/protocols";
|
|
602
|
-
import { schema } from "@dxos/protocols/proto";
|
|
603
|
-
import { ComplexMap } from "@dxos/util";
|
|
604
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/signal/swarm-messenger.ts";
|
|
605
|
-
var SwarmMessage = schema.getCodecForType("dxos.mesh.swarm.SwarmMessage");
|
|
606
|
-
var SwarmMessenger = class {
|
|
607
|
-
constructor({ sendMessage, onSignal, onOffer, topic }) {
|
|
608
|
-
this._ctx = new Context2(void 0, {
|
|
609
|
-
F: __dxlog_file3,
|
|
610
|
-
L: 35
|
|
611
|
-
});
|
|
612
|
-
this._offerRecords = new ComplexMap((key) => key.toHex());
|
|
613
|
-
this._sendMessage = sendMessage;
|
|
614
|
-
this._onSignal = onSignal;
|
|
615
|
-
this._onOffer = onOffer;
|
|
616
|
-
this._topic = topic;
|
|
617
|
-
}
|
|
618
|
-
async receiveMessage({ author, recipient, payload }) {
|
|
619
|
-
if (payload.type_url !== "dxos.mesh.swarm.SwarmMessage") {
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
const message = SwarmMessage.decode(payload.value);
|
|
623
|
-
if (!this._topic.equals(message.topic)) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
log3("received", {
|
|
627
|
-
from: author,
|
|
628
|
-
to: recipient,
|
|
629
|
-
msg: message
|
|
630
|
-
}, {
|
|
631
|
-
F: __dxlog_file3,
|
|
632
|
-
L: 71,
|
|
633
|
-
S: this,
|
|
634
|
-
C: (f, a) => f(...a)
|
|
635
|
-
});
|
|
636
|
-
if (message.data?.offer) {
|
|
637
|
-
await this._handleOffer({
|
|
638
|
-
author,
|
|
639
|
-
recipient,
|
|
640
|
-
message
|
|
641
|
-
});
|
|
642
|
-
} else if (message.data?.answer) {
|
|
643
|
-
await this._resolveAnswers(message);
|
|
644
|
-
} else if (message.data?.signal) {
|
|
645
|
-
await this._handleSignal({
|
|
646
|
-
author,
|
|
647
|
-
recipient,
|
|
648
|
-
message
|
|
649
|
-
});
|
|
650
|
-
} else if (message.data?.signalBatch) {
|
|
651
|
-
await this._handleSignal({
|
|
652
|
-
author,
|
|
653
|
-
recipient,
|
|
654
|
-
message
|
|
655
|
-
});
|
|
656
|
-
} else {
|
|
657
|
-
log3.warn("unknown message", {
|
|
658
|
-
message
|
|
659
|
-
}, {
|
|
660
|
-
F: __dxlog_file3,
|
|
661
|
-
L: 82,
|
|
662
|
-
S: this,
|
|
663
|
-
C: (f, a) => f(...a)
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
async signal(message) {
|
|
668
|
-
invariant2(message.data?.signal || message.data?.signalBatch, "Invalid message", {
|
|
669
|
-
F: __dxlog_file3,
|
|
670
|
-
L: 87,
|
|
671
|
-
S: this,
|
|
672
|
-
A: [
|
|
673
|
-
"message.data?.signal || message.data?.signalBatch",
|
|
674
|
-
"'Invalid message'"
|
|
675
|
-
]
|
|
676
|
-
});
|
|
677
|
-
await this._sendReliableMessage({
|
|
678
|
-
author: message.author,
|
|
679
|
-
recipient: message.recipient,
|
|
680
|
-
message
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
async offer(message) {
|
|
684
|
-
const networkMessage = {
|
|
685
|
-
...message,
|
|
686
|
-
messageId: PublicKey2.random()
|
|
687
|
-
};
|
|
688
|
-
return new Promise((resolve, reject) => {
|
|
689
|
-
this._offerRecords.set(networkMessage.messageId, {
|
|
690
|
-
resolve
|
|
691
|
-
});
|
|
692
|
-
this._sendReliableMessage({
|
|
693
|
-
author: message.author,
|
|
694
|
-
recipient: message.recipient,
|
|
695
|
-
message: networkMessage
|
|
696
|
-
}).catch((err) => reject(err));
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
async _sendReliableMessage({ author, recipient, message }) {
|
|
700
|
-
const networkMessage = {
|
|
701
|
-
...message,
|
|
702
|
-
// Setting unique message_id if it not specified yet.
|
|
703
|
-
messageId: message.messageId ?? PublicKey2.random()
|
|
704
|
-
};
|
|
705
|
-
log3("sending", {
|
|
706
|
-
from: author,
|
|
707
|
-
to: recipient,
|
|
708
|
-
msg: networkMessage
|
|
709
|
-
}, {
|
|
710
|
-
F: __dxlog_file3,
|
|
711
|
-
L: 125,
|
|
712
|
-
S: this,
|
|
713
|
-
C: (f, a) => f(...a)
|
|
714
|
-
});
|
|
715
|
-
await this._sendMessage({
|
|
716
|
-
author,
|
|
717
|
-
recipient,
|
|
718
|
-
payload: {
|
|
719
|
-
type_url: "dxos.mesh.swarm.SwarmMessage",
|
|
720
|
-
value: SwarmMessage.encode(networkMessage)
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
async _resolveAnswers(message) {
|
|
725
|
-
invariant2(message.data?.answer?.offerMessageId, "No offerMessageId", {
|
|
726
|
-
F: __dxlog_file3,
|
|
727
|
-
L: 137,
|
|
728
|
-
S: this,
|
|
729
|
-
A: [
|
|
730
|
-
"message.data?.answer?.offerMessageId",
|
|
731
|
-
"'No offerMessageId'"
|
|
732
|
-
]
|
|
733
|
-
});
|
|
734
|
-
const offerRecord = this._offerRecords.get(message.data.answer.offerMessageId);
|
|
735
|
-
if (offerRecord) {
|
|
736
|
-
this._offerRecords.delete(message.data.answer.offerMessageId);
|
|
737
|
-
invariant2(message.data?.answer, "No answer", {
|
|
738
|
-
F: __dxlog_file3,
|
|
739
|
-
L: 141,
|
|
740
|
-
S: this,
|
|
741
|
-
A: [
|
|
742
|
-
"message.data?.answer",
|
|
743
|
-
"'No answer'"
|
|
744
|
-
]
|
|
745
|
-
});
|
|
746
|
-
log3("resolving", {
|
|
747
|
-
answer: message.data.answer
|
|
748
|
-
}, {
|
|
749
|
-
F: __dxlog_file3,
|
|
750
|
-
L: 142,
|
|
751
|
-
S: this,
|
|
752
|
-
C: (f, a) => f(...a)
|
|
753
|
-
});
|
|
754
|
-
offerRecord.resolve(message.data.answer);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
async _handleOffer({ author, recipient, message }) {
|
|
758
|
-
invariant2(message.data.offer, "No offer", {
|
|
759
|
-
F: __dxlog_file3,
|
|
760
|
-
L: 156,
|
|
761
|
-
S: this,
|
|
762
|
-
A: [
|
|
763
|
-
"message.data.offer",
|
|
764
|
-
"'No offer'"
|
|
765
|
-
]
|
|
766
|
-
});
|
|
767
|
-
const offerMessage = {
|
|
768
|
-
author,
|
|
769
|
-
recipient,
|
|
770
|
-
...message,
|
|
771
|
-
data: {
|
|
772
|
-
offer: message.data.offer
|
|
773
|
-
}
|
|
774
|
-
};
|
|
775
|
-
const answer = await this._onOffer(offerMessage);
|
|
776
|
-
answer.offerMessageId = message.messageId;
|
|
777
|
-
try {
|
|
778
|
-
await this._sendReliableMessage({
|
|
779
|
-
author: recipient,
|
|
780
|
-
recipient: author,
|
|
781
|
-
message: {
|
|
782
|
-
topic: message.topic,
|
|
783
|
-
sessionId: message.sessionId,
|
|
784
|
-
data: {
|
|
785
|
-
answer
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
});
|
|
789
|
-
} catch (err) {
|
|
790
|
-
if (err instanceof TimeoutError2) {
|
|
791
|
-
log3.info("timeout sending answer to offer", {
|
|
792
|
-
err
|
|
793
|
-
}, {
|
|
794
|
-
F: __dxlog_file3,
|
|
795
|
-
L: 177,
|
|
796
|
-
S: this,
|
|
797
|
-
C: (f, a) => f(...a)
|
|
798
|
-
});
|
|
799
|
-
} else {
|
|
800
|
-
log3.info("error sending answer to offer", {
|
|
801
|
-
err
|
|
802
|
-
}, {
|
|
803
|
-
F: __dxlog_file3,
|
|
804
|
-
L: 179,
|
|
805
|
-
S: this,
|
|
806
|
-
C: (f, a) => f(...a)
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
async _handleSignal({ author, recipient, message }) {
|
|
812
|
-
invariant2(message.messageId, void 0, {
|
|
813
|
-
F: __dxlog_file3,
|
|
814
|
-
L: 193,
|
|
815
|
-
S: this,
|
|
816
|
-
A: [
|
|
817
|
-
"message.messageId",
|
|
818
|
-
""
|
|
819
|
-
]
|
|
820
|
-
});
|
|
821
|
-
invariant2(message.data.signal || message.data.signalBatch, "Invalid message", {
|
|
822
|
-
F: __dxlog_file3,
|
|
823
|
-
L: 194,
|
|
824
|
-
S: this,
|
|
825
|
-
A: [
|
|
826
|
-
"message.data.signal || message.data.signalBatch",
|
|
827
|
-
"'Invalid message'"
|
|
828
|
-
]
|
|
829
|
-
});
|
|
830
|
-
const signalMessage = {
|
|
831
|
-
author,
|
|
832
|
-
recipient,
|
|
833
|
-
...message,
|
|
834
|
-
data: {
|
|
835
|
-
signal: message.data.signal,
|
|
836
|
-
signalBatch: message.data.signalBatch
|
|
837
|
-
}
|
|
838
|
-
};
|
|
839
|
-
await this._onSignal(signalMessage);
|
|
840
|
-
}
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
// packages/core/mesh/network-manager/src/swarm/swarm.ts
|
|
844
|
-
import { Event as Event3, scheduleTask as scheduleTask3, sleep as sleep2, synchronized as synchronized3 } from "@dxos/async";
|
|
845
|
-
import { Context as Context4 } from "@dxos/context";
|
|
846
|
-
import { ErrorStream as ErrorStream2 } from "@dxos/debug";
|
|
847
|
-
import { invariant as invariant4 } from "@dxos/invariant";
|
|
848
|
-
import { PublicKey as PublicKey4 } from "@dxos/keys";
|
|
849
|
-
import { log as log5, logInfo as logInfo2 } from "@dxos/log";
|
|
850
|
-
import { PeerInfoHash } from "@dxos/messaging";
|
|
851
|
-
import { trace as trace2 } from "@dxos/protocols";
|
|
852
|
-
import { ComplexMap as ComplexMap2, isNotNullOrUndefined as isNotNullOrUndefined2 } from "@dxos/util";
|
|
853
|
-
|
|
854
|
-
// packages/core/mesh/network-manager/src/swarm/peer.ts
|
|
855
|
-
import { Event as Event2, scheduleTask as scheduleTask2, synchronized as synchronized2 } from "@dxos/async";
|
|
856
|
-
import { Context as Context3 } from "@dxos/context";
|
|
857
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
858
|
-
import { PublicKey as PublicKey3 } from "@dxos/keys";
|
|
859
|
-
import { log as log4 } from "@dxos/log";
|
|
860
|
-
import { CancelledError as CancelledError2, SystemError } from "@dxos/protocols";
|
|
861
|
-
function _ts_decorate2(decorators, target, key, desc) {
|
|
862
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
863
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
864
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
865
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
866
|
-
}
|
|
867
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/peer.ts";
|
|
868
|
-
var ConnectionDisplacedError = class extends SystemError {
|
|
869
|
-
constructor() {
|
|
870
|
-
super("Connection displaced by remote initiator.");
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
var CONNECTION_COUNTS_STABLE_AFTER = 5e3;
|
|
874
|
-
var Peer = class {
|
|
875
|
-
constructor(remoteInfo, topic, localInfo, _signalMessaging, _protocolProvider, _transportFactory, _connectionLimiter, _callbacks) {
|
|
876
|
-
this.remoteInfo = remoteInfo;
|
|
877
|
-
this.topic = topic;
|
|
878
|
-
this.localInfo = localInfo;
|
|
879
|
-
this._signalMessaging = _signalMessaging;
|
|
880
|
-
this._protocolProvider = _protocolProvider;
|
|
881
|
-
this._transportFactory = _transportFactory;
|
|
882
|
-
this._connectionLimiter = _connectionLimiter;
|
|
883
|
-
this._callbacks = _callbacks;
|
|
884
|
-
this._availableAfter = 0;
|
|
885
|
-
this.availableToConnect = true;
|
|
886
|
-
this._ctx = new Context3(void 0, {
|
|
887
|
-
F: __dxlog_file4,
|
|
888
|
-
L: 80
|
|
889
|
-
});
|
|
890
|
-
this.advertizing = false;
|
|
891
|
-
this.initiating = false;
|
|
892
|
-
this.connectionDisplaced = new Event2();
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Respond to remote offer.
|
|
896
|
-
*/
|
|
897
|
-
async onOffer(message) {
|
|
898
|
-
const remote = message.author;
|
|
899
|
-
if (this.connection && ![
|
|
900
|
-
ConnectionState.CREATED,
|
|
901
|
-
ConnectionState.INITIAL,
|
|
902
|
-
ConnectionState.CONNECTING
|
|
903
|
-
].includes(this.connection.state)) {
|
|
904
|
-
log4.info(`received offer when connection already in ${this.connection.state} state`, void 0, {
|
|
905
|
-
F: __dxlog_file4,
|
|
906
|
-
L: 115,
|
|
907
|
-
S: this,
|
|
908
|
-
C: (f, a) => f(...a)
|
|
909
|
-
});
|
|
910
|
-
return {
|
|
911
|
-
accept: false
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
if (this.connection || this.initiating) {
|
|
915
|
-
if (remote.peerKey < this.localInfo.peerKey) {
|
|
916
|
-
log4("close local connection", {
|
|
917
|
-
localPeer: this.localInfo,
|
|
918
|
-
topic: this.topic,
|
|
919
|
-
remotePeer: this.remoteInfo,
|
|
920
|
-
sessionId: this.connection?.sessionId
|
|
921
|
-
}, {
|
|
922
|
-
F: __dxlog_file4,
|
|
923
|
-
L: 124,
|
|
924
|
-
S: this,
|
|
925
|
-
C: (f, a) => f(...a)
|
|
926
|
-
});
|
|
927
|
-
if (this.connection) {
|
|
928
|
-
await this.closeConnection(new ConnectionDisplacedError());
|
|
929
|
-
}
|
|
930
|
-
} else {
|
|
931
|
-
return {
|
|
932
|
-
accept: false
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
if (await this._callbacks.onOffer(remote)) {
|
|
937
|
-
if (!this.connection) {
|
|
938
|
-
invariant3(message.sessionId, void 0, {
|
|
939
|
-
F: __dxlog_file4,
|
|
940
|
-
L: 144,
|
|
941
|
-
S: this,
|
|
942
|
-
A: [
|
|
943
|
-
"message.sessionId",
|
|
944
|
-
""
|
|
945
|
-
]
|
|
946
|
-
});
|
|
947
|
-
const connection = this._createConnection(false, message.sessionId);
|
|
948
|
-
try {
|
|
949
|
-
await this._connectionLimiter.connecting(message.sessionId);
|
|
950
|
-
connection.initiate();
|
|
951
|
-
await connection.openConnection();
|
|
952
|
-
} catch (err) {
|
|
953
|
-
if (!(err instanceof CancelledError2)) {
|
|
954
|
-
log4.info("connection error", {
|
|
955
|
-
topic: this.topic,
|
|
956
|
-
peerId: this.localInfo,
|
|
957
|
-
remoteId: this.remoteInfo,
|
|
958
|
-
err
|
|
959
|
-
}, {
|
|
960
|
-
F: __dxlog_file4,
|
|
961
|
-
L: 154,
|
|
962
|
-
S: this,
|
|
963
|
-
C: (f, a) => f(...a)
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
await this.closeConnection(err);
|
|
967
|
-
}
|
|
968
|
-
return {
|
|
969
|
-
accept: true
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return {
|
|
974
|
-
accept: false
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Initiate a connection to the remote peer.
|
|
979
|
-
*/
|
|
980
|
-
async initiateConnection() {
|
|
981
|
-
invariant3(!this.initiating, "Initiation in progress.", {
|
|
982
|
-
F: __dxlog_file4,
|
|
983
|
-
L: 171,
|
|
984
|
-
S: this,
|
|
985
|
-
A: [
|
|
986
|
-
"!this.initiating",
|
|
987
|
-
"'Initiation in progress.'"
|
|
988
|
-
]
|
|
989
|
-
});
|
|
990
|
-
invariant3(!this.connection, "Already connected.", {
|
|
991
|
-
F: __dxlog_file4,
|
|
992
|
-
L: 172,
|
|
993
|
-
S: this,
|
|
994
|
-
A: [
|
|
995
|
-
"!this.connection",
|
|
996
|
-
"'Already connected.'"
|
|
997
|
-
]
|
|
998
|
-
});
|
|
999
|
-
const sessionId = PublicKey3.random();
|
|
1000
|
-
log4("initiating...", {
|
|
1001
|
-
local: this.localInfo,
|
|
1002
|
-
topic: this.topic,
|
|
1003
|
-
remote: this.remoteInfo,
|
|
1004
|
-
sessionId
|
|
1005
|
-
}, {
|
|
1006
|
-
F: __dxlog_file4,
|
|
1007
|
-
L: 174,
|
|
1008
|
-
S: this,
|
|
1009
|
-
C: (f, a) => f(...a)
|
|
1010
|
-
});
|
|
1011
|
-
const connection = this._createConnection(true, sessionId);
|
|
1012
|
-
this.initiating = true;
|
|
1013
|
-
let answer;
|
|
1014
|
-
try {
|
|
1015
|
-
await this._connectionLimiter.connecting(sessionId);
|
|
1016
|
-
connection.initiate();
|
|
1017
|
-
answer = await this._signalMessaging.offer({
|
|
1018
|
-
author: this.localInfo,
|
|
1019
|
-
recipient: this.remoteInfo,
|
|
1020
|
-
sessionId,
|
|
1021
|
-
topic: this.topic,
|
|
1022
|
-
data: {
|
|
1023
|
-
offer: {}
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
log4("received", {
|
|
1027
|
-
answer,
|
|
1028
|
-
topic: this.topic,
|
|
1029
|
-
local: this.localInfo,
|
|
1030
|
-
remote: this.remoteInfo
|
|
1031
|
-
}, {
|
|
1032
|
-
F: __dxlog_file4,
|
|
1033
|
-
L: 191,
|
|
1034
|
-
S: this,
|
|
1035
|
-
C: (f, a) => f(...a)
|
|
1036
|
-
});
|
|
1037
|
-
if (connection.state !== ConnectionState.INITIAL) {
|
|
1038
|
-
log4("ignoring response", void 0, {
|
|
1039
|
-
F: __dxlog_file4,
|
|
1040
|
-
L: 193,
|
|
1041
|
-
S: this,
|
|
1042
|
-
C: (f, a) => f(...a)
|
|
1043
|
-
});
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
} catch (err) {
|
|
1047
|
-
log4("initiation error: send offer", {
|
|
1048
|
-
err,
|
|
1049
|
-
topic: this.topic,
|
|
1050
|
-
local: this.localInfo,
|
|
1051
|
-
remote: this.remoteInfo
|
|
1052
|
-
}, {
|
|
1053
|
-
F: __dxlog_file4,
|
|
1054
|
-
L: 197,
|
|
1055
|
-
S: this,
|
|
1056
|
-
C: (f, a) => f(...a)
|
|
1057
|
-
});
|
|
1058
|
-
await connection.abort(err);
|
|
1059
|
-
throw err;
|
|
1060
|
-
} finally {
|
|
1061
|
-
this.initiating = false;
|
|
1062
|
-
}
|
|
1063
|
-
try {
|
|
1064
|
-
if (!answer.accept) {
|
|
1065
|
-
this._callbacks.onRejected();
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
} catch (err) {
|
|
1069
|
-
log4("initiation error: accept answer", {
|
|
1070
|
-
err,
|
|
1071
|
-
topic: this.topic,
|
|
1072
|
-
local: this.localInfo,
|
|
1073
|
-
remote: this.remoteInfo
|
|
1074
|
-
}, {
|
|
1075
|
-
F: __dxlog_file4,
|
|
1076
|
-
L: 210,
|
|
1077
|
-
S: this,
|
|
1078
|
-
C: (f, a) => f(...a)
|
|
1079
|
-
});
|
|
1080
|
-
await connection.abort(err);
|
|
1081
|
-
throw err;
|
|
1082
|
-
} finally {
|
|
1083
|
-
this.initiating = false;
|
|
1084
|
-
}
|
|
1085
|
-
try {
|
|
1086
|
-
log4("opening connection as initiator", void 0, {
|
|
1087
|
-
F: __dxlog_file4,
|
|
1088
|
-
L: 223,
|
|
1089
|
-
S: this,
|
|
1090
|
-
C: (f, a) => f(...a)
|
|
1091
|
-
});
|
|
1092
|
-
await connection.openConnection();
|
|
1093
|
-
this._callbacks.onAccepted();
|
|
1094
|
-
} catch (err) {
|
|
1095
|
-
log4("initiation error: open connection", {
|
|
1096
|
-
err,
|
|
1097
|
-
topic: this.topic,
|
|
1098
|
-
local: this.localInfo,
|
|
1099
|
-
remote: this.remoteInfo
|
|
1100
|
-
}, {
|
|
1101
|
-
F: __dxlog_file4,
|
|
1102
|
-
L: 227,
|
|
1103
|
-
S: this,
|
|
1104
|
-
C: (f, a) => f(...a)
|
|
1105
|
-
});
|
|
1106
|
-
log4.warn("closing connection due to unhandled error on openConnection", {
|
|
1107
|
-
err
|
|
1108
|
-
}, {
|
|
1109
|
-
F: __dxlog_file4,
|
|
1110
|
-
L: 234,
|
|
1111
|
-
S: this,
|
|
1112
|
-
C: (f, a) => f(...a)
|
|
1113
|
-
});
|
|
1114
|
-
await this.closeConnection(err);
|
|
1115
|
-
throw err;
|
|
1116
|
-
} finally {
|
|
1117
|
-
this.initiating = false;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Create new connection.
|
|
1122
|
-
* Either we're initiating a connection or creating one in response to an offer from the other peer.
|
|
1123
|
-
*/
|
|
1124
|
-
_createConnection(initiator, sessionId) {
|
|
1125
|
-
log4("creating connection", {
|
|
1126
|
-
topic: this.topic,
|
|
1127
|
-
peerId: this.localInfo,
|
|
1128
|
-
remoteId: this.remoteInfo,
|
|
1129
|
-
initiator,
|
|
1130
|
-
sessionId
|
|
1131
|
-
}, {
|
|
1132
|
-
F: __dxlog_file4,
|
|
1133
|
-
L: 248,
|
|
1134
|
-
S: this,
|
|
1135
|
-
C: (f, a) => f(...a)
|
|
1136
|
-
});
|
|
1137
|
-
invariant3(!this.connection, "Already connected.", {
|
|
1138
|
-
F: __dxlog_file4,
|
|
1139
|
-
L: 255,
|
|
1140
|
-
S: this,
|
|
1141
|
-
A: [
|
|
1142
|
-
"!this.connection",
|
|
1143
|
-
"'Already connected.'"
|
|
1144
|
-
]
|
|
1145
|
-
});
|
|
1146
|
-
const connection = new Connection(
|
|
1147
|
-
this.topic,
|
|
1148
|
-
this.localInfo,
|
|
1149
|
-
this.remoteInfo,
|
|
1150
|
-
sessionId,
|
|
1151
|
-
initiator,
|
|
1152
|
-
this._signalMessaging,
|
|
1153
|
-
// TODO(dmaretskyi): Init only when connection is established.
|
|
1154
|
-
this._protocolProvider({
|
|
1155
|
-
initiator,
|
|
1156
|
-
localPeerId: PublicKey3.from(this.localInfo.peerKey),
|
|
1157
|
-
remotePeerId: PublicKey3.from(this.remoteInfo.peerKey),
|
|
1158
|
-
topic: this.topic
|
|
1159
|
-
}),
|
|
1160
|
-
this._transportFactory,
|
|
1161
|
-
{
|
|
1162
|
-
onConnected: () => {
|
|
1163
|
-
this.availableToConnect = true;
|
|
1164
|
-
this._lastConnectionTime = Date.now();
|
|
1165
|
-
this._callbacks.onConnected();
|
|
1166
|
-
this._connectionLimiter.doneConnecting(sessionId);
|
|
1167
|
-
log4.trace("dxos.mesh.connection.connected", {
|
|
1168
|
-
topic: this.topic,
|
|
1169
|
-
localPeerId: this.localInfo,
|
|
1170
|
-
remotePeerId: this.remoteInfo,
|
|
1171
|
-
sessionId,
|
|
1172
|
-
initiator
|
|
1173
|
-
}, {
|
|
1174
|
-
F: __dxlog_file4,
|
|
1175
|
-
L: 279,
|
|
1176
|
-
S: this,
|
|
1177
|
-
C: (f, a) => f(...a)
|
|
1178
|
-
});
|
|
1179
|
-
},
|
|
1180
|
-
onClosed: (err) => {
|
|
1181
|
-
log4("connection closed", {
|
|
1182
|
-
topic: this.topic,
|
|
1183
|
-
peerId: this.localInfo,
|
|
1184
|
-
remoteId: this.remoteInfo,
|
|
1185
|
-
initiator
|
|
1186
|
-
}, {
|
|
1187
|
-
F: __dxlog_file4,
|
|
1188
|
-
L: 288,
|
|
1189
|
-
S: this,
|
|
1190
|
-
C: (f, a) => f(...a)
|
|
1191
|
-
});
|
|
1192
|
-
this._connectionLimiter.doneConnecting(sessionId);
|
|
1193
|
-
invariant3(this.connection === connection, "Connection mismatch (race condition).", {
|
|
1194
|
-
F: __dxlog_file4,
|
|
1195
|
-
L: 293,
|
|
1196
|
-
S: this,
|
|
1197
|
-
A: [
|
|
1198
|
-
"this.connection === connection",
|
|
1199
|
-
"'Connection mismatch (race condition).'"
|
|
1200
|
-
]
|
|
1201
|
-
});
|
|
1202
|
-
log4.trace("dxos.mesh.connection.closed", {
|
|
1203
|
-
topic: this.topic,
|
|
1204
|
-
localPeerId: this.localInfo,
|
|
1205
|
-
remotePeerId: this.remoteInfo,
|
|
1206
|
-
sessionId,
|
|
1207
|
-
initiator
|
|
1208
|
-
}, {
|
|
1209
|
-
F: __dxlog_file4,
|
|
1210
|
-
L: 295,
|
|
1211
|
-
S: this,
|
|
1212
|
-
C: (f, a) => f(...a)
|
|
1213
|
-
});
|
|
1214
|
-
if (err instanceof ConnectionDisplacedError) {
|
|
1215
|
-
this.connectionDisplaced.emit(this.connection);
|
|
1216
|
-
} else {
|
|
1217
|
-
if (this._lastConnectionTime && this._lastConnectionTime + CONNECTION_COUNTS_STABLE_AFTER < Date.now()) {
|
|
1218
|
-
this._availableAfter = 0;
|
|
1219
|
-
} else {
|
|
1220
|
-
this.availableToConnect = false;
|
|
1221
|
-
this._availableAfter = increaseInterval(this._availableAfter);
|
|
1222
|
-
}
|
|
1223
|
-
this._callbacks.onDisconnected();
|
|
1224
|
-
scheduleTask2(this._connectionCtx, () => {
|
|
1225
|
-
this.availableToConnect = true;
|
|
1226
|
-
this._callbacks.onPeerAvailable();
|
|
1227
|
-
}, this._availableAfter);
|
|
1228
|
-
}
|
|
1229
|
-
this.connection = void 0;
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
);
|
|
1233
|
-
this._callbacks.onInitiated(connection);
|
|
1234
|
-
void this._connectionCtx?.dispose();
|
|
1235
|
-
this._connectionCtx = this._ctx.derive();
|
|
1236
|
-
connection.errors.handle((err) => {
|
|
1237
|
-
log4.info("connection error, closing", {
|
|
1238
|
-
topic: this.topic,
|
|
1239
|
-
peerId: this.localInfo,
|
|
1240
|
-
remoteId: this.remoteInfo,
|
|
1241
|
-
initiator,
|
|
1242
|
-
err
|
|
1243
|
-
}, {
|
|
1244
|
-
F: __dxlog_file4,
|
|
1245
|
-
L: 335,
|
|
1246
|
-
S: this,
|
|
1247
|
-
C: (f, a) => f(...a)
|
|
1248
|
-
});
|
|
1249
|
-
log4.trace("dxos.mesh.connection.error", {
|
|
1250
|
-
topic: this.topic,
|
|
1251
|
-
localPeerId: this.localInfo,
|
|
1252
|
-
remotePeerId: this.remoteInfo,
|
|
1253
|
-
sessionId,
|
|
1254
|
-
initiator,
|
|
1255
|
-
err
|
|
1256
|
-
}, {
|
|
1257
|
-
F: __dxlog_file4,
|
|
1258
|
-
L: 342,
|
|
1259
|
-
S: this,
|
|
1260
|
-
C: (f, a) => f(...a)
|
|
1261
|
-
});
|
|
1262
|
-
void this.closeConnection(err);
|
|
1263
|
-
});
|
|
1264
|
-
this.connection = connection;
|
|
1265
|
-
return connection;
|
|
1266
|
-
}
|
|
1267
|
-
async closeConnection(err) {
|
|
1268
|
-
if (!this.connection) {
|
|
1269
|
-
return;
|
|
1270
|
-
}
|
|
1271
|
-
const connection = this.connection;
|
|
1272
|
-
log4("closing...", {
|
|
1273
|
-
peerId: this.remoteInfo,
|
|
1274
|
-
sessionId: connection.sessionId
|
|
1275
|
-
}, {
|
|
1276
|
-
F: __dxlog_file4,
|
|
1277
|
-
L: 367,
|
|
1278
|
-
S: this,
|
|
1279
|
-
C: (f, a) => f(...a)
|
|
1280
|
-
});
|
|
1281
|
-
await connection.close(err);
|
|
1282
|
-
log4("closed", {
|
|
1283
|
-
peerId: this.remoteInfo,
|
|
1284
|
-
sessionId: connection.sessionId
|
|
1285
|
-
}, {
|
|
1286
|
-
F: __dxlog_file4,
|
|
1287
|
-
L: 373,
|
|
1288
|
-
S: this,
|
|
1289
|
-
C: (f, a) => f(...a)
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
async onSignal(message) {
|
|
1293
|
-
if (!this.connection) {
|
|
1294
|
-
log4("dropping signal message for non-existent connection", {
|
|
1295
|
-
message
|
|
1296
|
-
}, {
|
|
1297
|
-
F: __dxlog_file4,
|
|
1298
|
-
L: 378,
|
|
1299
|
-
S: this,
|
|
1300
|
-
C: (f, a) => f(...a)
|
|
1301
|
-
});
|
|
1302
|
-
return;
|
|
1303
|
-
}
|
|
1304
|
-
await this.connection.signal(message);
|
|
1305
|
-
}
|
|
1306
|
-
async safeDestroy(reason) {
|
|
1307
|
-
await this._ctx.dispose();
|
|
1308
|
-
log4("Destroying peer", {
|
|
1309
|
-
peerId: this.remoteInfo,
|
|
1310
|
-
topic: this.topic
|
|
1311
|
-
}, {
|
|
1312
|
-
F: __dxlog_file4,
|
|
1313
|
-
L: 388,
|
|
1314
|
-
S: this,
|
|
1315
|
-
C: (f, a) => f(...a)
|
|
1316
|
-
});
|
|
1317
|
-
await this?.connection?.close(reason);
|
|
1318
|
-
}
|
|
1319
|
-
};
|
|
1320
|
-
_ts_decorate2([
|
|
1321
|
-
synchronized2
|
|
1322
|
-
], Peer.prototype, "safeDestroy", null);
|
|
1323
|
-
var increaseInterval = (interval) => {
|
|
1324
|
-
if (interval === 0) {
|
|
1325
|
-
return 50;
|
|
1326
|
-
} else if (interval < 500) {
|
|
1327
|
-
return 500;
|
|
1328
|
-
} else if (interval < 1e3) {
|
|
1329
|
-
return 1e3;
|
|
1330
|
-
} else if (interval < 5e3) {
|
|
1331
|
-
return 5e3;
|
|
1332
|
-
}
|
|
1333
|
-
return 1e4;
|
|
1334
|
-
};
|
|
1335
|
-
|
|
1336
|
-
// packages/core/mesh/network-manager/src/swarm/swarm.ts
|
|
1337
|
-
function _ts_decorate3(decorators, target, key, desc) {
|
|
1338
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1339
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1340
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1341
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1342
|
-
}
|
|
1343
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/swarm.ts";
|
|
1344
|
-
var INITIATION_DELAY = 100;
|
|
1345
|
-
var getClassName = (obj) => Object.getPrototypeOf(obj).constructor.name;
|
|
1346
|
-
var Swarm = class {
|
|
1347
|
-
// TODO(burdon): Swarm => Peer.create/destroy =< Connection.open/close
|
|
1348
|
-
// TODO(burdon): Pass in object.
|
|
1349
|
-
constructor(_topic, _ownPeer, _topology, _protocolProvider, _messenger, _transportFactory, _label, _connectionLimiter, _initiationDelay = INITIATION_DELAY) {
|
|
1350
|
-
this._topic = _topic;
|
|
1351
|
-
this._ownPeer = _ownPeer;
|
|
1352
|
-
this._topology = _topology;
|
|
1353
|
-
this._protocolProvider = _protocolProvider;
|
|
1354
|
-
this._messenger = _messenger;
|
|
1355
|
-
this._transportFactory = _transportFactory;
|
|
1356
|
-
this._label = _label;
|
|
1357
|
-
this._connectionLimiter = _connectionLimiter;
|
|
1358
|
-
this._initiationDelay = _initiationDelay;
|
|
1359
|
-
this._ctx = new Context4(void 0, {
|
|
1360
|
-
F: __dxlog_file5,
|
|
1361
|
-
L: 38
|
|
1362
|
-
});
|
|
1363
|
-
this._listeningHandle = void 0;
|
|
1364
|
-
this._peers = new ComplexMap2(PeerInfoHash);
|
|
1365
|
-
this._instanceId = PublicKey4.random().toHex();
|
|
1366
|
-
this.connectionAdded = new Event3();
|
|
1367
|
-
this.disconnected = new Event3();
|
|
1368
|
-
this.connected = new Event3();
|
|
1369
|
-
this.errors = new ErrorStream2();
|
|
1370
|
-
log5.trace("dxos.mesh.swarm.constructor", trace2.begin({
|
|
1371
|
-
id: this._instanceId,
|
|
1372
|
-
data: {
|
|
1373
|
-
topic: this._topic.toHex(),
|
|
1374
|
-
peer: this._ownPeer
|
|
1375
|
-
}
|
|
1376
|
-
}), {
|
|
1377
|
-
F: __dxlog_file5,
|
|
1378
|
-
L: 88,
|
|
1379
|
-
S: this,
|
|
1380
|
-
C: (f, a) => f(...a)
|
|
1381
|
-
});
|
|
1382
|
-
log5("creating swarm", {
|
|
1383
|
-
peerId: _ownPeer
|
|
1384
|
-
}, {
|
|
1385
|
-
F: __dxlog_file5,
|
|
1386
|
-
L: 92,
|
|
1387
|
-
S: this,
|
|
1388
|
-
C: (f, a) => f(...a)
|
|
1389
|
-
});
|
|
1390
|
-
_topology.init(this._getSwarmController());
|
|
1391
|
-
this._swarmMessenger = new SwarmMessenger({
|
|
1392
|
-
sendMessage: async (msg) => await this._messenger.sendMessage(msg),
|
|
1393
|
-
onSignal: async (msg) => await this.onSignal(msg),
|
|
1394
|
-
onOffer: async (msg) => await this.onOffer(msg),
|
|
1395
|
-
topic: this._topic
|
|
1396
|
-
});
|
|
1397
|
-
log5.trace("dxos.mesh.swarm.constructor", trace2.end({
|
|
1398
|
-
id: this._instanceId
|
|
1399
|
-
}), {
|
|
1400
|
-
F: __dxlog_file5,
|
|
1401
|
-
L: 101,
|
|
1402
|
-
S: this,
|
|
1403
|
-
C: (f, a) => f(...a)
|
|
1404
|
-
});
|
|
1405
|
-
}
|
|
1406
|
-
get connections() {
|
|
1407
|
-
return Array.from(this._peers.values()).map((peer) => peer.connection).filter(isNotNullOrUndefined2);
|
|
1408
|
-
}
|
|
1409
|
-
get ownPeerId() {
|
|
1410
|
-
return PublicKey4.from(this._ownPeer.peerKey);
|
|
1411
|
-
}
|
|
1412
|
-
get ownPeer() {
|
|
1413
|
-
return this._ownPeer;
|
|
1414
|
-
}
|
|
1415
|
-
/**
|
|
1416
|
-
* Custom label assigned to this swarm. Used in devtools to display human-readable names for swarms.
|
|
1417
|
-
*/
|
|
1418
|
-
get label() {
|
|
1419
|
-
return this._label;
|
|
1420
|
-
}
|
|
1421
|
-
get topic() {
|
|
1422
|
-
return this._topic;
|
|
1423
|
-
}
|
|
1424
|
-
async open() {
|
|
1425
|
-
invariant4(!this._listeningHandle, void 0, {
|
|
1426
|
-
F: __dxlog_file5,
|
|
1427
|
-
L: 132,
|
|
1428
|
-
S: this,
|
|
1429
|
-
A: [
|
|
1430
|
-
"!this._listeningHandle",
|
|
1431
|
-
""
|
|
1432
|
-
]
|
|
1433
|
-
});
|
|
1434
|
-
this._listeningHandle = await this._messenger.listen({
|
|
1435
|
-
peer: this._ownPeer,
|
|
1436
|
-
payloadType: "dxos.mesh.swarm.SwarmMessage",
|
|
1437
|
-
onMessage: async (message) => {
|
|
1438
|
-
await this._swarmMessenger.receiveMessage(message).catch((err) => log5.info("Error while receiving message", {
|
|
1439
|
-
err
|
|
1440
|
-
}, {
|
|
1441
|
-
F: __dxlog_file5,
|
|
1442
|
-
L: 140,
|
|
1443
|
-
S: this,
|
|
1444
|
-
C: (f, a) => f(...a)
|
|
1445
|
-
}));
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
}
|
|
1449
|
-
async destroy() {
|
|
1450
|
-
log5("destroying...", void 0, {
|
|
1451
|
-
F: __dxlog_file5,
|
|
1452
|
-
L: 146,
|
|
1453
|
-
S: this,
|
|
1454
|
-
C: (f, a) => f(...a)
|
|
1455
|
-
});
|
|
1456
|
-
await this._listeningHandle?.unsubscribe();
|
|
1457
|
-
this._listeningHandle = void 0;
|
|
1458
|
-
await this._ctx.dispose();
|
|
1459
|
-
await this._topology.destroy();
|
|
1460
|
-
await Promise.all(Array.from(this._peers.keys()).map((key) => this._destroyPeer(key, "swarm destroyed")));
|
|
1461
|
-
log5("destroyed", void 0, {
|
|
1462
|
-
F: __dxlog_file5,
|
|
1463
|
-
L: 153,
|
|
1464
|
-
S: this,
|
|
1465
|
-
C: (f, a) => f(...a)
|
|
1466
|
-
});
|
|
1467
|
-
}
|
|
1468
|
-
async setTopology(topology) {
|
|
1469
|
-
invariant4(!this._ctx.disposed, "Swarm is offline", {
|
|
1470
|
-
F: __dxlog_file5,
|
|
1471
|
-
L: 157,
|
|
1472
|
-
S: this,
|
|
1473
|
-
A: [
|
|
1474
|
-
"!this._ctx.disposed",
|
|
1475
|
-
"'Swarm is offline'"
|
|
1476
|
-
]
|
|
1477
|
-
});
|
|
1478
|
-
if (topology === this._topology) {
|
|
1479
|
-
return;
|
|
1480
|
-
}
|
|
1481
|
-
log5("setting topology", {
|
|
1482
|
-
previous: getClassName(this._topology),
|
|
1483
|
-
topology: getClassName(topology)
|
|
1484
|
-
}, {
|
|
1485
|
-
F: __dxlog_file5,
|
|
1486
|
-
L: 161,
|
|
1487
|
-
S: this,
|
|
1488
|
-
C: (f, a) => f(...a)
|
|
1489
|
-
});
|
|
1490
|
-
await this._topology.destroy();
|
|
1491
|
-
this._topology = topology;
|
|
1492
|
-
this._topology.init(this._getSwarmController());
|
|
1493
|
-
this._topology.update();
|
|
1494
|
-
}
|
|
1495
|
-
onSwarmEvent(swarmEvent) {
|
|
1496
|
-
log5("swarm event", {
|
|
1497
|
-
swarmEvent
|
|
1498
|
-
}, {
|
|
1499
|
-
F: __dxlog_file5,
|
|
1500
|
-
L: 174,
|
|
1501
|
-
S: this,
|
|
1502
|
-
C: (f, a) => f(...a)
|
|
1503
|
-
});
|
|
1504
|
-
if (this._ctx.disposed) {
|
|
1505
|
-
log5("swarm event ignored for disposed swarm", void 0, {
|
|
1506
|
-
F: __dxlog_file5,
|
|
1507
|
-
L: 177,
|
|
1508
|
-
S: this,
|
|
1509
|
-
C: (f, a) => f(...a)
|
|
1510
|
-
});
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
if (swarmEvent.peerAvailable) {
|
|
1514
|
-
const peerId = swarmEvent.peerAvailable.peer.peerKey;
|
|
1515
|
-
if (peerId !== this._ownPeer.peerKey) {
|
|
1516
|
-
log5("new peer", {
|
|
1517
|
-
peerId
|
|
1518
|
-
}, {
|
|
1519
|
-
F: __dxlog_file5,
|
|
1520
|
-
L: 184,
|
|
1521
|
-
S: this,
|
|
1522
|
-
C: (f, a) => f(...a)
|
|
1523
|
-
});
|
|
1524
|
-
const peer = this._getOrCreatePeer(swarmEvent.peerAvailable.peer);
|
|
1525
|
-
peer.advertizing = true;
|
|
1526
|
-
}
|
|
1527
|
-
} else if (swarmEvent.peerLeft) {
|
|
1528
|
-
const peer = this._peers.get(swarmEvent.peerLeft.peer);
|
|
1529
|
-
if (peer) {
|
|
1530
|
-
peer.advertizing = false;
|
|
1531
|
-
if (peer.connection?.state !== ConnectionState.CONNECTED) {
|
|
1532
|
-
void this._destroyPeer(swarmEvent.peerLeft.peer, "peer left").catch((err) => log5.catch(err, void 0, {
|
|
1533
|
-
F: __dxlog_file5,
|
|
1534
|
-
L: 194,
|
|
1535
|
-
S: this,
|
|
1536
|
-
C: (f, a) => f(...a)
|
|
1537
|
-
}));
|
|
1538
|
-
}
|
|
1539
|
-
} else {
|
|
1540
|
-
log5("received peerLeft but no peer found", {
|
|
1541
|
-
peer: swarmEvent.peerLeft.peer.peerKey
|
|
1542
|
-
}, {
|
|
1543
|
-
F: __dxlog_file5,
|
|
1544
|
-
L: 197,
|
|
1545
|
-
S: this,
|
|
1546
|
-
C: (f, a) => f(...a)
|
|
1547
|
-
});
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
this._topology.update();
|
|
1551
|
-
}
|
|
1552
|
-
async onOffer(message) {
|
|
1553
|
-
log5("offer", {
|
|
1554
|
-
message
|
|
1555
|
-
}, {
|
|
1556
|
-
F: __dxlog_file5,
|
|
1557
|
-
L: 206,
|
|
1558
|
-
S: this,
|
|
1559
|
-
C: (f, a) => f(...a)
|
|
1560
|
-
});
|
|
1561
|
-
if (this._ctx.disposed) {
|
|
1562
|
-
log5("ignored for disposed swarm", void 0, {
|
|
1563
|
-
F: __dxlog_file5,
|
|
1564
|
-
L: 208,
|
|
1565
|
-
S: this,
|
|
1566
|
-
C: (f, a) => f(...a)
|
|
1567
|
-
});
|
|
1568
|
-
return {
|
|
1569
|
-
accept: false
|
|
1570
|
-
};
|
|
1571
|
-
}
|
|
1572
|
-
invariant4(message.author, void 0, {
|
|
1573
|
-
F: __dxlog_file5,
|
|
1574
|
-
L: 213,
|
|
1575
|
-
S: this,
|
|
1576
|
-
A: [
|
|
1577
|
-
"message.author",
|
|
1578
|
-
""
|
|
1579
|
-
]
|
|
1580
|
-
});
|
|
1581
|
-
if (message.recipient.peerKey !== this._ownPeer.peerKey) {
|
|
1582
|
-
log5("rejecting offer with incorrect peerId", {
|
|
1583
|
-
message
|
|
1584
|
-
}, {
|
|
1585
|
-
F: __dxlog_file5,
|
|
1586
|
-
L: 215,
|
|
1587
|
-
S: this,
|
|
1588
|
-
C: (f, a) => f(...a)
|
|
1589
|
-
});
|
|
1590
|
-
return {
|
|
1591
|
-
accept: false
|
|
1592
|
-
};
|
|
1593
|
-
}
|
|
1594
|
-
if (!message.topic?.equals(this._topic)) {
|
|
1595
|
-
log5("rejecting offer with incorrect topic", {
|
|
1596
|
-
message
|
|
1597
|
-
}, {
|
|
1598
|
-
F: __dxlog_file5,
|
|
1599
|
-
L: 219,
|
|
1600
|
-
S: this,
|
|
1601
|
-
C: (f, a) => f(...a)
|
|
1602
|
-
});
|
|
1603
|
-
return {
|
|
1604
|
-
accept: false
|
|
1605
|
-
};
|
|
1606
|
-
}
|
|
1607
|
-
const peer = this._getOrCreatePeer(message.author);
|
|
1608
|
-
const answer = await peer.onOffer(message);
|
|
1609
|
-
this._topology.update();
|
|
1610
|
-
return answer;
|
|
1611
|
-
}
|
|
1612
|
-
async onSignal(message) {
|
|
1613
|
-
log5("signal", {
|
|
1614
|
-
message
|
|
1615
|
-
}, {
|
|
1616
|
-
F: __dxlog_file5,
|
|
1617
|
-
L: 230,
|
|
1618
|
-
S: this,
|
|
1619
|
-
C: (f, a) => f(...a)
|
|
1620
|
-
});
|
|
1621
|
-
if (this._ctx.disposed) {
|
|
1622
|
-
log5.info("ignored for offline swarm", void 0, {
|
|
1623
|
-
F: __dxlog_file5,
|
|
1624
|
-
L: 232,
|
|
1625
|
-
S: this,
|
|
1626
|
-
C: (f, a) => f(...a)
|
|
1627
|
-
});
|
|
1628
|
-
return;
|
|
1629
|
-
}
|
|
1630
|
-
invariant4(message.recipient.peerKey === this._ownPeer.peerKey, `Invalid signal peer id expected=${this.ownPeerId}, actual=${message.recipient}`, {
|
|
1631
|
-
F: __dxlog_file5,
|
|
1632
|
-
L: 235,
|
|
1633
|
-
S: this,
|
|
1634
|
-
A: [
|
|
1635
|
-
"message.recipient.peerKey === this._ownPeer.peerKey",
|
|
1636
|
-
"`Invalid signal peer id expected=${this.ownPeerId}, actual=${message.recipient}`"
|
|
1637
|
-
]
|
|
1638
|
-
});
|
|
1639
|
-
invariant4(message.topic?.equals(this._topic), void 0, {
|
|
1640
|
-
F: __dxlog_file5,
|
|
1641
|
-
L: 239,
|
|
1642
|
-
S: this,
|
|
1643
|
-
A: [
|
|
1644
|
-
"message.topic?.equals(this._topic)",
|
|
1645
|
-
""
|
|
1646
|
-
]
|
|
1647
|
-
});
|
|
1648
|
-
invariant4(message.author, void 0, {
|
|
1649
|
-
F: __dxlog_file5,
|
|
1650
|
-
L: 240,
|
|
1651
|
-
S: this,
|
|
1652
|
-
A: [
|
|
1653
|
-
"message.author",
|
|
1654
|
-
""
|
|
1655
|
-
]
|
|
1656
|
-
});
|
|
1657
|
-
const peer = this._getOrCreatePeer(message.author);
|
|
1658
|
-
await peer.onSignal(message);
|
|
1659
|
-
}
|
|
1660
|
-
// For debug purposes
|
|
1661
|
-
async goOffline() {
|
|
1662
|
-
await this._ctx.dispose();
|
|
1663
|
-
await Promise.all([
|
|
1664
|
-
...this._peers.keys()
|
|
1665
|
-
].map((peerId) => this._destroyPeer(peerId, "goOffline")));
|
|
1666
|
-
}
|
|
1667
|
-
// For debug purposes
|
|
1668
|
-
async goOnline() {
|
|
1669
|
-
this._ctx = new Context4(void 0, {
|
|
1670
|
-
F: __dxlog_file5,
|
|
1671
|
-
L: 256
|
|
1672
|
-
});
|
|
1673
|
-
}
|
|
1674
|
-
_getOrCreatePeer(peerInfo) {
|
|
1675
|
-
invariant4(peerInfo.peerKey, "PeerInfo.peerKey is required", {
|
|
1676
|
-
F: __dxlog_file5,
|
|
1677
|
-
L: 260,
|
|
1678
|
-
S: this,
|
|
1679
|
-
A: [
|
|
1680
|
-
"peerInfo.peerKey",
|
|
1681
|
-
"'PeerInfo.peerKey is required'"
|
|
1682
|
-
]
|
|
1683
|
-
});
|
|
1684
|
-
let peer = this._peers.get(peerInfo);
|
|
1685
|
-
if (!peer) {
|
|
1686
|
-
peer = new Peer(peerInfo, this._topic, this._ownPeer, this._swarmMessenger, this._protocolProvider, this._transportFactory, this._connectionLimiter, {
|
|
1687
|
-
onInitiated: (connection) => {
|
|
1688
|
-
this.connectionAdded.emit(connection);
|
|
1689
|
-
},
|
|
1690
|
-
onConnected: () => {
|
|
1691
|
-
this.connected.emit(peerInfo);
|
|
1692
|
-
},
|
|
1693
|
-
onDisconnected: async () => {
|
|
1694
|
-
if (this._isUnregistered(peer)) {
|
|
1695
|
-
return;
|
|
1696
|
-
}
|
|
1697
|
-
if (!peer.advertizing) {
|
|
1698
|
-
await this._destroyPeer(peerInfo, "peer disconnected");
|
|
1699
|
-
}
|
|
1700
|
-
this.disconnected.emit(peerInfo);
|
|
1701
|
-
this._topology.update();
|
|
1702
|
-
},
|
|
1703
|
-
onRejected: () => {
|
|
1704
|
-
if (!this._isUnregistered(peer)) {
|
|
1705
|
-
log5("peer rejected connection", {
|
|
1706
|
-
peerInfo
|
|
1707
|
-
}, {
|
|
1708
|
-
F: __dxlog_file5,
|
|
1709
|
-
L: 293,
|
|
1710
|
-
S: this,
|
|
1711
|
-
C: (f, a) => f(...a)
|
|
1712
|
-
});
|
|
1713
|
-
void this._destroyPeer(peerInfo, "peer rejected connection");
|
|
1714
|
-
}
|
|
1715
|
-
},
|
|
1716
|
-
onAccepted: () => {
|
|
1717
|
-
this._topology.update();
|
|
1718
|
-
},
|
|
1719
|
-
onOffer: (remoteId) => {
|
|
1720
|
-
return this._topology.onOffer(PublicKey4.from(remoteId.peerKey));
|
|
1721
|
-
},
|
|
1722
|
-
onPeerAvailable: () => {
|
|
1723
|
-
this._topology.update();
|
|
1724
|
-
}
|
|
1725
|
-
});
|
|
1726
|
-
this._peers.set(peerInfo, peer);
|
|
1727
|
-
}
|
|
1728
|
-
return peer;
|
|
1729
|
-
}
|
|
1730
|
-
async _destroyPeer(peerInfo, reason) {
|
|
1731
|
-
const peer = this._peers.get(peerInfo);
|
|
1732
|
-
invariant4(peer, void 0, {
|
|
1733
|
-
F: __dxlog_file5,
|
|
1734
|
-
L: 316,
|
|
1735
|
-
S: this,
|
|
1736
|
-
A: [
|
|
1737
|
-
"peer",
|
|
1738
|
-
""
|
|
1739
|
-
]
|
|
1740
|
-
});
|
|
1741
|
-
this._peers.delete(peerInfo);
|
|
1742
|
-
await peer.safeDestroy(new Error(reason));
|
|
1743
|
-
}
|
|
1744
|
-
_getSwarmController() {
|
|
1745
|
-
return {
|
|
1746
|
-
getState: () => ({
|
|
1747
|
-
ownPeerId: PublicKey4.from(this._ownPeer.peerKey),
|
|
1748
|
-
connected: Array.from(this._peers.entries()).filter(([_, peer]) => peer.connection).map(([info]) => PublicKey4.from(info.peerKey)),
|
|
1749
|
-
candidates: Array.from(this._peers.entries()).filter(([_, peer]) => !peer.connection && peer.advertizing && peer.availableToConnect).map(([info]) => PublicKey4.from(info.peerKey)),
|
|
1750
|
-
allPeers: Array.from(this._peers.keys()).map((info) => PublicKey4.from(info.peerKey))
|
|
1751
|
-
}),
|
|
1752
|
-
connect: (peer) => {
|
|
1753
|
-
if (this._ctx.disposed) {
|
|
1754
|
-
return;
|
|
1755
|
-
}
|
|
1756
|
-
scheduleTask3(this._ctx, async () => {
|
|
1757
|
-
try {
|
|
1758
|
-
await this._initiateConnection({
|
|
1759
|
-
peerKey: peer.toHex()
|
|
1760
|
-
});
|
|
1761
|
-
} catch (err) {
|
|
1762
|
-
log5("initiation error", err, {
|
|
1763
|
-
F: __dxlog_file5,
|
|
1764
|
-
L: 343,
|
|
1765
|
-
S: this,
|
|
1766
|
-
C: (f, a) => f(...a)
|
|
1767
|
-
});
|
|
1768
|
-
}
|
|
1769
|
-
});
|
|
1770
|
-
},
|
|
1771
|
-
disconnect: async (peer) => {
|
|
1772
|
-
if (this._ctx.disposed) {
|
|
1773
|
-
return;
|
|
1774
|
-
}
|
|
1775
|
-
scheduleTask3(this._ctx, async () => {
|
|
1776
|
-
await this._closeConnection({
|
|
1777
|
-
peerKey: peer.toHex()
|
|
1778
|
-
});
|
|
1779
|
-
this._topology.update();
|
|
1780
|
-
});
|
|
1781
|
-
}
|
|
1782
|
-
};
|
|
1783
|
-
}
|
|
1784
|
-
/**
|
|
1785
|
-
* Creates a connection then sends message over signal network.
|
|
1786
|
-
*/
|
|
1787
|
-
async _initiateConnection(remotePeer) {
|
|
1788
|
-
const ctx = this._ctx;
|
|
1789
|
-
const peer = this._getOrCreatePeer(remotePeer);
|
|
1790
|
-
if (remotePeer.peerKey < this._ownPeer.peerKey) {
|
|
1791
|
-
log5("initiation delay", {
|
|
1792
|
-
remotePeer
|
|
1793
|
-
}, {
|
|
1794
|
-
F: __dxlog_file5,
|
|
1795
|
-
L: 371,
|
|
1796
|
-
S: this,
|
|
1797
|
-
C: (f, a) => f(...a)
|
|
1798
|
-
});
|
|
1799
|
-
await sleep2(this._initiationDelay);
|
|
1800
|
-
}
|
|
1801
|
-
if (ctx.disposed) {
|
|
1802
|
-
return;
|
|
1803
|
-
}
|
|
1804
|
-
if (this._isUnregistered(peer)) {
|
|
1805
|
-
throw new Error("Peer left during initiation delay");
|
|
1806
|
-
}
|
|
1807
|
-
if (peer.connection) {
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
log5("initiating connection...", {
|
|
1811
|
-
remotePeer
|
|
1812
|
-
}, {
|
|
1813
|
-
F: __dxlog_file5,
|
|
1814
|
-
L: 387,
|
|
1815
|
-
S: this,
|
|
1816
|
-
C: (f, a) => f(...a)
|
|
1817
|
-
});
|
|
1818
|
-
await peer.initiateConnection();
|
|
1819
|
-
this._topology.update();
|
|
1820
|
-
log5("initiated", {
|
|
1821
|
-
remotePeer
|
|
1822
|
-
}, {
|
|
1823
|
-
F: __dxlog_file5,
|
|
1824
|
-
L: 390,
|
|
1825
|
-
S: this,
|
|
1826
|
-
C: (f, a) => f(...a)
|
|
1827
|
-
});
|
|
1828
|
-
}
|
|
1829
|
-
async _closeConnection(peerInfo) {
|
|
1830
|
-
const peer = this._peers.get(peerInfo);
|
|
1831
|
-
if (!peer) {
|
|
1832
|
-
return;
|
|
1833
|
-
}
|
|
1834
|
-
await peer.closeConnection();
|
|
1835
|
-
}
|
|
1836
|
-
_isUnregistered(peer) {
|
|
1837
|
-
return !peer || this._peers.get(peer.remoteInfo) !== peer;
|
|
1838
|
-
}
|
|
1839
|
-
};
|
|
1840
|
-
_ts_decorate3([
|
|
1841
|
-
logInfo2
|
|
1842
|
-
], Swarm.prototype, "_instanceId", void 0);
|
|
1843
|
-
_ts_decorate3([
|
|
1844
|
-
logInfo2
|
|
1845
|
-
], Swarm.prototype, "ownPeer", null);
|
|
1846
|
-
_ts_decorate3([
|
|
1847
|
-
logInfo2
|
|
1848
|
-
], Swarm.prototype, "topic", null);
|
|
1849
|
-
_ts_decorate3([
|
|
1850
|
-
synchronized3
|
|
1851
|
-
], Swarm.prototype, "onSwarmEvent", null);
|
|
1852
|
-
_ts_decorate3([
|
|
1853
|
-
synchronized3
|
|
1854
|
-
], Swarm.prototype, "onOffer", null);
|
|
1855
|
-
_ts_decorate3([
|
|
1856
|
-
synchronized3
|
|
1857
|
-
], Swarm.prototype, "goOffline", null);
|
|
1858
|
-
_ts_decorate3([
|
|
1859
|
-
synchronized3
|
|
1860
|
-
], Swarm.prototype, "goOnline", null);
|
|
1861
|
-
|
|
1862
|
-
// packages/core/mesh/network-manager/src/swarm/swarm-mapper.ts
|
|
1863
|
-
import { Event as Event4, EventSubscriptions } from "@dxos/async";
|
|
1864
|
-
import { PublicKey as PublicKey5 } from "@dxos/keys";
|
|
1865
|
-
import { log as log6 } from "@dxos/log";
|
|
1866
|
-
import { PeerInfoHash as PeerInfoHash2 } from "@dxos/messaging";
|
|
1867
|
-
import { ComplexMap as ComplexMap3 } from "@dxos/util";
|
|
1868
|
-
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/swarm-mapper.ts";
|
|
1869
|
-
var SwarmMapper = class {
|
|
1870
|
-
get peers() {
|
|
1871
|
-
return Array.from(this._peers.values());
|
|
1872
|
-
}
|
|
1873
|
-
constructor(_swarm) {
|
|
1874
|
-
this._swarm = _swarm;
|
|
1875
|
-
this._subscriptions = new EventSubscriptions();
|
|
1876
|
-
this._connectionSubscriptions = new ComplexMap3(PeerInfoHash2);
|
|
1877
|
-
this._peers = new ComplexMap3(PeerInfoHash2);
|
|
1878
|
-
this.mapUpdated = new Event4();
|
|
1879
|
-
this._subscriptions.add(_swarm.connectionAdded.on((connection) => {
|
|
1880
|
-
this._update();
|
|
1881
|
-
this._connectionSubscriptions.set(connection.remoteInfo, connection.stateChanged.on(() => {
|
|
1882
|
-
this._update();
|
|
1883
|
-
}));
|
|
1884
|
-
}));
|
|
1885
|
-
this._subscriptions.add(_swarm.disconnected.on((peerId) => {
|
|
1886
|
-
this._connectionSubscriptions.get(peerId)?.();
|
|
1887
|
-
this._connectionSubscriptions.delete(peerId);
|
|
1888
|
-
this._update();
|
|
1889
|
-
}));
|
|
1890
|
-
this._update();
|
|
1891
|
-
}
|
|
1892
|
-
_update() {
|
|
1893
|
-
log6("updating swarm", void 0, {
|
|
1894
|
-
F: __dxlog_file6,
|
|
1895
|
-
L: 73,
|
|
1896
|
-
S: this,
|
|
1897
|
-
C: (f, a) => f(...a)
|
|
1898
|
-
});
|
|
1899
|
-
this._peers.clear();
|
|
1900
|
-
this._peers.set(this._swarm.ownPeer, {
|
|
1901
|
-
id: this._swarm.ownPeerId,
|
|
1902
|
-
state: "ME",
|
|
1903
|
-
connections: []
|
|
1904
|
-
});
|
|
1905
|
-
for (const connection of this._swarm.connections) {
|
|
1906
|
-
this._peers.set(connection.remoteInfo, {
|
|
1907
|
-
id: PublicKey5.from(connection.remoteInfo.peerKey),
|
|
1908
|
-
state: connection.state,
|
|
1909
|
-
connections: [
|
|
1910
|
-
this._swarm.ownPeerId
|
|
1911
|
-
]
|
|
1912
|
-
});
|
|
1913
|
-
}
|
|
1914
|
-
log6("graph changed", {
|
|
1915
|
-
directConnections: this._swarm.connections.length,
|
|
1916
|
-
totalPeersInSwarm: this._peers.size
|
|
1917
|
-
}, {
|
|
1918
|
-
F: __dxlog_file6,
|
|
1919
|
-
L: 114,
|
|
1920
|
-
S: this,
|
|
1921
|
-
C: (f, a) => f(...a)
|
|
1922
|
-
});
|
|
1923
|
-
this.mapUpdated.emit(Array.from(this._peers.values()));
|
|
1924
|
-
}
|
|
1925
|
-
// TODO(burdon): Async open/close.
|
|
1926
|
-
destroy() {
|
|
1927
|
-
Array.from(this._connectionSubscriptions.values()).forEach((cb) => cb());
|
|
1928
|
-
this._subscriptions.clear();
|
|
1929
|
-
}
|
|
1930
|
-
};
|
|
1931
|
-
|
|
1932
|
-
// packages/core/mesh/network-manager/src/swarm/connection-limiter.ts
|
|
1933
|
-
import { DeferredTask as DeferredTask2 } from "@dxos/async";
|
|
1934
|
-
import { Context as Context5 } from "@dxos/context";
|
|
1935
|
-
import { invariant as invariant5 } from "@dxos/invariant";
|
|
1936
|
-
import { PublicKey as PublicKey6 } from "@dxos/keys";
|
|
1937
|
-
import { log as log7 } from "@dxos/log";
|
|
1938
|
-
import { CancelledError as CancelledError3 } from "@dxos/protocols";
|
|
1939
|
-
import { ComplexMap as ComplexMap4 } from "@dxos/util";
|
|
1940
|
-
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/connection-limiter.ts";
|
|
1941
|
-
var MAX_CONCURRENT_INITIATING_CONNECTIONS = 50;
|
|
1942
|
-
var ConnectionLimiter = class {
|
|
1943
|
-
constructor({ maxConcurrentInitConnections = MAX_CONCURRENT_INITIATING_CONNECTIONS } = {}) {
|
|
1944
|
-
this._ctx = new Context5(void 0, {
|
|
1945
|
-
F: __dxlog_file7,
|
|
1946
|
-
L: 23
|
|
1947
|
-
});
|
|
1948
|
-
/**
|
|
1949
|
-
* Queue of promises to resolve when initiating connections amount is below the limit.
|
|
1950
|
-
*/
|
|
1951
|
-
this._waitingPromises = new ComplexMap4(PublicKey6.hash);
|
|
1952
|
-
this.resolveWaitingPromises = new DeferredTask2(this._ctx, async () => {
|
|
1953
|
-
Array.from(this._waitingPromises.values()).slice(0, this._maxConcurrentInitConnections).forEach(({ resolve }) => {
|
|
1954
|
-
resolve();
|
|
1955
|
-
});
|
|
1956
|
-
});
|
|
1957
|
-
this._maxConcurrentInitConnections = maxConcurrentInitConnections;
|
|
1958
|
-
}
|
|
1959
|
-
/**
|
|
1960
|
-
* @returns Promise that resolves in queue when connections amount with 'CONNECTING' state is below the limit.
|
|
1961
|
-
*/
|
|
1962
|
-
async connecting(sessionId) {
|
|
1963
|
-
invariant5(!this._waitingPromises.has(sessionId), "Peer is already waiting for connection", {
|
|
1964
|
-
F: __dxlog_file7,
|
|
1965
|
-
L: 48,
|
|
1966
|
-
S: this,
|
|
1967
|
-
A: [
|
|
1968
|
-
"!this._waitingPromises.has(sessionId)",
|
|
1969
|
-
"'Peer is already waiting for connection'"
|
|
1970
|
-
]
|
|
1971
|
-
});
|
|
1972
|
-
log7("waiting", {
|
|
1973
|
-
sessionId
|
|
1974
|
-
}, {
|
|
1975
|
-
F: __dxlog_file7,
|
|
1976
|
-
L: 49,
|
|
1977
|
-
S: this,
|
|
1978
|
-
C: (f, a) => f(...a)
|
|
1979
|
-
});
|
|
1980
|
-
await new Promise((resolve, reject) => {
|
|
1981
|
-
this._waitingPromises.set(sessionId, {
|
|
1982
|
-
resolve,
|
|
1983
|
-
reject
|
|
1984
|
-
});
|
|
1985
|
-
this.resolveWaitingPromises.schedule();
|
|
1986
|
-
});
|
|
1987
|
-
log7("allow", {
|
|
1988
|
-
sessionId
|
|
1989
|
-
}, {
|
|
1990
|
-
F: __dxlog_file7,
|
|
1991
|
-
L: 57,
|
|
1992
|
-
S: this,
|
|
1993
|
-
C: (f, a) => f(...a)
|
|
1994
|
-
});
|
|
1995
|
-
}
|
|
1996
|
-
/**
|
|
1997
|
-
* Rejects promise returned by `connecting` method.
|
|
1998
|
-
*/
|
|
1999
|
-
doneConnecting(sessionId) {
|
|
2000
|
-
log7("done", {
|
|
2001
|
-
sessionId
|
|
2002
|
-
}, {
|
|
2003
|
-
F: __dxlog_file7,
|
|
2004
|
-
L: 64,
|
|
2005
|
-
S: this,
|
|
2006
|
-
C: (f, a) => f(...a)
|
|
2007
|
-
});
|
|
2008
|
-
if (!this._waitingPromises.has(sessionId)) {
|
|
2009
|
-
return;
|
|
2010
|
-
}
|
|
2011
|
-
this._waitingPromises.get(sessionId).reject(new CancelledError3());
|
|
2012
|
-
this._waitingPromises.delete(sessionId);
|
|
2013
|
-
this.resolveWaitingPromises.schedule();
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2016
|
-
|
|
2017
|
-
// packages/core/mesh/network-manager/src/connection-log.ts
|
|
2018
|
-
import { Event as Event5 } from "@dxos/async";
|
|
2019
|
-
import { raise } from "@dxos/debug";
|
|
2020
|
-
import { PublicKey as PublicKey7 } from "@dxos/keys";
|
|
2021
|
-
import { ComplexMap as ComplexMap5 } from "@dxos/util";
|
|
2022
|
-
var CONNECTION_GC_THRESHOLD = 1e3 * 60 * 15;
|
|
2023
|
-
var EventType;
|
|
2024
|
-
(function(EventType2) {
|
|
2025
|
-
EventType2["CONNECTION_STATE_CHANGED"] = "CONNECTION_STATE_CHANGED";
|
|
2026
|
-
EventType2["PROTOCOL_ERROR"] = "PROTOCOL_ERROR";
|
|
2027
|
-
EventType2["PROTOCOL_EXTENSIONS_INITIALIZED"] = "PROTOCOL_EXTENSIONS_INITIALIZED";
|
|
2028
|
-
EventType2["PROTOCOL_EXTENSIONS_HANDSHAKE"] = "PROTOCOL_EXTENSIONS_HANDSHAKE";
|
|
2029
|
-
EventType2["PROTOCOL_HANDSHAKE"] = "PROTOCOL_HANDSHAKE";
|
|
2030
|
-
})(EventType || (EventType = {}));
|
|
2031
|
-
var ConnectionLog = class {
|
|
2032
|
-
constructor() {
|
|
2033
|
-
/**
|
|
2034
|
-
* SwarmId => info
|
|
2035
|
-
*/
|
|
2036
|
-
this._swarms = new ComplexMap5(PublicKey7.hash);
|
|
2037
|
-
this.update = new Event5();
|
|
2038
|
-
}
|
|
2039
|
-
getSwarmInfo(swarmId) {
|
|
2040
|
-
return this._swarms.get(swarmId) ?? raise(new Error(`Swarm not found: ${swarmId}`));
|
|
2041
|
-
}
|
|
2042
|
-
get swarms() {
|
|
2043
|
-
return Array.from(this._swarms.values());
|
|
2044
|
-
}
|
|
2045
|
-
joinedSwarm(swarm) {
|
|
2046
|
-
const info = {
|
|
2047
|
-
id: PublicKey7.from(swarm._instanceId),
|
|
2048
|
-
topic: swarm.topic,
|
|
2049
|
-
isActive: true,
|
|
2050
|
-
label: swarm.label,
|
|
2051
|
-
connections: []
|
|
2052
|
-
};
|
|
2053
|
-
this._swarms.set(PublicKey7.from(swarm._instanceId), info);
|
|
2054
|
-
this.update.emit();
|
|
2055
|
-
swarm.connectionAdded.on((connection) => {
|
|
2056
|
-
const connectionInfo = {
|
|
2057
|
-
state: ConnectionState.CREATED,
|
|
2058
|
-
closeReason: connection.closeReason,
|
|
2059
|
-
remotePeerId: PublicKey7.from(connection.remoteInfo.peerKey),
|
|
2060
|
-
sessionId: connection.sessionId,
|
|
2061
|
-
transport: connection.transport && Object.getPrototypeOf(connection.transport).constructor.name,
|
|
2062
|
-
protocolExtensions: [],
|
|
2063
|
-
events: [],
|
|
2064
|
-
lastUpdate: /* @__PURE__ */ new Date()
|
|
2065
|
-
};
|
|
2066
|
-
info.connections.push(connectionInfo);
|
|
2067
|
-
this.update.emit();
|
|
2068
|
-
connection.stateChanged.on(async (state) => {
|
|
2069
|
-
connectionInfo.state = state;
|
|
2070
|
-
connectionInfo.closeReason = connection.closeReason;
|
|
2071
|
-
connectionInfo.lastUpdate = /* @__PURE__ */ new Date();
|
|
2072
|
-
connectionInfo.events.push({
|
|
2073
|
-
type: "CONNECTION_STATE_CHANGED",
|
|
2074
|
-
newState: state
|
|
2075
|
-
});
|
|
2076
|
-
if (state === ConnectionState.CONNECTED) {
|
|
2077
|
-
const details = await connection.transport?.getDetails();
|
|
2078
|
-
connectionInfo.transportDetails = details;
|
|
2079
|
-
}
|
|
2080
|
-
this.update.emit();
|
|
2081
|
-
});
|
|
2082
|
-
connection.protocol?.stats?.on((stats) => {
|
|
2083
|
-
connectionInfo.readBufferSize = stats.readBufferSize;
|
|
2084
|
-
connectionInfo.writeBufferSize = stats.writeBufferSize;
|
|
2085
|
-
connectionInfo.streams = stats.channels;
|
|
2086
|
-
connectionInfo.lastUpdate = /* @__PURE__ */ new Date();
|
|
2087
|
-
this.update.emit();
|
|
2088
|
-
});
|
|
2089
|
-
connection.transportStats?.on((stats) => {
|
|
2090
|
-
connectionInfo.transportBytesSent = stats.bytesSent;
|
|
2091
|
-
connectionInfo.transportBytesReceived = stats.bytesReceived;
|
|
2092
|
-
connectionInfo.transportPacketsSent = stats.packetsSent;
|
|
2093
|
-
connectionInfo.transportPacketsReceived = stats.packetsReceived;
|
|
2094
|
-
});
|
|
2095
|
-
gcSwarm(info);
|
|
2096
|
-
});
|
|
2097
|
-
}
|
|
2098
|
-
leftSwarm(swarm) {
|
|
2099
|
-
this.getSwarmInfo(PublicKey7.from(swarm._instanceId)).isActive = false;
|
|
2100
|
-
this.update.emit();
|
|
2101
|
-
}
|
|
2102
|
-
};
|
|
2103
|
-
var gcSwarm = (swarm) => {
|
|
2104
|
-
swarm.connections = swarm.connections?.filter((connection) => {
|
|
2105
|
-
return connection.lastUpdate ? Date.now() - connection.lastUpdate.getTime() < CONNECTION_GC_THRESHOLD : true;
|
|
2106
|
-
});
|
|
2107
|
-
};
|
|
2108
|
-
|
|
2109
|
-
// packages/core/mesh/network-manager/src/network-manager.ts
|
|
2110
|
-
import { Event as Event6, synchronized as synchronized4 } from "@dxos/async";
|
|
2111
|
-
import { invariant as invariant6 } from "@dxos/invariant";
|
|
2112
|
-
import { PublicKey as PublicKey8 } from "@dxos/keys";
|
|
2113
|
-
import { log as log8 } from "@dxos/log";
|
|
2114
|
-
import { Messenger } from "@dxos/messaging";
|
|
2115
|
-
import { trace as trace3 } from "@dxos/protocols";
|
|
2116
|
-
import { ConnectionState as ConnectionState2 } from "@dxos/protocols/proto/dxos/client/services";
|
|
2117
|
-
import { ComplexMap as ComplexMap6 } from "@dxos/util";
|
|
2118
|
-
function _ts_decorate4(decorators, target, key, desc) {
|
|
2119
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2120
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2121
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2122
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2123
|
-
}
|
|
2124
|
-
var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/network-manager.ts";
|
|
2125
|
-
var SwarmNetworkManager = class {
|
|
2126
|
-
constructor({ transportFactory, signalManager, enableDevtoolsLogging, peerInfo }) {
|
|
2127
|
-
/**
|
|
2128
|
-
* @internal
|
|
2129
|
-
*/
|
|
2130
|
-
this._swarms = new ComplexMap6(PublicKey8.hash);
|
|
2131
|
-
this._mappers = new ComplexMap6(PublicKey8.hash);
|
|
2132
|
-
this._instanceId = PublicKey8.random().toHex();
|
|
2133
|
-
this._peerInfo = void 0;
|
|
2134
|
-
this._connectionState = ConnectionState2.ONLINE;
|
|
2135
|
-
this.connectionStateChanged = new Event6();
|
|
2136
|
-
this.topicsUpdated = new Event6();
|
|
2137
|
-
this._transportFactory = transportFactory;
|
|
2138
|
-
this._signalManager = signalManager;
|
|
2139
|
-
this._signalManager.swarmEvent.on((event) => this._swarms.get(event.topic)?.onSwarmEvent(event));
|
|
2140
|
-
this._messenger = new Messenger({
|
|
2141
|
-
signalManager: this._signalManager
|
|
2142
|
-
});
|
|
2143
|
-
this._signalConnection = {
|
|
2144
|
-
join: (opts) => this._signalManager.join(opts),
|
|
2145
|
-
leave: (opts) => this._signalManager.leave(opts)
|
|
2146
|
-
};
|
|
2147
|
-
this._peerInfo = peerInfo;
|
|
2148
|
-
this._connectionLimiter = new ConnectionLimiter();
|
|
2149
|
-
if (enableDevtoolsLogging) {
|
|
2150
|
-
this._connectionLog = new ConnectionLog();
|
|
2151
|
-
}
|
|
2152
|
-
}
|
|
2153
|
-
// TODO(burdon): Remove access (Devtools only).
|
|
2154
|
-
get connectionLog() {
|
|
2155
|
-
return this._connectionLog;
|
|
2156
|
-
}
|
|
2157
|
-
get connectionState() {
|
|
2158
|
-
return this._connectionState;
|
|
2159
|
-
}
|
|
2160
|
-
// TODO(burdon): Reconcile with "discovery_key".
|
|
2161
|
-
get topics() {
|
|
2162
|
-
return Array.from(this._swarms.keys());
|
|
2163
|
-
}
|
|
2164
|
-
getSwarmMap(topic) {
|
|
2165
|
-
return this._mappers.get(topic);
|
|
2166
|
-
}
|
|
2167
|
-
getSwarm(topic) {
|
|
2168
|
-
return this._swarms.get(topic);
|
|
2169
|
-
}
|
|
2170
|
-
setPeerInfo(peerInfo) {
|
|
2171
|
-
this._peerInfo = peerInfo;
|
|
2172
|
-
}
|
|
2173
|
-
async open() {
|
|
2174
|
-
log8.trace("dxos.mesh.network-manager.open", trace3.begin({
|
|
2175
|
-
id: this._instanceId
|
|
2176
|
-
}), {
|
|
2177
|
-
F: __dxlog_file8,
|
|
2178
|
-
L: 133,
|
|
2179
|
-
S: this,
|
|
2180
|
-
C: (f, a) => f(...a)
|
|
2181
|
-
});
|
|
2182
|
-
await this._messenger.open();
|
|
2183
|
-
await this._signalManager.open();
|
|
2184
|
-
log8.trace("dxos.mesh.network-manager.open", trace3.end({
|
|
2185
|
-
id: this._instanceId
|
|
2186
|
-
}), {
|
|
2187
|
-
F: __dxlog_file8,
|
|
2188
|
-
L: 136,
|
|
2189
|
-
S: this,
|
|
2190
|
-
C: (f, a) => f(...a)
|
|
2191
|
-
});
|
|
2192
|
-
}
|
|
2193
|
-
async close() {
|
|
2194
|
-
for (const topic of this._swarms.keys()) {
|
|
2195
|
-
await this.leaveSwarm(topic).catch((err) => {
|
|
2196
|
-
log8(err, void 0, {
|
|
2197
|
-
F: __dxlog_file8,
|
|
2198
|
-
L: 142,
|
|
2199
|
-
S: this,
|
|
2200
|
-
C: (f, a) => f(...a)
|
|
2201
|
-
});
|
|
2202
|
-
});
|
|
2203
|
-
}
|
|
2204
|
-
await this._messenger.close();
|
|
2205
|
-
await this._signalManager.close();
|
|
2206
|
-
}
|
|
2207
|
-
/**
|
|
2208
|
-
* Join the swarm.
|
|
2209
|
-
*/
|
|
2210
|
-
async joinSwarm({ topic, peerInfo, topology, protocolProvider: protocol, label }) {
|
|
2211
|
-
invariant6(PublicKey8.isPublicKey(topic), void 0, {
|
|
2212
|
-
F: __dxlog_file8,
|
|
2213
|
-
L: 161,
|
|
2214
|
-
S: this,
|
|
2215
|
-
A: [
|
|
2216
|
-
"PublicKey.isPublicKey(topic)",
|
|
2217
|
-
""
|
|
2218
|
-
]
|
|
2219
|
-
});
|
|
2220
|
-
if (!peerInfo) {
|
|
2221
|
-
peerInfo = {
|
|
2222
|
-
peerKey: this._peerInfo?.peerKey ?? PublicKey8.random().toHex(),
|
|
2223
|
-
identityKey: this._peerInfo?.identityKey ?? PublicKey8.random().toHex()
|
|
2224
|
-
};
|
|
2225
|
-
}
|
|
2226
|
-
invariant6(PublicKey8.from(peerInfo.peerKey), void 0, {
|
|
2227
|
-
F: __dxlog_file8,
|
|
2228
|
-
L: 168,
|
|
2229
|
-
S: this,
|
|
2230
|
-
A: [
|
|
2231
|
-
"PublicKey.from(peerInfo.peerKey)",
|
|
2232
|
-
""
|
|
2233
|
-
]
|
|
2234
|
-
});
|
|
2235
|
-
invariant6(PublicKey8.from(peerInfo.identityKey), void 0, {
|
|
2236
|
-
F: __dxlog_file8,
|
|
2237
|
-
L: 169,
|
|
2238
|
-
S: this,
|
|
2239
|
-
A: [
|
|
2240
|
-
"PublicKey.from(peerInfo.identityKey!)",
|
|
2241
|
-
""
|
|
2242
|
-
]
|
|
2243
|
-
});
|
|
2244
|
-
invariant6(topology, void 0, {
|
|
2245
|
-
F: __dxlog_file8,
|
|
2246
|
-
L: 170,
|
|
2247
|
-
S: this,
|
|
2248
|
-
A: [
|
|
2249
|
-
"topology",
|
|
2250
|
-
""
|
|
2251
|
-
]
|
|
2252
|
-
});
|
|
2253
|
-
invariant6(typeof protocol === "function", void 0, {
|
|
2254
|
-
F: __dxlog_file8,
|
|
2255
|
-
L: 171,
|
|
2256
|
-
S: this,
|
|
2257
|
-
A: [
|
|
2258
|
-
"typeof protocol === 'function'",
|
|
2259
|
-
""
|
|
2260
|
-
]
|
|
2261
|
-
});
|
|
2262
|
-
if (this._swarms.has(topic)) {
|
|
2263
|
-
throw new Error(`Already connected to swarm: ${PublicKey8.from(topic)}`);
|
|
2264
|
-
}
|
|
2265
|
-
log8("joining", {
|
|
2266
|
-
topic: PublicKey8.from(topic),
|
|
2267
|
-
peerInfo,
|
|
2268
|
-
topology: topology.toString()
|
|
2269
|
-
}, {
|
|
2270
|
-
F: __dxlog_file8,
|
|
2271
|
-
L: 176,
|
|
2272
|
-
S: this,
|
|
2273
|
-
C: (f, a) => f(...a)
|
|
2274
|
-
});
|
|
2275
|
-
const swarm = new Swarm(topic, peerInfo, topology, protocol, this._messenger, this._transportFactory, label, this._connectionLimiter);
|
|
2276
|
-
swarm.errors.handle((error) => {
|
|
2277
|
-
log8("swarm error", {
|
|
2278
|
-
error
|
|
2279
|
-
}, {
|
|
2280
|
-
F: __dxlog_file8,
|
|
2281
|
-
L: 189,
|
|
2282
|
-
S: this,
|
|
2283
|
-
C: (f, a) => f(...a)
|
|
2284
|
-
});
|
|
2285
|
-
});
|
|
2286
|
-
this._swarms.set(topic, swarm);
|
|
2287
|
-
this._mappers.set(topic, new SwarmMapper(swarm));
|
|
2288
|
-
await swarm.open();
|
|
2289
|
-
this._signalConnection.join({
|
|
2290
|
-
topic,
|
|
2291
|
-
peer: peerInfo
|
|
2292
|
-
}).catch((error) => log8.catch(error, void 0, {
|
|
2293
|
-
F: __dxlog_file8,
|
|
2294
|
-
L: 198,
|
|
2295
|
-
S: this,
|
|
2296
|
-
C: (f, a) => f(...a)
|
|
2297
|
-
}));
|
|
2298
|
-
this.topicsUpdated.emit();
|
|
2299
|
-
this._connectionLog?.joinedSwarm(swarm);
|
|
2300
|
-
log8("joined", {
|
|
2301
|
-
topic: PublicKey8.from(topic),
|
|
2302
|
-
count: this._swarms.size
|
|
2303
|
-
}, {
|
|
2304
|
-
F: __dxlog_file8,
|
|
2305
|
-
L: 202,
|
|
2306
|
-
S: this,
|
|
2307
|
-
C: (f, a) => f(...a)
|
|
2308
|
-
});
|
|
2309
|
-
return {
|
|
2310
|
-
close: () => this.leaveSwarm(topic)
|
|
2311
|
-
};
|
|
2312
|
-
}
|
|
2313
|
-
/**
|
|
2314
|
-
* Close the connection.
|
|
2315
|
-
*/
|
|
2316
|
-
async leaveSwarm(topic) {
|
|
2317
|
-
if (!this._swarms.has(topic)) {
|
|
2318
|
-
return;
|
|
2319
|
-
}
|
|
2320
|
-
log8("leaving", {
|
|
2321
|
-
topic: PublicKey8.from(topic)
|
|
2322
|
-
}, {
|
|
2323
|
-
F: __dxlog_file8,
|
|
2324
|
-
L: 219,
|
|
2325
|
-
S: this,
|
|
2326
|
-
C: (f, a) => f(...a)
|
|
2327
|
-
});
|
|
2328
|
-
const swarm = this._swarms.get(topic);
|
|
2329
|
-
await this._signalConnection.leave({
|
|
2330
|
-
topic,
|
|
2331
|
-
peer: swarm.ownPeer
|
|
2332
|
-
});
|
|
2333
|
-
const map = this._mappers.get(topic);
|
|
2334
|
-
map.destroy();
|
|
2335
|
-
this._mappers.delete(topic);
|
|
2336
|
-
this._connectionLog?.leftSwarm(swarm);
|
|
2337
|
-
await swarm.destroy();
|
|
2338
|
-
this._swarms.delete(topic);
|
|
2339
|
-
this.topicsUpdated.emit();
|
|
2340
|
-
log8("left", {
|
|
2341
|
-
topic: PublicKey8.from(topic),
|
|
2342
|
-
count: this._swarms.size
|
|
2343
|
-
}, {
|
|
2344
|
-
F: __dxlog_file8,
|
|
2345
|
-
L: 233,
|
|
2346
|
-
S: this,
|
|
2347
|
-
C: (f, a) => f(...a)
|
|
2348
|
-
});
|
|
2349
|
-
}
|
|
2350
|
-
async setConnectionState(state) {
|
|
2351
|
-
if (state === this._connectionState) {
|
|
2352
|
-
return;
|
|
2353
|
-
}
|
|
2354
|
-
switch (state) {
|
|
2355
|
-
case ConnectionState2.OFFLINE: {
|
|
2356
|
-
this._connectionState = state;
|
|
2357
|
-
await Promise.all([
|
|
2358
|
-
...this._swarms.values()
|
|
2359
|
-
].map((swarm) => swarm.goOffline()));
|
|
2360
|
-
await this._messenger.close();
|
|
2361
|
-
await this._signalManager.close();
|
|
2362
|
-
break;
|
|
2363
|
-
}
|
|
2364
|
-
case ConnectionState2.ONLINE: {
|
|
2365
|
-
this._connectionState = state;
|
|
2366
|
-
this._messenger.open();
|
|
2367
|
-
await Promise.all([
|
|
2368
|
-
...this._swarms.values()
|
|
2369
|
-
].map((swarm) => swarm.goOnline()));
|
|
2370
|
-
await this._signalManager.open();
|
|
2371
|
-
break;
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
this.connectionStateChanged.emit(this._connectionState);
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
_ts_decorate4([
|
|
2378
|
-
synchronized4
|
|
2379
|
-
], SwarmNetworkManager.prototype, "joinSwarm", null);
|
|
2380
|
-
_ts_decorate4([
|
|
2381
|
-
synchronized4
|
|
2382
|
-
], SwarmNetworkManager.prototype, "leaveSwarm", null);
|
|
2383
|
-
|
|
2384
|
-
// packages/core/mesh/network-manager/src/topology/fully-connected-topology.ts
|
|
2385
|
-
import { invariant as invariant7 } from "@dxos/invariant";
|
|
2386
|
-
var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/fully-connected-topology.ts";
|
|
2387
|
-
var FullyConnectedTopology = class {
|
|
2388
|
-
toString() {
|
|
2389
|
-
return "FullyConnectedTopology";
|
|
2390
|
-
}
|
|
2391
|
-
init(controller) {
|
|
2392
|
-
invariant7(!this._controller, "Already initialized", {
|
|
2393
|
-
F: __dxlog_file9,
|
|
2394
|
-
L: 18,
|
|
2395
|
-
S: this,
|
|
2396
|
-
A: [
|
|
2397
|
-
"!this._controller",
|
|
2398
|
-
"'Already initialized'"
|
|
2399
|
-
]
|
|
2400
|
-
});
|
|
2401
|
-
this._controller = controller;
|
|
2402
|
-
}
|
|
2403
|
-
update() {
|
|
2404
|
-
invariant7(this._controller, "Not initialized", {
|
|
2405
|
-
F: __dxlog_file9,
|
|
2406
|
-
L: 23,
|
|
2407
|
-
S: this,
|
|
2408
|
-
A: [
|
|
2409
|
-
"this._controller",
|
|
2410
|
-
"'Not initialized'"
|
|
2411
|
-
]
|
|
2412
|
-
});
|
|
2413
|
-
const { candidates: discovered } = this._controller.getState();
|
|
2414
|
-
for (const peer of discovered) {
|
|
2415
|
-
this._controller.connect(peer);
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
async onOffer(peer) {
|
|
2419
|
-
return true;
|
|
2420
|
-
}
|
|
2421
|
-
async destroy() {
|
|
2422
|
-
}
|
|
2423
|
-
};
|
|
2424
|
-
|
|
2425
|
-
// packages/core/mesh/network-manager/src/topology/mmst-topology.ts
|
|
2426
|
-
import { invariant as invariant8 } from "@dxos/invariant";
|
|
2427
|
-
import { log as log9 } from "@dxos/log";
|
|
2428
|
-
var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/mmst-topology.ts";
|
|
2429
|
-
var MIN_UPDATE_INTERVAL = 1e3 * 10;
|
|
2430
|
-
var MAX_CHANGES_PER_UPDATE = 1;
|
|
2431
|
-
var MMSTTopology = class {
|
|
2432
|
-
constructor({ originateConnections = 2, maxPeers = 4, sampleSize = 10 } = {}) {
|
|
2433
|
-
this._sampleCollected = false;
|
|
2434
|
-
this._lastAction = /* @__PURE__ */ new Date(0);
|
|
2435
|
-
this._originateConnections = originateConnections;
|
|
2436
|
-
this._maxPeers = maxPeers;
|
|
2437
|
-
this._sampleSize = sampleSize;
|
|
2438
|
-
}
|
|
2439
|
-
init(controller) {
|
|
2440
|
-
invariant8(!this._controller, "Already initialized", {
|
|
2441
|
-
F: __dxlog_file10,
|
|
2442
|
-
L: 49,
|
|
2443
|
-
S: this,
|
|
2444
|
-
A: [
|
|
2445
|
-
"!this._controller",
|
|
2446
|
-
"'Already initialized'"
|
|
2447
|
-
]
|
|
2448
|
-
});
|
|
2449
|
-
this._controller = controller;
|
|
2450
|
-
}
|
|
2451
|
-
update() {
|
|
2452
|
-
invariant8(this._controller, "Not initialized", {
|
|
2453
|
-
F: __dxlog_file10,
|
|
2454
|
-
L: 54,
|
|
2455
|
-
S: this,
|
|
2456
|
-
A: [
|
|
2457
|
-
"this._controller",
|
|
2458
|
-
"'Not initialized'"
|
|
2459
|
-
]
|
|
2460
|
-
});
|
|
2461
|
-
const { connected, candidates } = this._controller.getState();
|
|
2462
|
-
if (this._sampleCollected || connected.length > this._maxPeers || candidates.length > 0) {
|
|
2463
|
-
log9("Running the algorithm.", void 0, {
|
|
2464
|
-
F: __dxlog_file10,
|
|
2465
|
-
L: 58,
|
|
2466
|
-
S: this,
|
|
2467
|
-
C: (f, a) => f(...a)
|
|
2468
|
-
});
|
|
2469
|
-
this._sampleCollected = true;
|
|
2470
|
-
this._runAlgorithm();
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
forceUpdate() {
|
|
2474
|
-
this._lastAction = /* @__PURE__ */ new Date(0);
|
|
2475
|
-
this.update();
|
|
2476
|
-
}
|
|
2477
|
-
async onOffer(peer) {
|
|
2478
|
-
invariant8(this._controller, "Not initialized", {
|
|
2479
|
-
F: __dxlog_file10,
|
|
2480
|
-
L: 70,
|
|
2481
|
-
S: this,
|
|
2482
|
-
A: [
|
|
2483
|
-
"this._controller",
|
|
2484
|
-
"'Not initialized'"
|
|
2485
|
-
]
|
|
2486
|
-
});
|
|
2487
|
-
const { connected } = this._controller.getState();
|
|
2488
|
-
const accept = connected.length < this._maxPeers;
|
|
2489
|
-
log9(`Offer ${peer} accept=${accept}`, void 0, {
|
|
2490
|
-
F: __dxlog_file10,
|
|
2491
|
-
L: 73,
|
|
2492
|
-
S: this,
|
|
2493
|
-
C: (f, a) => f(...a)
|
|
2494
|
-
});
|
|
2495
|
-
return accept;
|
|
2496
|
-
}
|
|
2497
|
-
async destroy() {
|
|
2498
|
-
}
|
|
2499
|
-
_runAlgorithm() {
|
|
2500
|
-
invariant8(this._controller, "Not initialized", {
|
|
2501
|
-
F: __dxlog_file10,
|
|
2502
|
-
L: 82,
|
|
2503
|
-
S: this,
|
|
2504
|
-
A: [
|
|
2505
|
-
"this._controller",
|
|
2506
|
-
"'Not initialized'"
|
|
2507
|
-
]
|
|
2508
|
-
});
|
|
2509
|
-
const { connected, candidates, ownPeerId } = this._controller.getState();
|
|
2510
|
-
if (connected.length > this._maxPeers) {
|
|
2511
|
-
log9(`disconnect ${connected.length - this._maxPeers} peers.`, void 0, {
|
|
2512
|
-
F: __dxlog_file10,
|
|
2513
|
-
L: 88,
|
|
2514
|
-
S: this,
|
|
2515
|
-
C: (f, a) => f(...a)
|
|
2516
|
-
});
|
|
2517
|
-
const sorted = sortByXorDistance(connected, ownPeerId).reverse().slice(0, this._maxPeers - connected.length);
|
|
2518
|
-
invariant8(sorted.length === 0, void 0, {
|
|
2519
|
-
F: __dxlog_file10,
|
|
2520
|
-
L: 92,
|
|
2521
|
-
S: this,
|
|
2522
|
-
A: [
|
|
2523
|
-
"sorted.length === 0",
|
|
2524
|
-
""
|
|
2525
|
-
]
|
|
2526
|
-
});
|
|
2527
|
-
if (sorted.length > MAX_CHANGES_PER_UPDATE) {
|
|
2528
|
-
log9(`want to disconnect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
|
|
2529
|
-
F: __dxlog_file10,
|
|
2530
|
-
L: 95,
|
|
2531
|
-
S: this,
|
|
2532
|
-
C: (f, a) => f(...a)
|
|
2533
|
-
});
|
|
2534
|
-
}
|
|
2535
|
-
if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
|
|
2536
|
-
for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
|
|
2537
|
-
log9(`Disconnect ${peer}.`, void 0, {
|
|
2538
|
-
F: __dxlog_file10,
|
|
2539
|
-
L: 100,
|
|
2540
|
-
S: this,
|
|
2541
|
-
C: (f, a) => f(...a)
|
|
2542
|
-
});
|
|
2543
|
-
this._controller.disconnect(peer);
|
|
2544
|
-
}
|
|
2545
|
-
this._lastAction = /* @__PURE__ */ new Date();
|
|
2546
|
-
} else {
|
|
2547
|
-
log9("rate limited disconnect", void 0, {
|
|
2548
|
-
F: __dxlog_file10,
|
|
2549
|
-
L: 105,
|
|
2550
|
-
S: this,
|
|
2551
|
-
C: (f, a) => f(...a)
|
|
2552
|
-
});
|
|
2553
|
-
}
|
|
2554
|
-
} else if (connected.length < this._originateConnections) {
|
|
2555
|
-
log9(`connect ${this._originateConnections - connected.length} peers.`, void 0, {
|
|
2556
|
-
F: __dxlog_file10,
|
|
2557
|
-
L: 109,
|
|
2558
|
-
S: this,
|
|
2559
|
-
C: (f, a) => f(...a)
|
|
2560
|
-
});
|
|
2561
|
-
const sample = candidates.sort(() => Math.random() - 0.5).slice(0, this._sampleSize);
|
|
2562
|
-
const sorted = sortByXorDistance(sample, ownPeerId).slice(0, this._originateConnections - connected.length);
|
|
2563
|
-
if (sorted.length > MAX_CHANGES_PER_UPDATE) {
|
|
2564
|
-
log9(`want to connect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
|
|
2565
|
-
F: __dxlog_file10,
|
|
2566
|
-
L: 114,
|
|
2567
|
-
S: this,
|
|
2568
|
-
C: (f, a) => f(...a)
|
|
2569
|
-
});
|
|
2570
|
-
}
|
|
2571
|
-
if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
|
|
2572
|
-
for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
|
|
2573
|
-
log9(`Connect ${peer}.`, void 0, {
|
|
2574
|
-
F: __dxlog_file10,
|
|
2575
|
-
L: 118,
|
|
2576
|
-
S: this,
|
|
2577
|
-
C: (f, a) => f(...a)
|
|
2578
|
-
});
|
|
2579
|
-
this._controller.connect(peer);
|
|
2580
|
-
}
|
|
2581
|
-
this._lastAction = /* @__PURE__ */ new Date();
|
|
2582
|
-
} else {
|
|
2583
|
-
log9("rate limited connect", void 0, {
|
|
2584
|
-
F: __dxlog_file10,
|
|
2585
|
-
L: 123,
|
|
2586
|
-
S: this,
|
|
2587
|
-
C: (f, a) => f(...a)
|
|
2588
|
-
});
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
toString() {
|
|
2593
|
-
return "MMSTTopology";
|
|
2594
|
-
}
|
|
2595
|
-
};
|
|
2596
|
-
var sortByXorDistance = (keys, reference) => {
|
|
2597
|
-
const sorted = keys.sort((a, b) => {
|
|
2598
|
-
return compareXor(distXor(a.asBuffer(), reference.asBuffer()), distXor(b.asBuffer(), reference.asBuffer()));
|
|
2599
|
-
});
|
|
2600
|
-
log9("Sorted keys", {
|
|
2601
|
-
keys,
|
|
2602
|
-
reference,
|
|
2603
|
-
sorted
|
|
2604
|
-
}, {
|
|
2605
|
-
F: __dxlog_file10,
|
|
2606
|
-
L: 137,
|
|
2607
|
-
S: void 0,
|
|
2608
|
-
C: (f, a) => f(...a)
|
|
2609
|
-
});
|
|
2610
|
-
return sorted;
|
|
2611
|
-
};
|
|
2612
|
-
var distXor = (a, b) => {
|
|
2613
|
-
const maxLength = Math.max(a.length, b.length);
|
|
2614
|
-
const result = Buffer.allocUnsafe(maxLength);
|
|
2615
|
-
for (let i = 0; i < maxLength; i++) {
|
|
2616
|
-
result[i] = (a[i] || 0) ^ (b[i] || 0);
|
|
2617
|
-
}
|
|
2618
|
-
return result;
|
|
2619
|
-
};
|
|
2620
|
-
var compareXor = (a, b) => {
|
|
2621
|
-
const maxLength = Math.max(a.length, b.length);
|
|
2622
|
-
for (let i = 0; i < maxLength; i++) {
|
|
2623
|
-
if ((a[i] || 0) === (b[i] || 0)) {
|
|
2624
|
-
continue;
|
|
2625
|
-
}
|
|
2626
|
-
return (a[i] || 0) < (b[i] || 0) ? -1 : 1;
|
|
2627
|
-
}
|
|
2628
|
-
return 0;
|
|
2629
|
-
};
|
|
2630
|
-
|
|
2631
|
-
// packages/core/mesh/network-manager/src/topology/star-topology.ts
|
|
2632
|
-
import { invariant as invariant9 } from "@dxos/invariant";
|
|
2633
|
-
import { log as log10 } from "@dxos/log";
|
|
2634
|
-
var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/star-topology.ts";
|
|
2635
|
-
var StarTopology = class {
|
|
2636
|
-
constructor(_centralPeer) {
|
|
2637
|
-
this._centralPeer = _centralPeer;
|
|
2638
|
-
}
|
|
2639
|
-
toString() {
|
|
2640
|
-
return `StarTopology(${this._centralPeer.truncate()})`;
|
|
2641
|
-
}
|
|
2642
|
-
init(controller) {
|
|
2643
|
-
invariant9(!this._controller, "Already initialized.", {
|
|
2644
|
-
F: __dxlog_file11,
|
|
2645
|
-
L: 21,
|
|
2646
|
-
S: this,
|
|
2647
|
-
A: [
|
|
2648
|
-
"!this._controller",
|
|
2649
|
-
"'Already initialized.'"
|
|
2650
|
-
]
|
|
2651
|
-
});
|
|
2652
|
-
this._controller = controller;
|
|
2653
|
-
}
|
|
2654
|
-
update() {
|
|
2655
|
-
invariant9(this._controller, "Not initialized.", {
|
|
2656
|
-
F: __dxlog_file11,
|
|
2657
|
-
L: 26,
|
|
2658
|
-
S: this,
|
|
2659
|
-
A: [
|
|
2660
|
-
"this._controller",
|
|
2661
|
-
"'Not initialized.'"
|
|
2662
|
-
]
|
|
2663
|
-
});
|
|
2664
|
-
const { candidates, connected, ownPeerId } = this._controller.getState();
|
|
2665
|
-
if (!ownPeerId.equals(this._centralPeer)) {
|
|
2666
|
-
log10("leaf peer dropping all connections apart from central peer.", void 0, {
|
|
2667
|
-
F: __dxlog_file11,
|
|
2668
|
-
L: 29,
|
|
2669
|
-
S: this,
|
|
2670
|
-
C: (f, a) => f(...a)
|
|
2671
|
-
});
|
|
2672
|
-
for (const peer of connected) {
|
|
2673
|
-
if (!peer.equals(this._centralPeer)) {
|
|
2674
|
-
log10("dropping connection", {
|
|
2675
|
-
peer
|
|
2676
|
-
}, {
|
|
2677
|
-
F: __dxlog_file11,
|
|
2678
|
-
L: 34,
|
|
2679
|
-
S: this,
|
|
2680
|
-
C: (f, a) => f(...a)
|
|
2681
|
-
});
|
|
2682
|
-
this._controller.disconnect(peer);
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
for (const peer of candidates) {
|
|
2687
|
-
if (peer.equals(this._centralPeer) || ownPeerId.equals(this._centralPeer)) {
|
|
2688
|
-
log10("connecting to peer", {
|
|
2689
|
-
peer
|
|
2690
|
-
}, {
|
|
2691
|
-
F: __dxlog_file11,
|
|
2692
|
-
L: 43,
|
|
2693
|
-
S: this,
|
|
2694
|
-
C: (f, a) => f(...a)
|
|
2695
|
-
});
|
|
2696
|
-
this._controller.connect(peer);
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
}
|
|
2700
|
-
async onOffer(peer) {
|
|
2701
|
-
invariant9(this._controller, "Not initialized.", {
|
|
2702
|
-
F: __dxlog_file11,
|
|
2703
|
-
L: 50,
|
|
2704
|
-
S: this,
|
|
2705
|
-
A: [
|
|
2706
|
-
"this._controller",
|
|
2707
|
-
"'Not initialized.'"
|
|
2708
|
-
]
|
|
2709
|
-
});
|
|
2710
|
-
const { ownPeerId } = this._controller.getState();
|
|
2711
|
-
log10("offer", {
|
|
2712
|
-
peer,
|
|
2713
|
-
isCentral: peer.equals(this._centralPeer),
|
|
2714
|
-
isSelfCentral: ownPeerId.equals(this._centralPeer)
|
|
2715
|
-
}, {
|
|
2716
|
-
F: __dxlog_file11,
|
|
2717
|
-
L: 52,
|
|
2718
|
-
S: this,
|
|
2719
|
-
C: (f, a) => f(...a)
|
|
2720
|
-
});
|
|
2721
|
-
return ownPeerId.equals(this._centralPeer) || peer.equals(this._centralPeer);
|
|
2722
|
-
}
|
|
2723
|
-
async destroy() {
|
|
2724
|
-
}
|
|
2725
|
-
};
|
|
2726
|
-
|
|
2727
|
-
// packages/core/mesh/network-manager/src/transport/memory-transport.ts
|
|
2728
|
-
import { Transform } from "node:stream";
|
|
2729
|
-
import { Event as Event7, Trigger as Trigger2 } from "@dxos/async";
|
|
2730
|
-
import { ErrorStream as ErrorStream3 } from "@dxos/debug";
|
|
2731
|
-
import { invariant as invariant10 } from "@dxos/invariant";
|
|
2732
|
-
import { PublicKey as PublicKey9 } from "@dxos/keys";
|
|
2733
|
-
import { log as log11, logInfo as logInfo3 } from "@dxos/log";
|
|
2734
|
-
import { ComplexMap as ComplexMap7 } from "@dxos/util";
|
|
2735
|
-
function _ts_decorate5(decorators, target, key, desc) {
|
|
2736
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2737
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2738
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2739
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2740
|
-
}
|
|
2741
|
-
var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/memory-transport.ts";
|
|
2742
|
-
var MEMORY_TRANSPORT_DELAY = 1;
|
|
2743
|
-
var createStreamDelay = (delay) => {
|
|
2744
|
-
return new Transform({
|
|
2745
|
-
objectMode: true,
|
|
2746
|
-
transform: (chunk, _, cb) => {
|
|
2747
|
-
setTimeout(() => cb(null, chunk), delay);
|
|
2748
|
-
}
|
|
2749
|
-
});
|
|
2750
|
-
};
|
|
2751
|
-
var MemoryTransportFactory = {
|
|
2752
|
-
createTransport: (options) => new MemoryTransport(options)
|
|
2753
|
-
};
|
|
2754
|
-
var MemoryTransport = class _MemoryTransport {
|
|
2755
|
-
static {
|
|
2756
|
-
// TODO(burdon): Remove static properties (inject context into constructor).
|
|
2757
|
-
this._connections = new ComplexMap7(PublicKey9.hash);
|
|
2758
|
-
}
|
|
2759
|
-
constructor(_options) {
|
|
2760
|
-
this._options = _options;
|
|
2761
|
-
this._instanceId = PublicKey9.random();
|
|
2762
|
-
this._remote = new Trigger2();
|
|
2763
|
-
this._outgoingDelay = createStreamDelay(MEMORY_TRANSPORT_DELAY);
|
|
2764
|
-
this._incomingDelay = createStreamDelay(MEMORY_TRANSPORT_DELAY);
|
|
2765
|
-
this._closed = false;
|
|
2766
|
-
this.closed = new Event7();
|
|
2767
|
-
this.connected = new Event7();
|
|
2768
|
-
this.errors = new ErrorStream3();
|
|
2769
|
-
invariant10(!_MemoryTransport._connections.has(this._instanceId), "Duplicate memory connection", {
|
|
2770
|
-
F: __dxlog_file12,
|
|
2771
|
-
L: 64,
|
|
2772
|
-
S: this,
|
|
2773
|
-
A: [
|
|
2774
|
-
"!MemoryTransport._connections.has(this._instanceId)",
|
|
2775
|
-
"'Duplicate memory connection'"
|
|
2776
|
-
]
|
|
2777
|
-
});
|
|
2778
|
-
_MemoryTransport._connections.set(this._instanceId, this);
|
|
2779
|
-
}
|
|
2780
|
-
get isOpen() {
|
|
2781
|
-
return !this._closed;
|
|
2782
|
-
}
|
|
2783
|
-
async open() {
|
|
2784
|
-
log11("opening...", void 0, {
|
|
2785
|
-
F: __dxlog_file12,
|
|
2786
|
-
L: 74,
|
|
2787
|
-
S: this,
|
|
2788
|
-
C: (f, a) => f(...a)
|
|
2789
|
-
});
|
|
2790
|
-
if (this._options.initiator) {
|
|
2791
|
-
log11("sending signal", void 0, {
|
|
2792
|
-
F: __dxlog_file12,
|
|
2793
|
-
L: 78,
|
|
2794
|
-
S: this,
|
|
2795
|
-
C: (f, a) => f(...a)
|
|
2796
|
-
});
|
|
2797
|
-
try {
|
|
2798
|
-
await this._options.sendSignal({
|
|
2799
|
-
payload: {
|
|
2800
|
-
transportId: this._instanceId.toHex()
|
|
2801
|
-
}
|
|
2802
|
-
});
|
|
2803
|
-
} catch (err) {
|
|
2804
|
-
if (!this._closed) {
|
|
2805
|
-
this.errors.raise(toError(err));
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
} else {
|
|
2809
|
-
this._remote.wait({
|
|
2810
|
-
timeout: this._options.timeout ?? 1e3
|
|
2811
|
-
}).then((remoteId) => {
|
|
2812
|
-
if (this._closed) {
|
|
2813
|
-
return;
|
|
2814
|
-
}
|
|
2815
|
-
this._remoteInstanceId = remoteId;
|
|
2816
|
-
this._remoteConnection = _MemoryTransport._connections.get(this._remoteInstanceId);
|
|
2817
|
-
if (!this._remoteConnection) {
|
|
2818
|
-
this._closed = true;
|
|
2819
|
-
this.closed.emit();
|
|
2820
|
-
return;
|
|
2821
|
-
}
|
|
2822
|
-
invariant10(!this._remoteConnection._remoteConnection, `Remote already connected: ${this._remoteInstanceId}`, {
|
|
2823
|
-
F: __dxlog_file12,
|
|
2824
|
-
L: 104,
|
|
2825
|
-
S: this,
|
|
2826
|
-
A: [
|
|
2827
|
-
"!this._remoteConnection._remoteConnection",
|
|
2828
|
-
"`Remote already connected: ${this._remoteInstanceId}`"
|
|
2829
|
-
]
|
|
2830
|
-
});
|
|
2831
|
-
this._remoteConnection._remoteConnection = this;
|
|
2832
|
-
this._remoteConnection._remoteInstanceId = this._instanceId;
|
|
2833
|
-
log11("connected", void 0, {
|
|
2834
|
-
F: __dxlog_file12,
|
|
2835
|
-
L: 108,
|
|
2836
|
-
S: this,
|
|
2837
|
-
C: (f, a) => f(...a)
|
|
2838
|
-
});
|
|
2839
|
-
this._options.stream.pipe(this._outgoingDelay).pipe(this._remoteConnection._options.stream).pipe(this._incomingDelay).pipe(this._options.stream);
|
|
2840
|
-
this.connected.emit();
|
|
2841
|
-
this._remoteConnection.connected.emit();
|
|
2842
|
-
}).catch((err) => {
|
|
2843
|
-
if (this._closed) {
|
|
2844
|
-
return;
|
|
2845
|
-
}
|
|
2846
|
-
this.errors.raise(err);
|
|
2847
|
-
});
|
|
2848
|
-
}
|
|
2849
|
-
return this;
|
|
2850
|
-
}
|
|
2851
|
-
async close() {
|
|
2852
|
-
log11("closing...", void 0, {
|
|
2853
|
-
F: __dxlog_file12,
|
|
2854
|
-
L: 130,
|
|
2855
|
-
S: this,
|
|
2856
|
-
C: (f, a) => f(...a)
|
|
2857
|
-
});
|
|
2858
|
-
this._closed = true;
|
|
2859
|
-
_MemoryTransport._connections.delete(this._instanceId);
|
|
2860
|
-
if (this._remoteConnection) {
|
|
2861
|
-
this._remoteConnection._closed = true;
|
|
2862
|
-
_MemoryTransport._connections.delete(this._remoteInstanceId);
|
|
2863
|
-
this._options.stream.unpipe(this._incomingDelay);
|
|
2864
|
-
this._incomingDelay.unpipe(this._remoteConnection._options.stream);
|
|
2865
|
-
this._remoteConnection._options.stream.unpipe(this._outgoingDelay);
|
|
2866
|
-
this._outgoingDelay.unpipe(this._options.stream);
|
|
2867
|
-
this._options.stream.unpipe(this._outgoingDelay);
|
|
2868
|
-
this._remoteConnection.closed.emit();
|
|
2869
|
-
this._remoteConnection._remoteConnection = void 0;
|
|
2870
|
-
this._remoteConnection = void 0;
|
|
2871
|
-
}
|
|
2872
|
-
this.closed.emit();
|
|
2873
|
-
log11("closed", void 0, {
|
|
2874
|
-
F: __dxlog_file12,
|
|
2875
|
-
L: 158,
|
|
2876
|
-
S: this,
|
|
2877
|
-
C: (f, a) => f(...a)
|
|
2878
|
-
});
|
|
2879
|
-
return this;
|
|
2880
|
-
}
|
|
2881
|
-
async onSignal({ payload }) {
|
|
2882
|
-
log11("received signal", {
|
|
2883
|
-
payload
|
|
2884
|
-
}, {
|
|
2885
|
-
F: __dxlog_file12,
|
|
2886
|
-
L: 163,
|
|
2887
|
-
S: this,
|
|
2888
|
-
C: (f, a) => f(...a)
|
|
2889
|
-
});
|
|
2890
|
-
if (!payload?.transportId) {
|
|
2891
|
-
return;
|
|
2892
|
-
}
|
|
2893
|
-
const transportId = payload.transportId;
|
|
2894
|
-
if (transportId) {
|
|
2895
|
-
const remoteId = PublicKey9.fromHex(transportId);
|
|
2896
|
-
this._remote.wake(remoteId);
|
|
2897
|
-
}
|
|
2898
|
-
}
|
|
2899
|
-
async getDetails() {
|
|
2900
|
-
return this._instanceId.toHex();
|
|
2901
|
-
}
|
|
2902
|
-
async getStats() {
|
|
2903
|
-
return {
|
|
2904
|
-
bytesSent: 0,
|
|
2905
|
-
bytesReceived: 0,
|
|
2906
|
-
packetsSent: 0,
|
|
2907
|
-
packetsReceived: 0
|
|
2908
|
-
};
|
|
2909
|
-
}
|
|
2910
|
-
};
|
|
2911
|
-
_ts_decorate5([
|
|
2912
|
-
logInfo3
|
|
2913
|
-
], MemoryTransport.prototype, "_instanceId", void 0);
|
|
2914
|
-
_ts_decorate5([
|
|
2915
|
-
logInfo3
|
|
2916
|
-
], MemoryTransport.prototype, "_remoteInstanceId", void 0);
|
|
2917
|
-
var toError = (err) => err instanceof Error ? err : new Error(String(err));
|
|
2918
|
-
|
|
2919
|
-
// packages/core/mesh/network-manager/src/transport/transport.ts
|
|
2920
|
-
var TransportKind;
|
|
2921
|
-
(function(TransportKind2) {
|
|
2922
|
-
TransportKind2["WEB_RTC"] = "WEB-RTC";
|
|
2923
|
-
TransportKind2["WEB_RTC_PROXY"] = "WEB-RTC_PROXY";
|
|
2924
|
-
TransportKind2["MEMORY"] = "MEMORY";
|
|
2925
|
-
TransportKind2["TCP"] = "TCP";
|
|
2926
|
-
})(TransportKind || (TransportKind = {}));
|
|
2927
|
-
|
|
2928
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-connection-factory.ts
|
|
2929
|
-
import { Mutex } from "@dxos/async";
|
|
2930
|
-
var BrowserRtcConnectionFactory = class {
|
|
2931
|
-
async initialize() {
|
|
2932
|
-
}
|
|
2933
|
-
async onConnectionDestroyed() {
|
|
2934
|
-
}
|
|
2935
|
-
async createConnection(config) {
|
|
2936
|
-
return new RTCPeerConnection(config);
|
|
2937
|
-
}
|
|
2938
|
-
async initConnection(connection, info) {
|
|
2939
|
-
}
|
|
2940
|
-
};
|
|
2941
|
-
var NodeRtcConnectionFactory = class _NodeRtcConnectionFactory {
|
|
2942
|
-
static {
|
|
2943
|
-
this._createdConnections = 0;
|
|
2944
|
-
}
|
|
2945
|
-
static {
|
|
2946
|
-
this._cleanupMutex = new Mutex();
|
|
2947
|
-
}
|
|
2948
|
-
// This should be inside the function to avoid triggering `eval` in the global scope.
|
|
2949
|
-
// eslint-disable-next-line no-new-func
|
|
2950
|
-
// TODO(burdon): Do imports here?
|
|
2951
|
-
async initialize() {
|
|
2952
|
-
}
|
|
2953
|
-
async onConnectionDestroyed() {
|
|
2954
|
-
return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
|
|
2955
|
-
if (--_NodeRtcConnectionFactory._createdConnections === 0) {
|
|
2956
|
-
(await import("#node-datachannel")).cleanup();
|
|
2957
|
-
}
|
|
2958
|
-
});
|
|
2959
|
-
}
|
|
2960
|
-
async createConnection(config) {
|
|
2961
|
-
return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
|
|
2962
|
-
const { RTCPeerConnection: RTCPeerConnection1 } = await import("#node-datachannel/polyfill");
|
|
2963
|
-
_NodeRtcConnectionFactory._createdConnections++;
|
|
2964
|
-
return new RTCPeerConnection1(config);
|
|
2965
|
-
});
|
|
2966
|
-
}
|
|
2967
|
-
async initConnection(connection, info) {
|
|
2968
|
-
if (info.initiator) {
|
|
2969
|
-
connection.onnegotiationneeded?.(null);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
};
|
|
2973
|
-
var getRtcConnectionFactory = () => {
|
|
2974
|
-
return typeof globalThis.RTCPeerConnection === "undefined" ? new NodeRtcConnectionFactory() : new BrowserRtcConnectionFactory();
|
|
2975
|
-
};
|
|
2976
|
-
|
|
2977
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
|
|
2978
|
-
import { synchronized as synchronized5, Trigger as Trigger3, Mutex as Mutex2 } from "@dxos/async";
|
|
2979
|
-
import { invariant as invariant12 } from "@dxos/invariant";
|
|
2980
|
-
import { log as log13, logInfo as logInfo4 } from "@dxos/log";
|
|
2981
|
-
import { ConnectivityError as ConnectivityError3 } from "@dxos/protocols";
|
|
2982
|
-
import { trace as trace4 } from "@dxos/tracing";
|
|
2983
|
-
|
|
2984
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
|
|
2985
|
-
import { Duplex } from "node:stream";
|
|
2986
|
-
import { Event as AsyncEvent } from "@dxos/async";
|
|
2987
|
-
import { Resource } from "@dxos/context";
|
|
2988
|
-
import { ErrorStream as ErrorStream4 } from "@dxos/debug";
|
|
2989
|
-
import { invariant as invariant11 } from "@dxos/invariant";
|
|
2990
|
-
import { log as log12 } from "@dxos/log";
|
|
2991
|
-
import { ConnectivityError as ConnectivityError2 } from "@dxos/protocols";
|
|
2992
|
-
|
|
2993
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-stats.ts
|
|
2994
|
-
var describeSelectedRemoteCandidate = async (connection) => {
|
|
2995
|
-
const stats = connection && await getRtcConnectionStats(connection);
|
|
2996
|
-
const rc = stats?.remoteCandidate;
|
|
2997
|
-
if (!rc) {
|
|
2998
|
-
return "unavailable";
|
|
2999
|
-
}
|
|
3000
|
-
if (rc.candidateType === "relay") {
|
|
3001
|
-
return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
|
|
3002
|
-
}
|
|
3003
|
-
return `${rc.ip}:${rc.port} ${rc.candidateType}`;
|
|
3004
|
-
};
|
|
3005
|
-
var createRtcTransportStats = async (connection, topic) => {
|
|
3006
|
-
const stats = connection && await getRtcConnectionStats(connection, topic);
|
|
3007
|
-
if (!stats) {
|
|
3008
|
-
return {
|
|
3009
|
-
bytesSent: 0,
|
|
3010
|
-
bytesReceived: 0,
|
|
3011
|
-
packetsSent: 0,
|
|
3012
|
-
packetsReceived: 0,
|
|
3013
|
-
rawStats: {}
|
|
3014
|
-
};
|
|
3015
|
-
}
|
|
3016
|
-
return {
|
|
3017
|
-
bytesSent: stats.dataChannel?.bytesSent,
|
|
3018
|
-
bytesReceived: stats.dataChannel?.bytesReceived,
|
|
3019
|
-
packetsSent: 0,
|
|
3020
|
-
packetsReceived: 0,
|
|
3021
|
-
rawStats: stats.raw
|
|
3022
|
-
};
|
|
3023
|
-
};
|
|
3024
|
-
var getRtcConnectionStats = async (connection, channelTopic) => {
|
|
3025
|
-
const stats = await connection.getStats();
|
|
3026
|
-
const statsEntries = Array.from(stats.entries());
|
|
3027
|
-
const transport = statsEntries.find(([_, entry]) => entry.type === "transport")?.[1];
|
|
3028
|
-
const selectedCandidatePair = transport && statsEntries.find(([entryId]) => entryId === transport.selectedCandidatePairId)?.[1];
|
|
3029
|
-
const remoteCandidate = selectedCandidatePair && statsEntries.find(([entryId]) => entryId === selectedCandidatePair.remoteCandidateId)?.[1];
|
|
3030
|
-
const dataChannel = channelTopic && statsEntries.find(([_, entry]) => entry.type === "data-channel" && entry.label === channelTopic)?.[1];
|
|
3031
|
-
return {
|
|
3032
|
-
transport,
|
|
3033
|
-
selectedCandidatePair,
|
|
3034
|
-
dataChannel,
|
|
3035
|
-
remoteCandidate,
|
|
3036
|
-
raw: Object.fromEntries(stats)
|
|
3037
|
-
};
|
|
3038
|
-
};
|
|
3039
|
-
|
|
3040
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
|
|
3041
|
-
var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts";
|
|
3042
|
-
var MAX_MESSAGE_SIZE = 64 * 1024;
|
|
3043
|
-
var MAX_BUFFERED_AMOUNT = 64 * 1024;
|
|
3044
|
-
var RtcTransportChannel = class extends Resource {
|
|
3045
|
-
constructor(_connection, _options) {
|
|
3046
|
-
super();
|
|
3047
|
-
this._connection = _connection;
|
|
3048
|
-
this._options = _options;
|
|
3049
|
-
this.closed = new AsyncEvent();
|
|
3050
|
-
this.connected = new AsyncEvent();
|
|
3051
|
-
this.errors = new ErrorStream4();
|
|
3052
|
-
this._streamDataFlushedCallback = null;
|
|
3053
|
-
this._isChannelCreationInProgress = false;
|
|
3054
|
-
}
|
|
3055
|
-
get isRtcChannelCreationInProgress() {
|
|
3056
|
-
return this._isChannelCreationInProgress;
|
|
3057
|
-
}
|
|
3058
|
-
onConnectionError(error) {
|
|
3059
|
-
if (this.isOpen) {
|
|
3060
|
-
this.errors.raise(error);
|
|
3061
|
-
}
|
|
3062
|
-
}
|
|
3063
|
-
async _open() {
|
|
3064
|
-
invariant11(!this._isChannelCreationInProgress, void 0, {
|
|
3065
|
-
F: __dxlog_file13,
|
|
3066
|
-
L: 56,
|
|
3067
|
-
S: this,
|
|
3068
|
-
A: [
|
|
3069
|
-
"!this._isChannelCreationInProgress",
|
|
3070
|
-
""
|
|
3071
|
-
]
|
|
3072
|
-
});
|
|
3073
|
-
this._isChannelCreationInProgress = true;
|
|
3074
|
-
this._connection.createDataChannel(this._options.topic).then((channel) => {
|
|
3075
|
-
if (this.isOpen) {
|
|
3076
|
-
this._channel = channel;
|
|
3077
|
-
this._initChannel(this._channel);
|
|
3078
|
-
} else {
|
|
3079
|
-
this._safeCloseChannel(channel);
|
|
3080
|
-
}
|
|
3081
|
-
}).catch((err) => {
|
|
3082
|
-
if (this.isOpen) {
|
|
3083
|
-
this.errors.raise(new ConnectivityError2(`Failed to create a channel: ${err?.message ?? "unknown reason."}`));
|
|
3084
|
-
}
|
|
3085
|
-
}).finally(() => {
|
|
3086
|
-
this._isChannelCreationInProgress = false;
|
|
3087
|
-
});
|
|
3088
|
-
}
|
|
3089
|
-
async _close() {
|
|
3090
|
-
if (this._channel) {
|
|
3091
|
-
this._safeCloseChannel(this._channel);
|
|
3092
|
-
this._channel = void 0;
|
|
3093
|
-
this._stream = void 0;
|
|
3094
|
-
}
|
|
3095
|
-
this.closed.emit();
|
|
3096
|
-
log12("closed", void 0, {
|
|
3097
|
-
F: __dxlog_file13,
|
|
3098
|
-
L: 86,
|
|
3099
|
-
S: this,
|
|
3100
|
-
C: (f, a) => f(...a)
|
|
3101
|
-
});
|
|
3102
|
-
}
|
|
3103
|
-
_initChannel(channel) {
|
|
3104
|
-
Object.assign(channel, {
|
|
3105
|
-
onopen: () => {
|
|
3106
|
-
if (!this.isOpen) {
|
|
3107
|
-
log12.warn("channel opened in a closed transport", {
|
|
3108
|
-
topic: this._options.topic
|
|
3109
|
-
}, {
|
|
3110
|
-
F: __dxlog_file13,
|
|
3111
|
-
L: 93,
|
|
3112
|
-
S: this,
|
|
3113
|
-
C: (f, a) => f(...a)
|
|
3114
|
-
});
|
|
3115
|
-
this._safeCloseChannel(channel);
|
|
3116
|
-
return;
|
|
3117
|
-
}
|
|
3118
|
-
log12("onopen", void 0, {
|
|
3119
|
-
F: __dxlog_file13,
|
|
3120
|
-
L: 98,
|
|
3121
|
-
S: this,
|
|
3122
|
-
C: (f, a) => f(...a)
|
|
3123
|
-
});
|
|
3124
|
-
const duplex = new Duplex({
|
|
3125
|
-
read: () => {
|
|
3126
|
-
},
|
|
3127
|
-
write: (chunk, encoding, callback) => {
|
|
3128
|
-
return this._handleChannelWrite(chunk, callback);
|
|
3129
|
-
}
|
|
3130
|
-
});
|
|
3131
|
-
duplex.pipe(this._options.stream).pipe(duplex);
|
|
3132
|
-
this._stream = duplex;
|
|
3133
|
-
this.connected.emit();
|
|
3134
|
-
},
|
|
3135
|
-
onclose: async () => {
|
|
3136
|
-
log12("onclose", void 0, {
|
|
3137
|
-
F: __dxlog_file13,
|
|
3138
|
-
L: 111,
|
|
3139
|
-
S: this,
|
|
3140
|
-
C: (f, a) => f(...a)
|
|
3141
|
-
});
|
|
3142
|
-
await this.close();
|
|
3143
|
-
},
|
|
3144
|
-
onmessage: (event) => {
|
|
3145
|
-
if (!this._stream) {
|
|
3146
|
-
log12.warn("ignoring message on a closed channel", void 0, {
|
|
3147
|
-
F: __dxlog_file13,
|
|
3148
|
-
L: 117,
|
|
3149
|
-
S: this,
|
|
3150
|
-
C: (f, a) => f(...a)
|
|
3151
|
-
});
|
|
3152
|
-
return;
|
|
3153
|
-
}
|
|
3154
|
-
let data = event.data;
|
|
3155
|
-
if (data instanceof ArrayBuffer) {
|
|
3156
|
-
data = Buffer.from(data);
|
|
3157
|
-
}
|
|
3158
|
-
this._stream.push(data);
|
|
3159
|
-
},
|
|
3160
|
-
onerror: (event) => {
|
|
3161
|
-
if (this.isOpen) {
|
|
3162
|
-
const err = event.error instanceof Error ? event.error : new Error(`Datachannel error: ${event.type}.`);
|
|
3163
|
-
this.errors.raise(err);
|
|
3164
|
-
}
|
|
3165
|
-
},
|
|
3166
|
-
onbufferedamountlow: () => {
|
|
3167
|
-
const cb = this._streamDataFlushedCallback;
|
|
3168
|
-
this._streamDataFlushedCallback = null;
|
|
3169
|
-
cb?.();
|
|
3170
|
-
}
|
|
3171
|
-
});
|
|
3172
|
-
}
|
|
3173
|
-
async _handleChannelWrite(chunk, callback) {
|
|
3174
|
-
if (!this._channel) {
|
|
3175
|
-
log12.warn("writing to a channel after a connection was closed", void 0, {
|
|
3176
|
-
F: __dxlog_file13,
|
|
3177
|
-
L: 145,
|
|
3178
|
-
S: this,
|
|
3179
|
-
C: (f, a) => f(...a)
|
|
3180
|
-
});
|
|
3181
|
-
return;
|
|
3182
|
-
}
|
|
3183
|
-
if (chunk.length > MAX_MESSAGE_SIZE) {
|
|
3184
|
-
const error = new Error(`Message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}.`);
|
|
3185
|
-
this.errors.raise(error);
|
|
3186
|
-
callback();
|
|
3187
|
-
return;
|
|
3188
|
-
}
|
|
3189
|
-
try {
|
|
3190
|
-
this._channel.send(chunk);
|
|
3191
|
-
} catch (err) {
|
|
3192
|
-
this.errors.raise(err);
|
|
3193
|
-
callback();
|
|
3194
|
-
return;
|
|
3195
|
-
}
|
|
3196
|
-
if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
|
|
3197
|
-
if (this._streamDataFlushedCallback !== null) {
|
|
3198
|
-
log12.error("consumer trying to write before we are ready for more data", void 0, {
|
|
3199
|
-
F: __dxlog_file13,
|
|
3200
|
-
L: 166,
|
|
3201
|
-
S: this,
|
|
3202
|
-
C: (f, a) => f(...a)
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
|
-
this._streamDataFlushedCallback = callback;
|
|
3206
|
-
} else {
|
|
3207
|
-
callback();
|
|
3208
|
-
}
|
|
3209
|
-
}
|
|
3210
|
-
_safeCloseChannel(channel) {
|
|
3211
|
-
try {
|
|
3212
|
-
channel.close();
|
|
3213
|
-
} catch (error) {
|
|
3214
|
-
log12.catch(error, void 0, {
|
|
3215
|
-
F: __dxlog_file13,
|
|
3216
|
-
L: 178,
|
|
3217
|
-
S: this,
|
|
3218
|
-
C: (f, a) => f(...a)
|
|
3219
|
-
});
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
onSignal(signal) {
|
|
3223
|
-
return this._connection.onSignal(signal);
|
|
3224
|
-
}
|
|
3225
|
-
async getDetails() {
|
|
3226
|
-
return describeSelectedRemoteCandidate(this._connection.currentConnection);
|
|
3227
|
-
}
|
|
3228
|
-
async getStats() {
|
|
3229
|
-
return createRtcTransportStats(this._connection.currentConnection, this._options.topic);
|
|
3230
|
-
}
|
|
3231
|
-
};
|
|
3232
|
-
|
|
3233
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/utils.ts
|
|
3234
|
-
var chooseInitiatorPeer = (peer1Key, peer2Key) => peer1Key < peer2Key ? peer1Key : peer2Key;
|
|
3235
|
-
var areSdpEqual = (sdp1, sdp2) => {
|
|
3236
|
-
const sdp1Lines = deduplicatedSdpLines(sdp1);
|
|
3237
|
-
const sdp2Lines = deduplicatedSdpLines(sdp2);
|
|
3238
|
-
if (sdp1Lines.length !== sdp2Lines.length) {
|
|
3239
|
-
return false;
|
|
3240
|
-
}
|
|
3241
|
-
return sdp1Lines.every((line, idx) => line === sdp2Lines[idx]);
|
|
3242
|
-
};
|
|
3243
|
-
var deduplicatedSdpLines = (sdp) => {
|
|
3244
|
-
const deduplicatedLines = [];
|
|
3245
|
-
const seenLines = [];
|
|
3246
|
-
for (const line of sdp.split("\r\n")) {
|
|
3247
|
-
if (line.startsWith("m")) {
|
|
3248
|
-
seenLines.length = 0;
|
|
3249
|
-
}
|
|
3250
|
-
if (seenLines.includes(line)) {
|
|
3251
|
-
continue;
|
|
3252
|
-
}
|
|
3253
|
-
seenLines.push(line);
|
|
3254
|
-
deduplicatedLines.push(line);
|
|
3255
|
-
}
|
|
3256
|
-
return deduplicatedLines;
|
|
3257
|
-
};
|
|
3258
|
-
|
|
3259
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
|
|
3260
|
-
function _ts_decorate6(decorators, target, key, desc) {
|
|
3261
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3262
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3263
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3264
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3265
|
-
}
|
|
3266
|
-
var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts";
|
|
3267
|
-
var RtcPeerConnection = class {
|
|
3268
|
-
constructor(_factory, _options) {
|
|
3269
|
-
this._factory = _factory;
|
|
3270
|
-
this._options = _options;
|
|
3271
|
-
this._channelCreatedCallbacks = /* @__PURE__ */ new Map();
|
|
3272
|
-
this._transportChannels = /* @__PURE__ */ new Map();
|
|
3273
|
-
this._dataChannels = /* @__PURE__ */ new Map();
|
|
3274
|
-
this._readyForCandidates = new Trigger3();
|
|
3275
|
-
this._offerProcessingMutex = new Mutex2();
|
|
3276
|
-
this._initiator = chooseInitiatorPeer(_options.ownPeerKey, _options.remotePeerKey) === _options.ownPeerKey;
|
|
3277
|
-
}
|
|
3278
|
-
get transportChannelCount() {
|
|
3279
|
-
return this._transportChannels.size;
|
|
3280
|
-
}
|
|
3281
|
-
get currentConnection() {
|
|
3282
|
-
return this._connection;
|
|
3283
|
-
}
|
|
3284
|
-
async createDataChannel(topic) {
|
|
3285
|
-
const connection = await this._openConnection();
|
|
3286
|
-
if (!this._transportChannels.has(topic)) {
|
|
3287
|
-
if (!this._transportChannels.size) {
|
|
3288
|
-
this._lockAndCloseConnection();
|
|
3289
|
-
}
|
|
3290
|
-
throw new Error("Transport closed while connection was being open");
|
|
3291
|
-
}
|
|
3292
|
-
if (this._initiator) {
|
|
3293
|
-
const channel = connection.createDataChannel(topic);
|
|
3294
|
-
this._dataChannels.set(topic, channel);
|
|
3295
|
-
return channel;
|
|
3296
|
-
} else {
|
|
3297
|
-
const existingChannel = this._dataChannels.get(topic);
|
|
3298
|
-
if (existingChannel) {
|
|
3299
|
-
return existingChannel;
|
|
3300
|
-
}
|
|
3301
|
-
log13("waiting for initiator-peer to open a data channel", void 0, {
|
|
3302
|
-
F: __dxlog_file14,
|
|
3303
|
-
L: 90,
|
|
3304
|
-
S: this,
|
|
3305
|
-
C: (f, a) => f(...a)
|
|
3306
|
-
});
|
|
3307
|
-
return new Promise((resolve, reject) => {
|
|
3308
|
-
this._channelCreatedCallbacks.set(topic, {
|
|
3309
|
-
resolve,
|
|
3310
|
-
reject
|
|
3311
|
-
});
|
|
3312
|
-
});
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
createTransportChannel(options) {
|
|
3316
|
-
const channel = new RtcTransportChannel(this, options);
|
|
3317
|
-
this._transportChannels.set(options.topic, channel);
|
|
3318
|
-
channel.closed.on(() => {
|
|
3319
|
-
this._transportChannels.delete(options.topic);
|
|
3320
|
-
if (this._transportChannels.size === 0) {
|
|
3321
|
-
this._lockAndCloseConnection();
|
|
3322
|
-
}
|
|
3323
|
-
});
|
|
3324
|
-
return channel;
|
|
3325
|
-
}
|
|
3326
|
-
async _openConnection() {
|
|
3327
|
-
if (this._connection) {
|
|
3328
|
-
return this._connection;
|
|
3329
|
-
}
|
|
3330
|
-
log13("initializing connection...", () => ({
|
|
3331
|
-
remotePeer: this._options.remotePeerKey
|
|
3332
|
-
}), {
|
|
3333
|
-
F: __dxlog_file14,
|
|
3334
|
-
L: 115,
|
|
3335
|
-
S: this,
|
|
3336
|
-
C: (f, a) => f(...a)
|
|
3337
|
-
});
|
|
3338
|
-
const config = await this._loadConnectionConfig();
|
|
3339
|
-
const connection = await this._factory.createConnection(config);
|
|
3340
|
-
const iceCandidateErrors = [];
|
|
3341
|
-
Object.assign(connection, {
|
|
3342
|
-
onnegotiationneeded: async () => {
|
|
3343
|
-
invariant12(this._initiator, void 0, {
|
|
3344
|
-
F: __dxlog_file14,
|
|
3345
|
-
L: 130,
|
|
3346
|
-
S: this,
|
|
3347
|
-
A: [
|
|
3348
|
-
"this._initiator",
|
|
3349
|
-
""
|
|
3350
|
-
]
|
|
3351
|
-
});
|
|
3352
|
-
if (connection !== this._connection) {
|
|
3353
|
-
this._onConnectionCallbackAfterClose("onnegotiationneeded", connection);
|
|
3354
|
-
return;
|
|
3355
|
-
}
|
|
3356
|
-
log13("onnegotiationneeded", void 0, {
|
|
3357
|
-
F: __dxlog_file14,
|
|
3358
|
-
L: 137,
|
|
3359
|
-
S: this,
|
|
3360
|
-
C: (f, a) => f(...a)
|
|
3361
|
-
});
|
|
3362
|
-
try {
|
|
3363
|
-
const offer = await connection.createOffer();
|
|
3364
|
-
await connection.setLocalDescription(offer);
|
|
3365
|
-
await this._sendDescription(connection, offer);
|
|
3366
|
-
} catch (err) {
|
|
3367
|
-
this._lockAndAbort(connection, err);
|
|
3368
|
-
}
|
|
3369
|
-
},
|
|
3370
|
-
// When ICE candidate identified (should be sent to remote peer) and when ICE gathering finalized.
|
|
3371
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidate_event
|
|
3372
|
-
onicecandidate: async (event) => {
|
|
3373
|
-
if (connection !== this._connection) {
|
|
3374
|
-
this._onConnectionCallbackAfterClose("onicecandidate", connection);
|
|
3375
|
-
return;
|
|
3376
|
-
}
|
|
3377
|
-
if (event.candidate) {
|
|
3378
|
-
log13("onicecandidate", {
|
|
3379
|
-
candidate: event.candidate.candidate
|
|
3380
|
-
}, {
|
|
3381
|
-
F: __dxlog_file14,
|
|
3382
|
-
L: 156,
|
|
3383
|
-
S: this,
|
|
3384
|
-
C: (f, a) => f(...a)
|
|
3385
|
-
});
|
|
3386
|
-
await this._sendIceCandidate(event.candidate);
|
|
3387
|
-
} else {
|
|
3388
|
-
log13("onicecandidate gathering complete", void 0, {
|
|
3389
|
-
F: __dxlog_file14,
|
|
3390
|
-
L: 159,
|
|
3391
|
-
S: this,
|
|
3392
|
-
C: (f, a) => f(...a)
|
|
3393
|
-
});
|
|
3394
|
-
}
|
|
3395
|
-
},
|
|
3396
|
-
// When error occurs while performing ICE negotiations through a STUN or TURN server.
|
|
3397
|
-
// It's ok for some candidates to fail if a working pair is eventually found.
|
|
3398
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidateerror_event
|
|
3399
|
-
onicecandidateerror: (event) => {
|
|
3400
|
-
const { url, errorCode, errorText } = event;
|
|
3401
|
-
iceCandidateErrors.push({
|
|
3402
|
-
url,
|
|
3403
|
-
errorCode,
|
|
3404
|
-
errorText
|
|
3405
|
-
});
|
|
3406
|
-
},
|
|
3407
|
-
// When possible error during ICE gathering.
|
|
3408
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceconnectionstatechange_event
|
|
3409
|
-
oniceconnectionstatechange: () => {
|
|
3410
|
-
if (connection !== this._connection) {
|
|
3411
|
-
this._onConnectionCallbackAfterClose("oniceconnectionstatechange", connection);
|
|
3412
|
-
return;
|
|
3413
|
-
}
|
|
3414
|
-
log13("oniceconnectionstatechange", {
|
|
3415
|
-
state: connection.iceConnectionState
|
|
3416
|
-
}, {
|
|
3417
|
-
F: __dxlog_file14,
|
|
3418
|
-
L: 179,
|
|
3419
|
-
S: this,
|
|
3420
|
-
C: (f, a) => f(...a)
|
|
3421
|
-
});
|
|
3422
|
-
if (connection.iceConnectionState === "failed") {
|
|
3423
|
-
this._lockAndAbort(connection, createIceFailureError(iceCandidateErrors));
|
|
3424
|
-
}
|
|
3425
|
-
},
|
|
3426
|
-
// When new track (or channel) is added.
|
|
3427
|
-
// State: { new, connecting, connected, disconnected, failed, closed }
|
|
3428
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionstatechange_event
|
|
3429
|
-
onconnectionstatechange: () => {
|
|
3430
|
-
if (connection !== this._connection) {
|
|
3431
|
-
if (connection.connectionState !== "closed" && connection.connectionState !== "failed") {
|
|
3432
|
-
this._onConnectionCallbackAfterClose("onconnectionstatechange", connection);
|
|
3433
|
-
}
|
|
3434
|
-
return;
|
|
3435
|
-
}
|
|
3436
|
-
log13("onconnectionstatechange", {
|
|
3437
|
-
state: connection.connectionState
|
|
3438
|
-
}, {
|
|
3439
|
-
F: __dxlog_file14,
|
|
3440
|
-
L: 196,
|
|
3441
|
-
S: this,
|
|
3442
|
-
C: (f, a) => f(...a)
|
|
3443
|
-
});
|
|
3444
|
-
if (connection.connectionState === "failed") {
|
|
3445
|
-
this._lockAndAbort(connection, new Error("Connection failed."));
|
|
3446
|
-
}
|
|
3447
|
-
},
|
|
3448
|
-
onsignalingstatechange: () => {
|
|
3449
|
-
log13("onsignalingstatechange", {
|
|
3450
|
-
state: connection.signalingState
|
|
3451
|
-
}, {
|
|
3452
|
-
F: __dxlog_file14,
|
|
3453
|
-
L: 203,
|
|
3454
|
-
S: this,
|
|
3455
|
-
C: (f, a) => f(...a)
|
|
3456
|
-
});
|
|
3457
|
-
},
|
|
3458
|
-
// When channel is added to connection.
|
|
3459
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event
|
|
3460
|
-
ondatachannel: (event) => {
|
|
3461
|
-
invariant12(!this._initiator, "Initiator is expected to create data channels.", {
|
|
3462
|
-
F: __dxlog_file14,
|
|
3463
|
-
L: 209,
|
|
3464
|
-
S: this,
|
|
3465
|
-
A: [
|
|
3466
|
-
"!this._initiator",
|
|
3467
|
-
"'Initiator is expected to create data channels.'"
|
|
3468
|
-
]
|
|
3469
|
-
});
|
|
3470
|
-
if (connection !== this._connection) {
|
|
3471
|
-
this._onConnectionCallbackAfterClose("ondatachannel", connection);
|
|
3472
|
-
return;
|
|
3473
|
-
}
|
|
3474
|
-
log13("ondatachannel", {
|
|
3475
|
-
label: event.channel.label
|
|
3476
|
-
}, {
|
|
3477
|
-
F: __dxlog_file14,
|
|
3478
|
-
L: 216,
|
|
3479
|
-
S: this,
|
|
3480
|
-
C: (f, a) => f(...a)
|
|
3481
|
-
});
|
|
3482
|
-
this._dataChannels.set(event.channel.label, event.channel);
|
|
3483
|
-
const pendingCallback = this._channelCreatedCallbacks.get(event.channel.label);
|
|
3484
|
-
if (pendingCallback) {
|
|
3485
|
-
this._channelCreatedCallbacks.delete(event.channel.label);
|
|
3486
|
-
pendingCallback.resolve(event.channel);
|
|
3487
|
-
}
|
|
3488
|
-
}
|
|
3489
|
-
});
|
|
3490
|
-
this._connection = connection;
|
|
3491
|
-
this._readyForCandidates.reset();
|
|
3492
|
-
await this._factory.initConnection(connection, {
|
|
3493
|
-
initiator: this._initiator
|
|
3494
|
-
});
|
|
3495
|
-
return this._connection;
|
|
3496
|
-
}
|
|
3497
|
-
_lockAndAbort(connection, error) {
|
|
3498
|
-
this._abortConnection(connection, error);
|
|
3499
|
-
}
|
|
3500
|
-
_abortConnection(connection, error) {
|
|
3501
|
-
if (connection !== this._connection) {
|
|
3502
|
-
log13.error("attempted to abort an inactive connection", {
|
|
3503
|
-
error
|
|
3504
|
-
}, {
|
|
3505
|
-
F: __dxlog_file14,
|
|
3506
|
-
L: 241,
|
|
3507
|
-
S: this,
|
|
3508
|
-
C: (f, a) => f(...a)
|
|
3509
|
-
});
|
|
3510
|
-
this._safeCloseConnection(connection);
|
|
3511
|
-
return;
|
|
3512
|
-
}
|
|
3513
|
-
for (const [topic, pendingCallback] of this._channelCreatedCallbacks.entries()) {
|
|
3514
|
-
pendingCallback.reject(error);
|
|
3515
|
-
this._transportChannels.delete(topic);
|
|
3516
|
-
}
|
|
3517
|
-
this._channelCreatedCallbacks.clear();
|
|
3518
|
-
for (const channel of this._transportChannels.values()) {
|
|
3519
|
-
channel.onConnectionError(error);
|
|
3520
|
-
}
|
|
3521
|
-
this._transportChannels.clear();
|
|
3522
|
-
this._safeCloseConnection();
|
|
3523
|
-
log13("connection aborted", {
|
|
3524
|
-
reason: error.message
|
|
3525
|
-
}, {
|
|
3526
|
-
F: __dxlog_file14,
|
|
3527
|
-
L: 255,
|
|
3528
|
-
S: this,
|
|
3529
|
-
C: (f, a) => f(...a)
|
|
3530
|
-
});
|
|
3531
|
-
}
|
|
3532
|
-
_lockAndCloseConnection() {
|
|
3533
|
-
invariant12(this._transportChannels.size === 0, void 0, {
|
|
3534
|
-
F: __dxlog_file14,
|
|
3535
|
-
L: 260,
|
|
3536
|
-
S: this,
|
|
3537
|
-
A: [
|
|
3538
|
-
"this._transportChannels.size === 0",
|
|
3539
|
-
""
|
|
3540
|
-
]
|
|
3541
|
-
});
|
|
3542
|
-
if (this._connection) {
|
|
3543
|
-
this._safeCloseConnection();
|
|
3544
|
-
log13("connection closed", void 0, {
|
|
3545
|
-
F: __dxlog_file14,
|
|
3546
|
-
L: 263,
|
|
3547
|
-
S: this,
|
|
3548
|
-
C: (f, a) => f(...a)
|
|
3549
|
-
});
|
|
3550
|
-
}
|
|
3551
|
-
}
|
|
3552
|
-
async onSignal(signal) {
|
|
3553
|
-
const connection = this._connection;
|
|
3554
|
-
if (!connection) {
|
|
3555
|
-
log13.warn("a signal ignored because the connection was closed", {
|
|
3556
|
-
type: signal.payload.data.type
|
|
3557
|
-
}, {
|
|
3558
|
-
F: __dxlog_file14,
|
|
3559
|
-
L: 271,
|
|
3560
|
-
S: this,
|
|
3561
|
-
C: (f, a) => f(...a)
|
|
3562
|
-
});
|
|
3563
|
-
return;
|
|
3564
|
-
}
|
|
3565
|
-
const data = signal.payload.data;
|
|
3566
|
-
switch (data.type) {
|
|
3567
|
-
case "offer": {
|
|
3568
|
-
await this._offerProcessingMutex.executeSynchronized(async () => {
|
|
3569
|
-
if (isRemoteDescriptionSet(connection, data)) {
|
|
3570
|
-
return;
|
|
3571
|
-
}
|
|
3572
|
-
if (connection.connectionState !== "new") {
|
|
3573
|
-
this._abortConnection(connection, new Error(`Received an offer in ${connection.connectionState}.`));
|
|
3574
|
-
return;
|
|
3575
|
-
}
|
|
3576
|
-
try {
|
|
3577
|
-
await connection.setRemoteDescription({
|
|
3578
|
-
type: data.type,
|
|
3579
|
-
sdp: data.sdp
|
|
3580
|
-
});
|
|
3581
|
-
const answer = await connection.createAnswer();
|
|
3582
|
-
await connection.setLocalDescription(answer);
|
|
3583
|
-
await this._sendDescription(connection, answer);
|
|
3584
|
-
this._onSessionNegotiated(connection);
|
|
3585
|
-
} catch (err) {
|
|
3586
|
-
this._abortConnection(connection, new Error("Error handling a remote offer.", {
|
|
3587
|
-
cause: err
|
|
3588
|
-
}));
|
|
3589
|
-
}
|
|
3590
|
-
});
|
|
3591
|
-
break;
|
|
3592
|
-
}
|
|
3593
|
-
case "answer":
|
|
3594
|
-
await this._offerProcessingMutex.executeSynchronized(async () => {
|
|
3595
|
-
try {
|
|
3596
|
-
if (isRemoteDescriptionSet(connection, data)) {
|
|
3597
|
-
return;
|
|
3598
|
-
}
|
|
3599
|
-
if (connection.signalingState !== "have-local-offer") {
|
|
3600
|
-
this._abortConnection(connection, new Error(`Unexpected answer from remote peer, signalingState was ${connection.signalingState}.`));
|
|
3601
|
-
return;
|
|
3602
|
-
}
|
|
3603
|
-
await connection.setRemoteDescription({
|
|
3604
|
-
type: data.type,
|
|
3605
|
-
sdp: data.sdp
|
|
3606
|
-
});
|
|
3607
|
-
this._onSessionNegotiated(connection);
|
|
3608
|
-
} catch (err) {
|
|
3609
|
-
this._abortConnection(connection, new Error("Error handling a remote answer.", {
|
|
3610
|
-
cause: err
|
|
3611
|
-
}));
|
|
3612
|
-
}
|
|
3613
|
-
});
|
|
3614
|
-
break;
|
|
3615
|
-
case "candidate":
|
|
3616
|
-
void this._processIceCandidate(connection, data.candidate);
|
|
3617
|
-
break;
|
|
3618
|
-
default:
|
|
3619
|
-
this._abortConnection(connection, new Error(`Unknown signal type ${data.type}.`));
|
|
3620
|
-
break;
|
|
3621
|
-
}
|
|
3622
|
-
log13("signal processed", void 0, {
|
|
3623
|
-
F: __dxlog_file14,
|
|
3624
|
-
L: 330,
|
|
3625
|
-
S: this,
|
|
3626
|
-
C: (f, a) => f(...a)
|
|
3627
|
-
});
|
|
3628
|
-
}
|
|
3629
|
-
async _processIceCandidate(connection, candidate) {
|
|
3630
|
-
try {
|
|
3631
|
-
await this._readyForCandidates.wait();
|
|
3632
|
-
if (connection === this._connection) {
|
|
3633
|
-
log13("adding ice candidate", {
|
|
3634
|
-
candidate
|
|
3635
|
-
}, {
|
|
3636
|
-
F: __dxlog_file14,
|
|
3637
|
-
L: 338,
|
|
3638
|
-
S: this,
|
|
3639
|
-
C: (f, a) => f(...a)
|
|
3640
|
-
});
|
|
3641
|
-
await connection.addIceCandidate(candidate);
|
|
3642
|
-
}
|
|
3643
|
-
} catch (err) {
|
|
3644
|
-
log13.catch(err, void 0, {
|
|
3645
|
-
F: __dxlog_file14,
|
|
3646
|
-
L: 342,
|
|
3647
|
-
S: this,
|
|
3648
|
-
C: (f, a) => f(...a)
|
|
3649
|
-
});
|
|
3650
|
-
}
|
|
3651
|
-
}
|
|
3652
|
-
_onSessionNegotiated(connection) {
|
|
3653
|
-
if (connection === this._connection) {
|
|
3654
|
-
log13("ready to process ice candidates", void 0, {
|
|
3655
|
-
F: __dxlog_file14,
|
|
3656
|
-
L: 348,
|
|
3657
|
-
S: this,
|
|
3658
|
-
C: (f, a) => f(...a)
|
|
3659
|
-
});
|
|
3660
|
-
this._readyForCandidates.wake();
|
|
3661
|
-
} else {
|
|
3662
|
-
log13.warn("session was negotiated after connection became inactive", void 0, {
|
|
3663
|
-
F: __dxlog_file14,
|
|
3664
|
-
L: 351,
|
|
3665
|
-
S: this,
|
|
3666
|
-
C: (f, a) => f(...a)
|
|
3667
|
-
});
|
|
3668
|
-
}
|
|
3669
|
-
}
|
|
3670
|
-
_onConnectionCallbackAfterClose(callback, connection) {
|
|
3671
|
-
log13.warn("callback invoked after a connection was destroyed, this is probably a bug", {
|
|
3672
|
-
callback,
|
|
3673
|
-
state: connection.connectionState
|
|
3674
|
-
}, {
|
|
3675
|
-
F: __dxlog_file14,
|
|
3676
|
-
L: 356,
|
|
3677
|
-
S: this,
|
|
3678
|
-
C: (f, a) => f(...a)
|
|
3679
|
-
});
|
|
3680
|
-
this._safeCloseConnection(connection);
|
|
3681
|
-
}
|
|
3682
|
-
_safeCloseConnection(connection = this._connection) {
|
|
3683
|
-
const resetFields = this._connection && connection === this._connection;
|
|
3684
|
-
try {
|
|
3685
|
-
connection?.close();
|
|
3686
|
-
} catch (err) {
|
|
3687
|
-
log13.catch(err, void 0, {
|
|
3688
|
-
F: __dxlog_file14,
|
|
3689
|
-
L: 368,
|
|
3690
|
-
S: this,
|
|
3691
|
-
C: (f, a) => f(...a)
|
|
3692
|
-
});
|
|
3693
|
-
}
|
|
3694
|
-
if (resetFields) {
|
|
3695
|
-
this._connection = void 0;
|
|
3696
|
-
this._dataChannels.clear();
|
|
3697
|
-
this._readyForCandidates.wake();
|
|
3698
|
-
void this._factory.onConnectionDestroyed().catch((err) => log13.catch(err, void 0, {
|
|
3699
|
-
F: __dxlog_file14,
|
|
3700
|
-
L: 374,
|
|
3701
|
-
S: this,
|
|
3702
|
-
C: (f, a) => f(...a)
|
|
3703
|
-
}));
|
|
3704
|
-
for (const [_, pendingCallback] of this._channelCreatedCallbacks.entries()) {
|
|
3705
|
-
pendingCallback.reject("Connection closed.");
|
|
3706
|
-
}
|
|
3707
|
-
this._channelCreatedCallbacks.clear();
|
|
3708
|
-
}
|
|
3709
|
-
}
|
|
3710
|
-
async _loadConnectionConfig() {
|
|
3711
|
-
const config = {
|
|
3712
|
-
...this._options.webrtcConfig
|
|
3713
|
-
};
|
|
3714
|
-
try {
|
|
3715
|
-
const providedIceServers = await this._options.iceProvider?.getIceServers() ?? [];
|
|
3716
|
-
if (providedIceServers.length > 0) {
|
|
3717
|
-
config.iceServers = [
|
|
3718
|
-
...config.iceServers ?? [],
|
|
3719
|
-
...providedIceServers
|
|
3720
|
-
];
|
|
3721
|
-
}
|
|
3722
|
-
} catch (error) {
|
|
3723
|
-
log13.catch(error, void 0, {
|
|
3724
|
-
F: __dxlog_file14,
|
|
3725
|
-
L: 390,
|
|
3726
|
-
S: this,
|
|
3727
|
-
C: (f, a) => f(...a)
|
|
3728
|
-
});
|
|
3729
|
-
}
|
|
3730
|
-
return config;
|
|
3731
|
-
}
|
|
3732
|
-
async _sendIceCandidate(candidate) {
|
|
3733
|
-
try {
|
|
3734
|
-
await this._options.sendSignal({
|
|
3735
|
-
payload: {
|
|
3736
|
-
data: {
|
|
3737
|
-
type: "candidate",
|
|
3738
|
-
candidate: {
|
|
3739
|
-
candidate: candidate.candidate,
|
|
3740
|
-
// These fields never seem to be not null, but connecting to Chrome doesn't work if they are.
|
|
3741
|
-
sdpMLineIndex: candidate.sdpMLineIndex ?? "0",
|
|
3742
|
-
sdpMid: candidate.sdpMid ?? "0"
|
|
3743
|
-
}
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
});
|
|
3747
|
-
} catch (err) {
|
|
3748
|
-
log13.warn("signaling error", {
|
|
3749
|
-
err
|
|
3750
|
-
}, {
|
|
3751
|
-
F: __dxlog_file14,
|
|
3752
|
-
L: 411,
|
|
3753
|
-
S: this,
|
|
3754
|
-
C: (f, a) => f(...a)
|
|
3755
|
-
});
|
|
3756
|
-
}
|
|
3757
|
-
}
|
|
3758
|
-
async _sendDescription(connection, description) {
|
|
3759
|
-
if (connection !== this._connection) {
|
|
3760
|
-
return;
|
|
3761
|
-
}
|
|
3762
|
-
const data = {
|
|
3763
|
-
type: description.type,
|
|
3764
|
-
sdp: description.sdp
|
|
3765
|
-
};
|
|
3766
|
-
await this._options.sendSignal({
|
|
3767
|
-
payload: {
|
|
3768
|
-
data
|
|
3769
|
-
}
|
|
3770
|
-
});
|
|
3771
|
-
}
|
|
3772
|
-
get _connectionInfo() {
|
|
3773
|
-
const connectionInfo = this._connection && {
|
|
3774
|
-
connectionState: this._connection.connectionState,
|
|
3775
|
-
iceConnectionState: this._connection.iceConnectionState,
|
|
3776
|
-
iceGatheringState: this._connection.iceGatheringState,
|
|
3777
|
-
signalingState: this._connection.signalingState,
|
|
3778
|
-
remoteDescription: this._connection.remoteDescription,
|
|
3779
|
-
localDescription: this._connection.localDescription
|
|
3780
|
-
};
|
|
3781
|
-
return {
|
|
3782
|
-
...connectionInfo,
|
|
3783
|
-
ts: Date.now(),
|
|
3784
|
-
remotePeerKey: this._options.remotePeerKey,
|
|
3785
|
-
channels: [
|
|
3786
|
-
...this._transportChannels.keys()
|
|
3787
|
-
].map((topic) => topic),
|
|
3788
|
-
config: this._connection?.getConfiguration()
|
|
3789
|
-
};
|
|
3790
|
-
}
|
|
3791
|
-
get _loggerContext() {
|
|
3792
|
-
return {
|
|
3793
|
-
ownPeerKey: this._options.ownPeerKey,
|
|
3794
|
-
remotePeerKey: this._options.remotePeerKey,
|
|
3795
|
-
initiator: this._initiator,
|
|
3796
|
-
channels: this._transportChannels.size
|
|
3797
|
-
};
|
|
3798
|
-
}
|
|
3799
|
-
};
|
|
3800
|
-
_ts_decorate6([
|
|
3801
|
-
synchronized5
|
|
3802
|
-
], RtcPeerConnection.prototype, "_openConnection", null);
|
|
3803
|
-
_ts_decorate6([
|
|
3804
|
-
synchronized5
|
|
3805
|
-
], RtcPeerConnection.prototype, "_lockAndAbort", null);
|
|
3806
|
-
_ts_decorate6([
|
|
3807
|
-
synchronized5
|
|
3808
|
-
], RtcPeerConnection.prototype, "_lockAndCloseConnection", null);
|
|
3809
|
-
_ts_decorate6([
|
|
3810
|
-
synchronized5
|
|
3811
|
-
], RtcPeerConnection.prototype, "onSignal", null);
|
|
3812
|
-
_ts_decorate6([
|
|
3813
|
-
trace4.info()
|
|
3814
|
-
], RtcPeerConnection.prototype, "_connectionInfo", null);
|
|
3815
|
-
_ts_decorate6([
|
|
3816
|
-
logInfo4
|
|
3817
|
-
], RtcPeerConnection.prototype, "_loggerContext", null);
|
|
3818
|
-
RtcPeerConnection = _ts_decorate6([
|
|
3819
|
-
trace4.resource()
|
|
3820
|
-
], RtcPeerConnection);
|
|
3821
|
-
var isRemoteDescriptionSet = (connection, data) => {
|
|
3822
|
-
if (!connection.remoteDescription?.type || connection.remoteDescription?.type !== data.type) {
|
|
3823
|
-
return false;
|
|
3824
|
-
}
|
|
3825
|
-
return areSdpEqual(connection.remoteDescription.sdp, data.sdp);
|
|
3826
|
-
};
|
|
3827
|
-
var createIceFailureError = (details) => {
|
|
3828
|
-
const candidateErrors = details.map(({ url, errorCode, errorText }) => `${errorCode} ${url}: ${errorText}`);
|
|
3829
|
-
return new ConnectivityError3(`ICE failed:
|
|
3830
|
-
${candidateErrors.join("\n")}`);
|
|
3831
|
-
};
|
|
3832
|
-
|
|
3833
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-factory.ts
|
|
3834
|
-
var createRtcTransportFactory = (webrtcConfig, iceProvider) => {
|
|
3835
|
-
const connectionFactory = getRtcConnectionFactory();
|
|
3836
|
-
return {
|
|
3837
|
-
createTransport: (options) => {
|
|
3838
|
-
const connection = new RtcPeerConnection(connectionFactory, {
|
|
3839
|
-
ownPeerKey: options.ownPeerKey,
|
|
3840
|
-
remotePeerKey: options.remotePeerKey,
|
|
3841
|
-
sendSignal: options.sendSignal,
|
|
3842
|
-
webrtcConfig,
|
|
3843
|
-
iceProvider
|
|
3844
|
-
});
|
|
3845
|
-
return connection.createTransportChannel(options);
|
|
3846
|
-
}
|
|
3847
|
-
};
|
|
3848
|
-
};
|
|
3849
|
-
|
|
3850
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts
|
|
3851
|
-
import { Writable } from "node:stream";
|
|
3852
|
-
import { Event as Event8, scheduleTask as scheduleTask4 } from "@dxos/async";
|
|
3853
|
-
import { Resource as Resource2 } from "@dxos/context";
|
|
3854
|
-
import { ErrorStream as ErrorStream5 } from "@dxos/debug";
|
|
3855
|
-
import { invariant as invariant13 } from "@dxos/invariant";
|
|
3856
|
-
import { PublicKey as PublicKey10 } from "@dxos/keys";
|
|
3857
|
-
import { log as log14 } from "@dxos/log";
|
|
3858
|
-
import { ConnectionResetError as ConnectionResetError2, ConnectivityError as ConnectivityError4, TimeoutError as TimeoutError3 } from "@dxos/protocols";
|
|
3859
|
-
import { ConnectionState as ConnectionState3 } from "@dxos/protocols/proto/dxos/mesh/bridge";
|
|
3860
|
-
import { arrayToBuffer } from "@dxos/util";
|
|
3861
|
-
var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts";
|
|
3862
|
-
var RPC_TIMEOUT = 1e4;
|
|
3863
|
-
var CLOSE_RPC_TIMEOUT = 3e3;
|
|
3864
|
-
var RESP_MIN_THRESHOLD = 500;
|
|
3865
|
-
var RtcTransportProxy = class extends Resource2 {
|
|
3866
|
-
constructor(_options) {
|
|
3867
|
-
super();
|
|
3868
|
-
this._options = _options;
|
|
3869
|
-
this._proxyId = PublicKey10.random();
|
|
3870
|
-
this.closed = new Event8();
|
|
3871
|
-
this.connected = new Event8();
|
|
3872
|
-
this.errors = new ErrorStream5();
|
|
3873
|
-
}
|
|
3874
|
-
async _open() {
|
|
3875
|
-
let stream;
|
|
3876
|
-
try {
|
|
3877
|
-
stream = this._options.bridgeService.open({
|
|
3878
|
-
proxyId: this._proxyId,
|
|
3879
|
-
remotePeerKey: this._options.remotePeerKey,
|
|
3880
|
-
ownPeerKey: this._options.ownPeerKey,
|
|
3881
|
-
topic: this._options.topic,
|
|
3882
|
-
initiator: this._options.initiator ?? false
|
|
3883
|
-
}, {
|
|
3884
|
-
timeout: RPC_TIMEOUT
|
|
3885
|
-
});
|
|
3886
|
-
} catch (error) {
|
|
3887
|
-
this.errors.raise(error);
|
|
3888
|
-
return;
|
|
3889
|
-
}
|
|
3890
|
-
this._serviceStream = stream;
|
|
3891
|
-
stream.waitUntilReady().then(() => {
|
|
3892
|
-
stream.subscribe(async (event) => {
|
|
3893
|
-
log14("rtc transport proxy event", event, {
|
|
3894
|
-
F: __dxlog_file15,
|
|
3895
|
-
L: 66,
|
|
3896
|
-
S: this,
|
|
3897
|
-
C: (f, a) => f(...a)
|
|
3898
|
-
});
|
|
3899
|
-
if (event.connection) {
|
|
3900
|
-
await this._handleConnection(event.connection);
|
|
3901
|
-
} else if (event.data) {
|
|
3902
|
-
this._handleData(event.data);
|
|
3903
|
-
} else if (event.signal) {
|
|
3904
|
-
await this._handleSignal(event.signal);
|
|
3905
|
-
}
|
|
3906
|
-
}, (err) => {
|
|
3907
|
-
log14("rtc bridge stream closed", {
|
|
3908
|
-
err
|
|
3909
|
-
}, {
|
|
3910
|
-
F: __dxlog_file15,
|
|
3911
|
-
L: 76,
|
|
3912
|
-
S: this,
|
|
3913
|
-
C: (f, a) => f(...a)
|
|
3914
|
-
});
|
|
3915
|
-
if (err) {
|
|
3916
|
-
this._raiseIfOpen(err);
|
|
3917
|
-
} else {
|
|
3918
|
-
void this.close();
|
|
3919
|
-
}
|
|
3920
|
-
});
|
|
3921
|
-
const connectorStream = new Writable({
|
|
3922
|
-
write: (chunk, _, callback) => {
|
|
3923
|
-
const sendStartMs = Date.now();
|
|
3924
|
-
this._options.bridgeService.sendData({
|
|
3925
|
-
proxyId: this._proxyId,
|
|
3926
|
-
payload: chunk
|
|
3927
|
-
}, {
|
|
3928
|
-
timeout: RPC_TIMEOUT
|
|
3929
|
-
}).then(() => {
|
|
3930
|
-
if (Date.now() - sendStartMs > RESP_MIN_THRESHOLD) {
|
|
3931
|
-
log14("slow response, delaying callback", void 0, {
|
|
3932
|
-
F: __dxlog_file15,
|
|
3933
|
-
L: 93,
|
|
3934
|
-
S: this,
|
|
3935
|
-
C: (f, a) => f(...a)
|
|
3936
|
-
});
|
|
3937
|
-
scheduleTask4(this._ctx, () => callback(), RESP_MIN_THRESHOLD);
|
|
3938
|
-
} else {
|
|
3939
|
-
callback();
|
|
3940
|
-
}
|
|
3941
|
-
}, (err) => {
|
|
3942
|
-
callback();
|
|
3943
|
-
this._raiseIfOpen(err);
|
|
3944
|
-
});
|
|
3945
|
-
}
|
|
3946
|
-
});
|
|
3947
|
-
connectorStream.on("error", (err) => {
|
|
3948
|
-
this._raiseIfOpen(err);
|
|
3949
|
-
});
|
|
3950
|
-
this._options.stream.pipe(connectorStream);
|
|
3951
|
-
}, (error) => {
|
|
3952
|
-
if (error) {
|
|
3953
|
-
this._raiseIfOpen(error);
|
|
3954
|
-
} else {
|
|
3955
|
-
void this.close();
|
|
3956
|
-
}
|
|
3957
|
-
});
|
|
3958
|
-
}
|
|
3959
|
-
async _close() {
|
|
3960
|
-
try {
|
|
3961
|
-
await this._serviceStream?.close();
|
|
3962
|
-
this._serviceStream = void 0;
|
|
3963
|
-
} catch (err) {
|
|
3964
|
-
log14.catch(err, void 0, {
|
|
3965
|
-
F: __dxlog_file15,
|
|
3966
|
-
L: 128,
|
|
3967
|
-
S: this,
|
|
3968
|
-
C: (f, a) => f(...a)
|
|
3969
|
-
});
|
|
3970
|
-
}
|
|
3971
|
-
try {
|
|
3972
|
-
await this._options.bridgeService.close({
|
|
3973
|
-
proxyId: this._proxyId
|
|
3974
|
-
}, {
|
|
3975
|
-
timeout: CLOSE_RPC_TIMEOUT
|
|
3976
|
-
});
|
|
3977
|
-
} catch (err) {
|
|
3978
|
-
log14.catch(err, void 0, {
|
|
3979
|
-
F: __dxlog_file15,
|
|
3980
|
-
L: 134,
|
|
3981
|
-
S: this,
|
|
3982
|
-
C: (f, a) => f(...a)
|
|
3983
|
-
});
|
|
3984
|
-
}
|
|
3985
|
-
this.closed.emit();
|
|
3986
|
-
}
|
|
3987
|
-
async onSignal(signal) {
|
|
3988
|
-
this._options.bridgeService.sendSignal({
|
|
3989
|
-
proxyId: this._proxyId,
|
|
3990
|
-
signal
|
|
3991
|
-
}, {
|
|
3992
|
-
timeout: RPC_TIMEOUT
|
|
3993
|
-
}).catch((err) => this._raiseIfOpen(decodeError(err)));
|
|
3994
|
-
}
|
|
3995
|
-
async _handleConnection(connectionEvent) {
|
|
3996
|
-
if (connectionEvent.error) {
|
|
3997
|
-
this.errors.raise(decodeError(connectionEvent.error));
|
|
3998
|
-
return;
|
|
3999
|
-
}
|
|
4000
|
-
switch (connectionEvent.state) {
|
|
4001
|
-
case ConnectionState3.CONNECTED: {
|
|
4002
|
-
this.connected.emit();
|
|
4003
|
-
break;
|
|
4004
|
-
}
|
|
4005
|
-
case ConnectionState3.CLOSED: {
|
|
4006
|
-
await this.close();
|
|
4007
|
-
break;
|
|
4008
|
-
}
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
_handleData(dataEvent) {
|
|
4012
|
-
try {
|
|
4013
|
-
this._options.stream.write(arrayToBuffer(dataEvent.payload));
|
|
4014
|
-
} catch (error) {
|
|
4015
|
-
this._raiseIfOpen(error);
|
|
4016
|
-
}
|
|
4017
|
-
}
|
|
4018
|
-
async _handleSignal(signalEvent) {
|
|
4019
|
-
try {
|
|
4020
|
-
await this._options.sendSignal(signalEvent.payload);
|
|
4021
|
-
} catch (error) {
|
|
4022
|
-
const type = signalEvent.payload.payload.data?.type;
|
|
4023
|
-
if (type === "offer" || type === "answer") {
|
|
4024
|
-
this._raiseIfOpen(new ConnectivityError4(`Session establishment failed: ${type} couldn't be sent.`));
|
|
4025
|
-
}
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
async getDetails() {
|
|
4029
|
-
try {
|
|
4030
|
-
const response = await this._options.bridgeService.getDetails({
|
|
4031
|
-
proxyId: this._proxyId
|
|
4032
|
-
}, {
|
|
4033
|
-
timeout: RPC_TIMEOUT
|
|
4034
|
-
});
|
|
4035
|
-
return response.details;
|
|
4036
|
-
} catch (err) {
|
|
4037
|
-
return "bridge-svc unreachable";
|
|
4038
|
-
}
|
|
4039
|
-
}
|
|
4040
|
-
async getStats() {
|
|
4041
|
-
try {
|
|
4042
|
-
const response = await this._options.bridgeService.getStats({
|
|
4043
|
-
proxyId: this._proxyId
|
|
4044
|
-
}, {
|
|
4045
|
-
timeout: RPC_TIMEOUT
|
|
4046
|
-
});
|
|
4047
|
-
return response.stats;
|
|
4048
|
-
} catch (err) {
|
|
4049
|
-
return {
|
|
4050
|
-
bytesSent: 0,
|
|
4051
|
-
bytesReceived: 0,
|
|
4052
|
-
packetsSent: 0,
|
|
4053
|
-
packetsReceived: 0,
|
|
4054
|
-
rawStats: "bridge-svc unreachable"
|
|
4055
|
-
};
|
|
4056
|
-
}
|
|
4057
|
-
}
|
|
4058
|
-
_raiseIfOpen(error) {
|
|
4059
|
-
if (this.isOpen) {
|
|
4060
|
-
this.errors.raise(error);
|
|
4061
|
-
} else {
|
|
4062
|
-
log14.info("error swallowed because transport was closed", {
|
|
4063
|
-
message: error.message
|
|
4064
|
-
}, {
|
|
4065
|
-
F: __dxlog_file15,
|
|
4066
|
-
L: 215,
|
|
4067
|
-
S: this,
|
|
4068
|
-
C: (f, a) => f(...a)
|
|
4069
|
-
});
|
|
4070
|
-
}
|
|
4071
|
-
}
|
|
4072
|
-
/**
|
|
4073
|
-
* Called when underlying proxy service becomes unavailable.
|
|
4074
|
-
*/
|
|
4075
|
-
forceClose() {
|
|
4076
|
-
void this._serviceStream?.close();
|
|
4077
|
-
this.closed.emit();
|
|
4078
|
-
}
|
|
4079
|
-
};
|
|
4080
|
-
var RtcTransportProxyFactory = class {
|
|
4081
|
-
constructor() {
|
|
4082
|
-
this._connections = /* @__PURE__ */ new Set();
|
|
4083
|
-
}
|
|
4084
|
-
/**
|
|
4085
|
-
* Sets the current BridgeService to be used to open connections.
|
|
4086
|
-
* Calling this method will close any existing connections.
|
|
4087
|
-
*/
|
|
4088
|
-
setBridgeService(bridgeService) {
|
|
4089
|
-
this._bridgeService = bridgeService;
|
|
4090
|
-
for (const connection of this._connections) {
|
|
4091
|
-
connection.forceClose();
|
|
4092
|
-
}
|
|
4093
|
-
return this;
|
|
4094
|
-
}
|
|
4095
|
-
createTransport(options) {
|
|
4096
|
-
invariant13(this._bridgeService, "RtcTransportProxyFactory is not ready to open connections", {
|
|
4097
|
-
F: __dxlog_file15,
|
|
4098
|
-
L: 245,
|
|
4099
|
-
S: this,
|
|
4100
|
-
A: [
|
|
4101
|
-
"this._bridgeService",
|
|
4102
|
-
"'RtcTransportProxyFactory is not ready to open connections'"
|
|
4103
|
-
]
|
|
4104
|
-
});
|
|
4105
|
-
const transport = new RtcTransportProxy({
|
|
4106
|
-
...options,
|
|
4107
|
-
bridgeService: this._bridgeService
|
|
4108
|
-
});
|
|
4109
|
-
this._connections.add(transport);
|
|
4110
|
-
transport.closed.on(() => this._connections.delete(transport));
|
|
4111
|
-
return transport;
|
|
4112
|
-
}
|
|
4113
|
-
};
|
|
4114
|
-
var decodeError = (err) => {
|
|
4115
|
-
const message = typeof err === "string" ? err : err.message;
|
|
4116
|
-
if (message.includes("CONNECTION_RESET")) {
|
|
4117
|
-
return new ConnectionResetError2(message);
|
|
4118
|
-
} else if (message.includes("TIMEOUT")) {
|
|
4119
|
-
return new TimeoutError3(message);
|
|
4120
|
-
} else if (message.includes("CONNECTIVITY_ERROR")) {
|
|
4121
|
-
return new ConnectivityError4(message);
|
|
4122
|
-
} else {
|
|
4123
|
-
return typeof err === "string" ? new Error(err) : err;
|
|
4124
|
-
}
|
|
4125
|
-
};
|
|
4126
|
-
|
|
4127
|
-
// packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts
|
|
4128
|
-
import { Duplex as Duplex2 } from "node:stream";
|
|
4129
|
-
import { Stream } from "@dxos/codec-protobuf";
|
|
4130
|
-
import { invariant as invariant14 } from "@dxos/invariant";
|
|
4131
|
-
import { PublicKey as PublicKey11 } from "@dxos/keys";
|
|
4132
|
-
import { log as log15 } from "@dxos/log";
|
|
4133
|
-
import { ConnectionState as ConnectionState4 } from "@dxos/protocols/proto/dxos/mesh/bridge";
|
|
4134
|
-
import { ComplexMap as ComplexMap8 } from "@dxos/util";
|
|
4135
|
-
var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts";
|
|
4136
|
-
var RtcTransportService = class {
|
|
4137
|
-
constructor(webrtcConfig, iceProvider, _transportFactory = createRtcTransportFactory(webrtcConfig, iceProvider)) {
|
|
4138
|
-
this._transportFactory = _transportFactory;
|
|
4139
|
-
this._openTransports = new ComplexMap8(PublicKey11.hash);
|
|
4140
|
-
}
|
|
4141
|
-
hasOpenTransports() {
|
|
4142
|
-
return this._openTransports.size > 0;
|
|
4143
|
-
}
|
|
4144
|
-
open(request) {
|
|
4145
|
-
const existingTransport = this._openTransports.get(request.proxyId);
|
|
4146
|
-
if (existingTransport) {
|
|
4147
|
-
log15.error("requesting a new transport bridge for an existing proxy", void 0, {
|
|
4148
|
-
F: __dxlog_file16,
|
|
4149
|
-
L: 53,
|
|
4150
|
-
S: this,
|
|
4151
|
-
C: (f, a) => f(...a)
|
|
4152
|
-
});
|
|
4153
|
-
void this._safeCloseTransport(existingTransport);
|
|
4154
|
-
this._openTransports.delete(request.proxyId);
|
|
4155
|
-
}
|
|
4156
|
-
return new Stream(({ ready, next, close }) => {
|
|
4157
|
-
const pushNewState = createStateUpdater(next);
|
|
4158
|
-
const transportStream = new Duplex2({
|
|
4159
|
-
read: () => {
|
|
4160
|
-
const callbacks = [
|
|
4161
|
-
...transportState.writeProcessedCallbacks
|
|
4162
|
-
];
|
|
4163
|
-
transportState.writeProcessedCallbacks.length = 0;
|
|
4164
|
-
callbacks.forEach((cb) => cb());
|
|
4165
|
-
},
|
|
4166
|
-
write: function(chunk, _, callback) {
|
|
4167
|
-
next({
|
|
4168
|
-
data: {
|
|
4169
|
-
payload: chunk
|
|
4170
|
-
}
|
|
4171
|
-
});
|
|
4172
|
-
callback();
|
|
4173
|
-
}
|
|
4174
|
-
});
|
|
4175
|
-
const transport = this._transportFactory.createTransport({
|
|
4176
|
-
initiator: request.initiator,
|
|
4177
|
-
topic: request.topic,
|
|
4178
|
-
ownPeerKey: request.ownPeerKey,
|
|
4179
|
-
remotePeerKey: request.remotePeerKey,
|
|
4180
|
-
stream: transportStream,
|
|
4181
|
-
sendSignal: async (signal) => {
|
|
4182
|
-
next({
|
|
4183
|
-
signal: {
|
|
4184
|
-
payload: signal
|
|
4185
|
-
}
|
|
4186
|
-
});
|
|
4187
|
-
}
|
|
4188
|
-
});
|
|
4189
|
-
const transportState = {
|
|
4190
|
-
proxyId: request.proxyId,
|
|
4191
|
-
transport,
|
|
4192
|
-
connectorStream: transportStream,
|
|
4193
|
-
writeProcessedCallbacks: []
|
|
4194
|
-
};
|
|
4195
|
-
pushNewState(ConnectionState4.CONNECTING);
|
|
4196
|
-
transport.connected.on(() => pushNewState(ConnectionState4.CONNECTED));
|
|
4197
|
-
transport.errors.handle(async (err) => {
|
|
4198
|
-
pushNewState(ConnectionState4.CLOSED, err);
|
|
4199
|
-
void this._safeCloseTransport(transportState);
|
|
4200
|
-
close(err);
|
|
4201
|
-
});
|
|
4202
|
-
transport.closed.on(async () => {
|
|
4203
|
-
pushNewState(ConnectionState4.CLOSED);
|
|
4204
|
-
void this._safeCloseTransport(transportState);
|
|
4205
|
-
close();
|
|
4206
|
-
});
|
|
4207
|
-
this._openTransports.set(request.proxyId, transportState);
|
|
4208
|
-
transport.open().catch(async (err) => {
|
|
4209
|
-
pushNewState(ConnectionState4.CLOSED, err);
|
|
4210
|
-
void this._safeCloseTransport(transportState);
|
|
4211
|
-
close(err);
|
|
4212
|
-
});
|
|
4213
|
-
ready();
|
|
4214
|
-
});
|
|
4215
|
-
}
|
|
4216
|
-
async sendSignal({ proxyId, signal }) {
|
|
4217
|
-
const transport = this._openTransports.get(proxyId);
|
|
4218
|
-
invariant14(transport, void 0, {
|
|
4219
|
-
F: __dxlog_file16,
|
|
4220
|
-
L: 121,
|
|
4221
|
-
S: this,
|
|
4222
|
-
A: [
|
|
4223
|
-
"transport",
|
|
4224
|
-
""
|
|
4225
|
-
]
|
|
4226
|
-
});
|
|
4227
|
-
await transport.transport.onSignal(signal);
|
|
4228
|
-
}
|
|
4229
|
-
async getDetails({ proxyId }) {
|
|
4230
|
-
const transport = this._openTransports.get(proxyId);
|
|
4231
|
-
invariant14(transport, void 0, {
|
|
4232
|
-
F: __dxlog_file16,
|
|
4233
|
-
L: 128,
|
|
4234
|
-
S: this,
|
|
4235
|
-
A: [
|
|
4236
|
-
"transport",
|
|
4237
|
-
""
|
|
4238
|
-
]
|
|
4239
|
-
});
|
|
4240
|
-
return {
|
|
4241
|
-
details: await transport.transport.getDetails()
|
|
4242
|
-
};
|
|
4243
|
-
}
|
|
4244
|
-
async getStats({ proxyId }) {
|
|
4245
|
-
const transport = this._openTransports.get(proxyId);
|
|
4246
|
-
invariant14(transport, void 0, {
|
|
4247
|
-
F: __dxlog_file16,
|
|
4248
|
-
L: 135,
|
|
4249
|
-
S: this,
|
|
4250
|
-
A: [
|
|
4251
|
-
"transport",
|
|
4252
|
-
""
|
|
4253
|
-
]
|
|
4254
|
-
});
|
|
4255
|
-
return {
|
|
4256
|
-
stats: await transport.transport.getStats()
|
|
4257
|
-
};
|
|
4258
|
-
}
|
|
4259
|
-
async sendData({ proxyId, payload }) {
|
|
4260
|
-
const transport = this._openTransports.get(proxyId);
|
|
4261
|
-
invariant14(transport, void 0, {
|
|
4262
|
-
F: __dxlog_file16,
|
|
4263
|
-
L: 142,
|
|
4264
|
-
S: this,
|
|
4265
|
-
A: [
|
|
4266
|
-
"transport",
|
|
4267
|
-
""
|
|
4268
|
-
]
|
|
4269
|
-
});
|
|
4270
|
-
const bufferHasSpace = transport.connectorStream.push(payload);
|
|
4271
|
-
if (!bufferHasSpace) {
|
|
4272
|
-
await new Promise((resolve) => {
|
|
4273
|
-
transport.writeProcessedCallbacks.push(resolve);
|
|
4274
|
-
});
|
|
4275
|
-
}
|
|
4276
|
-
}
|
|
4277
|
-
async close({ proxyId }) {
|
|
4278
|
-
const transport = this._openTransports.get(proxyId);
|
|
4279
|
-
if (!transport) {
|
|
4280
|
-
return;
|
|
4281
|
-
}
|
|
4282
|
-
this._openTransports.delete(proxyId);
|
|
4283
|
-
await this._safeCloseTransport(transport);
|
|
4284
|
-
}
|
|
4285
|
-
async _safeCloseTransport(transport) {
|
|
4286
|
-
if (this._openTransports.get(transport.proxyId) === transport) {
|
|
4287
|
-
this._openTransports.delete(transport.proxyId);
|
|
4288
|
-
}
|
|
4289
|
-
transport.writeProcessedCallbacks.forEach((cb) => cb());
|
|
4290
|
-
try {
|
|
4291
|
-
await transport.transport.close();
|
|
4292
|
-
} catch (error) {
|
|
4293
|
-
log15.warn("transport close error", {
|
|
4294
|
-
message: error?.message
|
|
4295
|
-
}, {
|
|
4296
|
-
F: __dxlog_file16,
|
|
4297
|
-
L: 172,
|
|
4298
|
-
S: this,
|
|
4299
|
-
C: (f, a) => f(...a)
|
|
4300
|
-
});
|
|
4301
|
-
}
|
|
4302
|
-
try {
|
|
4303
|
-
transport.connectorStream.end();
|
|
4304
|
-
} catch (error) {
|
|
4305
|
-
log15.warn("connectorStream close error", {
|
|
4306
|
-
message: error?.message
|
|
4307
|
-
}, {
|
|
4308
|
-
F: __dxlog_file16,
|
|
4309
|
-
L: 177,
|
|
4310
|
-
S: this,
|
|
4311
|
-
C: (f, a) => f(...a)
|
|
4312
|
-
});
|
|
4313
|
-
}
|
|
4314
|
-
log15("closed", void 0, {
|
|
4315
|
-
F: __dxlog_file16,
|
|
4316
|
-
L: 179,
|
|
4317
|
-
S: this,
|
|
4318
|
-
C: (f, a) => f(...a)
|
|
4319
|
-
});
|
|
4320
|
-
}
|
|
4321
|
-
};
|
|
4322
|
-
var createStateUpdater = (next) => {
|
|
4323
|
-
return (state, err) => {
|
|
4324
|
-
next({
|
|
4325
|
-
connection: {
|
|
4326
|
-
state,
|
|
4327
|
-
...err ? {
|
|
4328
|
-
error: err.message
|
|
4329
|
-
} : void 0
|
|
4330
|
-
}
|
|
4331
|
-
});
|
|
4332
|
-
};
|
|
4333
|
-
};
|
|
4334
|
-
|
|
4335
|
-
// packages/core/mesh/network-manager/src/wire-protocol.ts
|
|
4336
|
-
import { Teleport } from "@dxos/teleport";
|
|
4337
|
-
var createTeleportProtocolFactory = (onConnection, defaultParams) => {
|
|
4338
|
-
return (params) => {
|
|
4339
|
-
const teleport = new Teleport({
|
|
4340
|
-
...defaultParams,
|
|
4341
|
-
...params
|
|
4342
|
-
});
|
|
4343
|
-
return {
|
|
4344
|
-
stream: teleport.stream,
|
|
4345
|
-
open: async (sessionId) => {
|
|
4346
|
-
await teleport.open(sessionId);
|
|
4347
|
-
await onConnection(teleport);
|
|
4348
|
-
},
|
|
4349
|
-
close: async () => {
|
|
4350
|
-
await teleport.close();
|
|
4351
|
-
},
|
|
4352
|
-
abort: async () => {
|
|
4353
|
-
await teleport.abort();
|
|
4354
|
-
}
|
|
4355
|
-
};
|
|
4356
|
-
};
|
|
4357
|
-
};
|
|
4358
|
-
|
|
4359
|
-
export {
|
|
4360
|
-
ConnectionState,
|
|
4361
|
-
Connection,
|
|
4362
|
-
createIceProvider,
|
|
4363
|
-
SwarmMessenger,
|
|
4364
|
-
Swarm,
|
|
4365
|
-
SwarmMapper,
|
|
4366
|
-
MAX_CONCURRENT_INITIATING_CONNECTIONS,
|
|
4367
|
-
ConnectionLimiter,
|
|
4368
|
-
EventType,
|
|
4369
|
-
ConnectionLog,
|
|
4370
|
-
SwarmNetworkManager,
|
|
4371
|
-
FullyConnectedTopology,
|
|
4372
|
-
MMSTTopology,
|
|
4373
|
-
StarTopology,
|
|
4374
|
-
MemoryTransportFactory,
|
|
4375
|
-
MemoryTransport,
|
|
4376
|
-
TransportKind,
|
|
4377
|
-
createRtcTransportFactory,
|
|
4378
|
-
RtcTransportProxy,
|
|
4379
|
-
RtcTransportProxyFactory,
|
|
4380
|
-
RtcTransportService,
|
|
4381
|
-
createTeleportProtocolFactory
|
|
4382
|
-
};
|
|
4383
|
-
//# sourceMappingURL=chunk-4VO725JT.mjs.map
|