@dxos/network-manager 0.10.0 → 0.11.1
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/chunk-wire-protocol.mjs +3554 -0
- package/dist/lib/chunk-wire-protocol.mjs.map +1 -0
- package/dist/lib/index.mjs +294 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/testing.mjs +237 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/transport/tcp/tcp-transport.browser.mjs +34 -0
- package/dist/lib/transport/tcp/tcp-transport.browser.mjs.map +1 -0
- package/dist/lib/transport/tcp/tcp-transport.mjs +140 -0
- package/dist/lib/transport/tcp/tcp-transport.mjs.map +1 -0
- package/dist/lib/transport/tcp.mjs +1 -0
- package/dist/types/src/network-manager.d.ts +9 -0
- package/dist/types/src/network-manager.d.ts.map +1 -1
- package/dist/types/src/signal/swarm-messenger.d.ts +2 -7
- package/dist/types/src/signal/swarm-messenger.d.ts.map +1 -1
- package/dist/types/src/testing/test-builder.d.ts +2 -6
- package/dist/types/src/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -31
- package/src/network-manager.ts +17 -4
- package/src/signal/integration.node.test.ts +7 -11
- package/src/signal/swarm-messenger.node.test.ts +7 -29
- package/src/signal/swarm-messenger.ts +3 -13
- package/src/swarm/swarm.test.ts +2 -2
- package/src/testing/test-builder.ts +48 -75
- package/src/tests/webrtc-transport.test.ts +4 -15
- package/src/transport/webrtc/rtc-peer-connection.ts +0 -3
- package/src/transport/webrtc/rtc-transport-proxy.test.ts +2 -1
- package/src/transport/webrtc/rtc-transport.test.ts +2 -1
- package/dist/lib/browser/chunk-ERB3AQAF.mjs +0 -3095
- package/dist/lib/browser/chunk-ERB3AQAF.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -244
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs +0 -280
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/browser/transport/tcp/index.mjs +0 -5
- package/dist/lib/browser/transport/tcp/index.mjs.map +0 -7
- package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs +0 -36
- package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs.map +0 -7
- package/dist/lib/browser/transport/tcp/tcp-transport.mjs +0 -125
- package/dist/lib/browser/transport/tcp/tcp-transport.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-KYLPLEZQ.mjs +0 -3095
- package/dist/lib/node-esm/chunk-KYLPLEZQ.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -244
- 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 -5
- package/dist/lib/node-esm/transport/tcp/index.mjs.map +0 -7
- package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs +0 -36
- package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs.map +0 -7
- package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs +0 -125
- package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs.map +0 -7
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { _ as Swarm, a as createRtcTransportFactory, b as ConnectionState, c as MemoryTransportFactory, d as SwarmNetworkManagerService, f as ConnectionLog, g as SwarmMapper, h as MAX_CONCURRENT_INITIATING_CONNECTIONS, i as RtcTransportProxyFactory, l as FullyConnectedTopology, m as ConnectionLimiter, n as RtcTransportService, o as TransportKind, p as EventType, r as RtcTransportProxy, s as MemoryTransport, t as createTeleportProtocolFactory, u as SwarmNetworkManager, v as SwarmMessenger, y as Connection } from "./chunk-wire-protocol.mjs";
|
|
2
|
+
import { asyncTimeout } from "@dxos/async";
|
|
3
|
+
import { isNonNullable } from "@dxos/util";
|
|
4
|
+
import { invariant } from "@dxos/invariant";
|
|
5
|
+
import { log } from "@dxos/log";
|
|
6
|
+
//#region src/signal/ice.ts
|
|
7
|
+
var __dxlog_file$2 = "/__w/dxos/dxos/packages/core/mesh/network-manager/src/signal/ice.ts";
|
|
8
|
+
var createIceProvider = (iceProviders) => {
|
|
9
|
+
let cachedIceServers;
|
|
10
|
+
return { getIceServers: async () => {
|
|
11
|
+
if (cachedIceServers) return cachedIceServers;
|
|
12
|
+
cachedIceServers = (await Promise.all(iceProviders.map(({ urls }) => asyncTimeout(fetch(urls, { method: "GET" }), 1e4).then((response) => response.json()).catch((err) => {
|
|
13
|
+
if (!(typeof window !== "undefined" && window.location.href.includes("localhost"))) log.error("Failed to fetch ICE servers from provider", {
|
|
14
|
+
urls,
|
|
15
|
+
err
|
|
16
|
+
}, {
|
|
17
|
+
"~LogMeta": "~LogMeta",
|
|
18
|
+
F: __dxlog_file$2,
|
|
19
|
+
L: 30,
|
|
20
|
+
S: void 0
|
|
21
|
+
});
|
|
22
|
+
})))).filter(isNonNullable).map(({ iceServers }) => iceServers).flat();
|
|
23
|
+
return cachedIceServers;
|
|
24
|
+
} };
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/topology/mmst-topology.ts
|
|
28
|
+
var __dxlog_file$1 = "/__w/dxos/dxos/packages/core/mesh/network-manager/src/topology/mmst-topology.ts";
|
|
29
|
+
var MIN_UPDATE_INTERVAL = 1e3 * 10;
|
|
30
|
+
var MAX_CHANGES_PER_UPDATE = 1;
|
|
31
|
+
var MMSTTopology = class {
|
|
32
|
+
_originateConnections;
|
|
33
|
+
_maxPeers;
|
|
34
|
+
_sampleSize;
|
|
35
|
+
_controller;
|
|
36
|
+
_sampleCollected = false;
|
|
37
|
+
_lastAction = /* @__PURE__ */ new Date(0);
|
|
38
|
+
constructor({ originateConnections = 2, maxPeers = 4, sampleSize = 10 } = {}) {
|
|
39
|
+
this._originateConnections = originateConnections;
|
|
40
|
+
this._maxPeers = maxPeers;
|
|
41
|
+
this._sampleSize = sampleSize;
|
|
42
|
+
}
|
|
43
|
+
init(controller) {
|
|
44
|
+
invariant(!this._controller, "Already initialized", {
|
|
45
|
+
"~LogMeta": "~LogMeta",
|
|
46
|
+
F: __dxlog_file$1,
|
|
47
|
+
L: 49,
|
|
48
|
+
S: this,
|
|
49
|
+
A: ["!this._controller", "'Already initialized'"]
|
|
50
|
+
});
|
|
51
|
+
this._controller = controller;
|
|
52
|
+
}
|
|
53
|
+
update() {
|
|
54
|
+
invariant(this._controller, "Not initialized", {
|
|
55
|
+
"~LogMeta": "~LogMeta",
|
|
56
|
+
F: __dxlog_file$1,
|
|
57
|
+
L: 54,
|
|
58
|
+
S: this,
|
|
59
|
+
A: ["this._controller", "'Not initialized'"]
|
|
60
|
+
});
|
|
61
|
+
const { connected, candidates } = this._controller.getState();
|
|
62
|
+
if (this._sampleCollected || connected.length > this._maxPeers || candidates.length > 0) {
|
|
63
|
+
log("Running the algorithm.", void 0, {
|
|
64
|
+
"~LogMeta": "~LogMeta",
|
|
65
|
+
F: __dxlog_file$1,
|
|
66
|
+
L: 58,
|
|
67
|
+
S: this
|
|
68
|
+
});
|
|
69
|
+
this._sampleCollected = true;
|
|
70
|
+
this._runAlgorithm();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
forceUpdate() {
|
|
74
|
+
this._lastAction = /* @__PURE__ */ new Date(0);
|
|
75
|
+
this.update();
|
|
76
|
+
}
|
|
77
|
+
async onOffer(peer) {
|
|
78
|
+
invariant(this._controller, "Not initialized", {
|
|
79
|
+
"~LogMeta": "~LogMeta",
|
|
80
|
+
F: __dxlog_file$1,
|
|
81
|
+
L: 70,
|
|
82
|
+
S: this,
|
|
83
|
+
A: ["this._controller", "'Not initialized'"]
|
|
84
|
+
});
|
|
85
|
+
const { connected } = this._controller.getState();
|
|
86
|
+
const accept = connected.length < this._maxPeers;
|
|
87
|
+
log(`Offer ${peer} accept=${accept}`, void 0, {
|
|
88
|
+
"~LogMeta": "~LogMeta",
|
|
89
|
+
F: __dxlog_file$1,
|
|
90
|
+
L: 73,
|
|
91
|
+
S: this
|
|
92
|
+
});
|
|
93
|
+
return accept;
|
|
94
|
+
}
|
|
95
|
+
async destroy() {}
|
|
96
|
+
_runAlgorithm() {
|
|
97
|
+
invariant(this._controller, "Not initialized", {
|
|
98
|
+
"~LogMeta": "~LogMeta",
|
|
99
|
+
F: __dxlog_file$1,
|
|
100
|
+
L: 82,
|
|
101
|
+
S: this,
|
|
102
|
+
A: ["this._controller", "'Not initialized'"]
|
|
103
|
+
});
|
|
104
|
+
const { connected, candidates, ownPeerId } = this._controller.getState();
|
|
105
|
+
if (connected.length > this._maxPeers) {
|
|
106
|
+
log(`disconnect ${connected.length - this._maxPeers} peers.`, void 0, {
|
|
107
|
+
"~LogMeta": "~LogMeta",
|
|
108
|
+
F: __dxlog_file$1,
|
|
109
|
+
L: 88,
|
|
110
|
+
S: this
|
|
111
|
+
});
|
|
112
|
+
const sorted = sortByXorDistance(connected, ownPeerId).reverse().slice(0, this._maxPeers - connected.length);
|
|
113
|
+
invariant(sorted.length === 0, void 0, {
|
|
114
|
+
"~LogMeta": "~LogMeta",
|
|
115
|
+
F: __dxlog_file$1,
|
|
116
|
+
L: 92,
|
|
117
|
+
S: this,
|
|
118
|
+
A: ["sorted.length === 0", ""]
|
|
119
|
+
});
|
|
120
|
+
if (sorted.length > MAX_CHANGES_PER_UPDATE) log(`want to disconnect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
|
|
121
|
+
"~LogMeta": "~LogMeta",
|
|
122
|
+
F: __dxlog_file$1,
|
|
123
|
+
L: 95,
|
|
124
|
+
S: this
|
|
125
|
+
});
|
|
126
|
+
if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
|
|
127
|
+
for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
|
|
128
|
+
log(`Disconnect ${peer}.`, void 0, {
|
|
129
|
+
"~LogMeta": "~LogMeta",
|
|
130
|
+
F: __dxlog_file$1,
|
|
131
|
+
L: 100,
|
|
132
|
+
S: this
|
|
133
|
+
});
|
|
134
|
+
this._controller.disconnect(peer);
|
|
135
|
+
}
|
|
136
|
+
this._lastAction = /* @__PURE__ */ new Date();
|
|
137
|
+
} else log("rate limited disconnect", void 0, {
|
|
138
|
+
"~LogMeta": "~LogMeta",
|
|
139
|
+
F: __dxlog_file$1,
|
|
140
|
+
L: 105,
|
|
141
|
+
S: this
|
|
142
|
+
});
|
|
143
|
+
} else if (connected.length < this._originateConnections) {
|
|
144
|
+
log(`connect ${this._originateConnections - connected.length} peers.`, void 0, {
|
|
145
|
+
"~LogMeta": "~LogMeta",
|
|
146
|
+
F: __dxlog_file$1,
|
|
147
|
+
L: 109,
|
|
148
|
+
S: this
|
|
149
|
+
});
|
|
150
|
+
const sorted = sortByXorDistance(candidates.sort(() => Math.random() - .5).slice(0, this._sampleSize), ownPeerId).slice(0, this._originateConnections - connected.length);
|
|
151
|
+
if (sorted.length > MAX_CHANGES_PER_UPDATE) log(`want to connect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
|
|
152
|
+
"~LogMeta": "~LogMeta",
|
|
153
|
+
F: __dxlog_file$1,
|
|
154
|
+
L: 114,
|
|
155
|
+
S: this
|
|
156
|
+
});
|
|
157
|
+
if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
|
|
158
|
+
for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
|
|
159
|
+
log(`Connect ${peer}.`, void 0, {
|
|
160
|
+
"~LogMeta": "~LogMeta",
|
|
161
|
+
F: __dxlog_file$1,
|
|
162
|
+
L: 118,
|
|
163
|
+
S: this
|
|
164
|
+
});
|
|
165
|
+
this._controller.connect(peer);
|
|
166
|
+
}
|
|
167
|
+
this._lastAction = /* @__PURE__ */ new Date();
|
|
168
|
+
} else log("rate limited connect", void 0, {
|
|
169
|
+
"~LogMeta": "~LogMeta",
|
|
170
|
+
F: __dxlog_file$1,
|
|
171
|
+
L: 123,
|
|
172
|
+
S: this
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
toString() {
|
|
177
|
+
return "MMSTTopology";
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
var sortByXorDistance = (keys, reference) => {
|
|
181
|
+
const sorted = keys.sort((a, b) => {
|
|
182
|
+
return compareXor(distXor(a.asBuffer(), reference.asBuffer()), distXor(b.asBuffer(), reference.asBuffer()));
|
|
183
|
+
});
|
|
184
|
+
log("Sorted keys", {
|
|
185
|
+
keys,
|
|
186
|
+
reference,
|
|
187
|
+
sorted
|
|
188
|
+
}, {
|
|
189
|
+
"~LogMeta": "~LogMeta",
|
|
190
|
+
F: __dxlog_file$1,
|
|
191
|
+
L: 137,
|
|
192
|
+
S: void 0
|
|
193
|
+
});
|
|
194
|
+
return sorted;
|
|
195
|
+
};
|
|
196
|
+
var distXor = (a, b) => {
|
|
197
|
+
const maxLength = Math.max(a.length, b.length);
|
|
198
|
+
const result = Buffer.allocUnsafe(maxLength);
|
|
199
|
+
for (let i = 0; i < maxLength; i++) result[i] = (a[i] || 0) ^ (b[i] || 0);
|
|
200
|
+
return result;
|
|
201
|
+
};
|
|
202
|
+
var compareXor = (a, b) => {
|
|
203
|
+
const maxLength = Math.max(a.length, b.length);
|
|
204
|
+
for (let i = 0; i < maxLength; i++) {
|
|
205
|
+
if ((a[i] || 0) === (b[i] || 0)) continue;
|
|
206
|
+
return (a[i] || 0) < (b[i] || 0) ? -1 : 1;
|
|
207
|
+
}
|
|
208
|
+
return 0;
|
|
209
|
+
};
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/topology/star-topology.ts
|
|
212
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/network-manager/src/topology/star-topology.ts";
|
|
213
|
+
var StarTopology = class {
|
|
214
|
+
_centralPeer;
|
|
215
|
+
_controller;
|
|
216
|
+
constructor(_centralPeer) {
|
|
217
|
+
this._centralPeer = _centralPeer;
|
|
218
|
+
}
|
|
219
|
+
toString() {
|
|
220
|
+
return `StarTopology(${this._centralPeer.truncate()})`;
|
|
221
|
+
}
|
|
222
|
+
init(controller) {
|
|
223
|
+
invariant(!this._controller, "Already initialized.", {
|
|
224
|
+
"~LogMeta": "~LogMeta",
|
|
225
|
+
F: __dxlog_file,
|
|
226
|
+
L: 21,
|
|
227
|
+
S: this,
|
|
228
|
+
A: ["!this._controller", "'Already initialized.'"]
|
|
229
|
+
});
|
|
230
|
+
this._controller = controller;
|
|
231
|
+
}
|
|
232
|
+
update() {
|
|
233
|
+
invariant(this._controller, "Not initialized.", {
|
|
234
|
+
"~LogMeta": "~LogMeta",
|
|
235
|
+
F: __dxlog_file,
|
|
236
|
+
L: 26,
|
|
237
|
+
S: this,
|
|
238
|
+
A: ["this._controller", "'Not initialized.'"]
|
|
239
|
+
});
|
|
240
|
+
const { candidates, connected, ownPeerId } = this._controller.getState();
|
|
241
|
+
if (!ownPeerId.equals(this._centralPeer)) {
|
|
242
|
+
log("leaf peer dropping all connections apart from central peer.", void 0, {
|
|
243
|
+
"~LogMeta": "~LogMeta",
|
|
244
|
+
F: __dxlog_file,
|
|
245
|
+
L: 29,
|
|
246
|
+
S: this
|
|
247
|
+
});
|
|
248
|
+
for (const peer of connected) if (!peer.equals(this._centralPeer)) {
|
|
249
|
+
log("dropping connection", { peer }, {
|
|
250
|
+
"~LogMeta": "~LogMeta",
|
|
251
|
+
F: __dxlog_file,
|
|
252
|
+
L: 34,
|
|
253
|
+
S: this
|
|
254
|
+
});
|
|
255
|
+
this._controller.disconnect(peer);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
for (const peer of candidates) if (peer.equals(this._centralPeer) || ownPeerId.equals(this._centralPeer)) {
|
|
259
|
+
log("connecting to peer", { peer }, {
|
|
260
|
+
"~LogMeta": "~LogMeta",
|
|
261
|
+
F: __dxlog_file,
|
|
262
|
+
L: 43,
|
|
263
|
+
S: this
|
|
264
|
+
});
|
|
265
|
+
this._controller.connect(peer);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async onOffer(peer) {
|
|
269
|
+
invariant(this._controller, "Not initialized.", {
|
|
270
|
+
"~LogMeta": "~LogMeta",
|
|
271
|
+
F: __dxlog_file,
|
|
272
|
+
L: 50,
|
|
273
|
+
S: this,
|
|
274
|
+
A: ["this._controller", "'Not initialized.'"]
|
|
275
|
+
});
|
|
276
|
+
const { ownPeerId } = this._controller.getState();
|
|
277
|
+
log("offer", {
|
|
278
|
+
peer,
|
|
279
|
+
isCentral: peer.equals(this._centralPeer),
|
|
280
|
+
isSelfCentral: ownPeerId.equals(this._centralPeer)
|
|
281
|
+
}, {
|
|
282
|
+
"~LogMeta": "~LogMeta",
|
|
283
|
+
F: __dxlog_file,
|
|
284
|
+
L: 52,
|
|
285
|
+
S: this
|
|
286
|
+
});
|
|
287
|
+
return ownPeerId.equals(this._centralPeer) || peer.equals(this._centralPeer);
|
|
288
|
+
}
|
|
289
|
+
async destroy() {}
|
|
290
|
+
};
|
|
291
|
+
//#endregion
|
|
292
|
+
export { Connection, ConnectionLimiter, ConnectionLog, ConnectionState, EventType, FullyConnectedTopology, MAX_CONCURRENT_INITIATING_CONNECTIONS, MMSTTopology, MemoryTransport, MemoryTransportFactory, RtcTransportProxy, RtcTransportProxyFactory, RtcTransportService, StarTopology, Swarm, SwarmMapper, SwarmMessenger, SwarmNetworkManager, SwarmNetworkManagerService, TransportKind, createIceProvider, createRtcTransportFactory, createTeleportProtocolFactory };
|
|
293
|
+
|
|
294
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/signal/ice.ts","../../src/topology/mmst-topology.ts","../../src/topology/star-topology.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { asyncTimeout } from '@dxos/async';\nimport { log } from '@dxos/log';\nimport { type Runtime } from '@dxos/protocols/proto/dxos/config';\nimport { isNonNullable } from '@dxos/util';\n\nexport interface IceProvider {\n getIceServers: () => Promise<RTCIceServer[]>;\n}\n\nexport const createIceProvider = (iceProviders: Runtime.Services.IceProvider[]): IceProvider => {\n let cachedIceServers: RTCIceServer[];\n return {\n getIceServers: async () => {\n if (cachedIceServers) {\n return cachedIceServers;\n }\n\n cachedIceServers = (\n await Promise.all(\n iceProviders.map(({ urls }) =>\n asyncTimeout(fetch(urls, { method: 'GET' }), 10_000)\n .then((response) => response.json())\n .catch((err) => {\n const isDev = typeof window !== 'undefined' && window.location.href.includes('localhost');\n if (!isDev) {\n log.error('Failed to fetch ICE servers from provider', { urls, err });\n }\n }),\n ),\n )\n )\n .filter(isNonNullable)\n .map(({ iceServers }: { iceServers: RTCIceServer[] }) => iceServers)\n .flat();\n\n return cachedIceServers;\n },\n };\n};\n","//\n// Copyright 2020 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { type SwarmController, type Topology } from './topology';\n\nconst MIN_UPDATE_INTERVAL = 1000 * 10;\nconst MAX_CHANGES_PER_UPDATE = 1;\n\nexport interface MMSTTopologyOptions {\n /**\n * Number of connections the peer will originate by itself.\n */\n originateConnections?: number;\n\n /**\n * Maximum number of connections allowed, all other connections will be dropped.\n */\n maxPeers?: number;\n\n /**\n * Size of random sample from which peer candidates are selected.\n */\n sampleSize?: number;\n}\n\nexport class MMSTTopology implements Topology {\n private readonly _originateConnections: number;\n private readonly _maxPeers: number;\n private readonly _sampleSize: number;\n\n private _controller?: SwarmController;\n\n private _sampleCollected = false;\n\n private _lastAction = new Date(0);\n\n constructor({ originateConnections = 2, maxPeers = 4, sampleSize = 10 }: MMSTTopologyOptions = {}) {\n this._originateConnections = originateConnections;\n this._maxPeers = maxPeers;\n this._sampleSize = sampleSize;\n }\n\n init(controller: SwarmController): void {\n invariant(!this._controller, 'Already initialized');\n this._controller = controller;\n }\n\n update(): void {\n invariant(this._controller, 'Not initialized');\n const { connected, candidates } = this._controller.getState();\n // Run the algorithms if we have first candidates, ran it before, or have more connections than needed.\n if (this._sampleCollected || connected.length > this._maxPeers || candidates.length > 0) {\n log('Running the algorithm.');\n this._sampleCollected = true;\n this._runAlgorithm();\n }\n }\n\n forceUpdate(): void {\n this._lastAction = new Date(0);\n this.update();\n }\n\n async onOffer(peer: PublicKey): Promise<boolean> {\n invariant(this._controller, 'Not initialized');\n const { connected } = this._controller.getState();\n const accept = connected.length < this._maxPeers;\n log(`Offer ${peer} accept=${accept}`);\n return accept;\n }\n\n async destroy(): Promise<void> {\n // Nothing to do.\n }\n\n private _runAlgorithm(): void {\n invariant(this._controller, 'Not initialized');\n const { connected, candidates, ownPeerId } = this._controller.getState();\n\n // TODO(nf): does this rate limiting/flap dampening logic belong here or in the SwarmController?\n if (connected.length > this._maxPeers) {\n // Disconnect extra peers.\n log(`disconnect ${connected.length - this._maxPeers} peers.`);\n const sorted = sortByXorDistance(connected, ownPeerId)\n .reverse()\n .slice(0, this._maxPeers - connected.length);\n invariant(sorted.length === 0);\n\n if (sorted.length > MAX_CHANGES_PER_UPDATE) {\n log(`want to disconnect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`);\n }\n\n if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {\n for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {\n log(`Disconnect ${peer}.`);\n this._controller.disconnect(peer);\n }\n this._lastAction = new Date();\n } else {\n log('rate limited disconnect');\n }\n } else if (connected.length < this._originateConnections) {\n // Connect new peers to reach desired quota.\n log(`connect ${this._originateConnections - connected.length} peers.`);\n const sample = candidates.sort(() => Math.random() - 0.5).slice(0, this._sampleSize);\n const sorted = sortByXorDistance(sample, ownPeerId).slice(0, this._originateConnections - connected.length);\n\n if (sorted.length > MAX_CHANGES_PER_UPDATE) {\n log(`want to connect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`);\n }\n if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {\n for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {\n log(`Connect ${peer}.`);\n this._controller.connect(peer);\n }\n this._lastAction = new Date();\n } else {\n log('rate limited connect');\n }\n }\n }\n\n toString(): string {\n return 'MMSTTopology';\n }\n}\n\nconst sortByXorDistance = (keys: PublicKey[], reference: PublicKey): PublicKey[] => {\n const sorted = keys.sort((a, b) => {\n return compareXor(distXor(a.asBuffer(), reference.asBuffer()), distXor(b.asBuffer(), reference.asBuffer()));\n });\n log('Sorted keys', { keys, reference, sorted });\n return sorted;\n};\n\nconst distXor = (a: Buffer, b: Buffer) => {\n const maxLength = Math.max(a.length, b.length);\n const result = Buffer.allocUnsafe(maxLength);\n for (let i = 0; i < maxLength; i++) {\n result[i] = (a[i] || 0) ^ (b[i] || 0);\n }\n return result;\n};\n\nconst compareXor = (a: Buffer, b: Buffer) => {\n const maxLength = Math.max(a.length, b.length);\n for (let i = 0; i < maxLength; i++) {\n if ((a[i] || 0) === (b[i] || 0)) {\n continue;\n }\n return (a[i] || 0) < (b[i] || 0) ? -1 : 1;\n }\n return 0;\n};\n","//\n// Copyright 2020 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { type SwarmController, type Topology } from './topology';\n\nexport class StarTopology implements Topology {\n private _controller?: SwarmController;\n\n constructor(private readonly _centralPeer: PublicKey) {}\n\n toString(): string {\n return `StarTopology(${this._centralPeer.truncate()})`;\n }\n\n init(controller: SwarmController): void {\n invariant(!this._controller, 'Already initialized.');\n this._controller = controller;\n }\n\n update(): void {\n invariant(this._controller, 'Not initialized.');\n const { candidates, connected, ownPeerId } = this._controller.getState();\n if (!ownPeerId.equals(this._centralPeer)) {\n log('leaf peer dropping all connections apart from central peer.');\n\n // Drop all connections other than central peer.\n for (const peer of connected) {\n if (!peer.equals(this._centralPeer)) {\n log('dropping connection', { peer });\n this._controller.disconnect(peer);\n }\n }\n }\n\n for (const peer of candidates) {\n // Connect to central peer.\n if (peer.equals(this._centralPeer) || ownPeerId.equals(this._centralPeer)) {\n log('connecting to peer', { peer });\n this._controller.connect(peer);\n }\n }\n }\n\n async onOffer(peer: PublicKey): Promise<boolean> {\n invariant(this._controller, 'Not initialized.');\n const { ownPeerId } = this._controller.getState();\n log('offer', {\n peer,\n isCentral: peer.equals(this._centralPeer),\n isSelfCentral: ownPeerId.equals(this._centralPeer),\n });\n return ownPeerId.equals(this._centralPeer) || peer.equals(this._centralPeer);\n }\n\n async destroy(): Promise<void> {\n // Nothing to do.\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { a as createRtcTransportFactory, c as MemoryTransportFactory, i as RtcTransportProxyFactory, l as FullyConnectedTopology, n as RtcTransportService, o as TransportKind, t as createTeleportProtocolFactory, u as SwarmNetworkManager } from "./chunk-wire-protocol.mjs";
|
|
2
|
+
import { Event, asyncTimeout } from "@dxos/async";
|
|
3
|
+
import { PublicKey } from "@dxos/keys";
|
|
4
|
+
import { ComplexMap } from "@dxos/util";
|
|
5
|
+
import { Context } from "@dxos/context";
|
|
6
|
+
import { log } from "@dxos/log";
|
|
7
|
+
import { MemorySignalManager, MemorySignalManagerContext } from "@dxos/messaging";
|
|
8
|
+
import { schema } from "@dxos/protocols/proto";
|
|
9
|
+
import { ConnectionState } from "@dxos/protocols/proto/dxos/client/services";
|
|
10
|
+
import { TestExtension, TestExtensionWithStreams } from "@dxos/teleport";
|
|
11
|
+
import { createLinkedPorts, createProtoRpcPeer } from "@dxos/rpc";
|
|
12
|
+
import { TcpTransportFactory } from "#tcp-transport";
|
|
13
|
+
//#region src/testing/test-wire-protocol.ts
|
|
14
|
+
var __dxlog_file$1 = "/__w/dxos/dxos/packages/core/mesh/network-manager/src/testing/test-wire-protocol.ts";
|
|
15
|
+
var TestWireProtocol = class {
|
|
16
|
+
_extensionFactory;
|
|
17
|
+
connections = new ComplexMap(PublicKey.hash);
|
|
18
|
+
streamConnections = new ComplexMap(PublicKey.hash);
|
|
19
|
+
connected = new Event();
|
|
20
|
+
disconnected = new Event();
|
|
21
|
+
otherConnections = new ComplexMap(({ remotePeerId, extension }) => remotePeerId.toHex() + extension);
|
|
22
|
+
constructor(_extensionFactory = () => []) {
|
|
23
|
+
this._extensionFactory = _extensionFactory;
|
|
24
|
+
}
|
|
25
|
+
factory = createTeleportProtocolFactory(async (teleport) => {
|
|
26
|
+
log("create", { remotePeerId: teleport.remotePeerId }, {
|
|
27
|
+
"~LogMeta": "~LogMeta",
|
|
28
|
+
F: __dxlog_file$1,
|
|
29
|
+
L: 35,
|
|
30
|
+
S: this
|
|
31
|
+
});
|
|
32
|
+
const handleDisconnect = () => {
|
|
33
|
+
this.connections.delete(teleport.remotePeerId);
|
|
34
|
+
this.disconnected.emit(teleport.remotePeerId);
|
|
35
|
+
};
|
|
36
|
+
const extension = new TestExtension({
|
|
37
|
+
onClose: async () => handleDisconnect(),
|
|
38
|
+
onAbort: async () => handleDisconnect()
|
|
39
|
+
});
|
|
40
|
+
this.connections.set(teleport.remotePeerId, extension);
|
|
41
|
+
teleport.addExtension("test", extension);
|
|
42
|
+
this.connected.emit(teleport.remotePeerId);
|
|
43
|
+
const streamExtension = new TestExtensionWithStreams({ onClose: async () => {
|
|
44
|
+
this.streamConnections.delete(teleport.remotePeerId);
|
|
45
|
+
} });
|
|
46
|
+
this.streamConnections.set(teleport.remotePeerId, streamExtension);
|
|
47
|
+
teleport.addExtension("test-stream", streamExtension);
|
|
48
|
+
for (const { name, extension } of this._extensionFactory()) {
|
|
49
|
+
this.otherConnections.set({
|
|
50
|
+
remotePeerId: teleport.remotePeerId,
|
|
51
|
+
extension: name
|
|
52
|
+
}, extension);
|
|
53
|
+
teleport.addExtension(name, extension);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
async waitForConnection(peerId) {
|
|
57
|
+
if (this.connections.has(peerId)) return this.connections.get(peerId);
|
|
58
|
+
log("waitForConnection", { peerId }, {
|
|
59
|
+
"~LogMeta": "~LogMeta",
|
|
60
|
+
F: __dxlog_file$1,
|
|
61
|
+
L: 66,
|
|
62
|
+
S: this
|
|
63
|
+
});
|
|
64
|
+
await asyncTimeout(this.connected.waitFor((connectedId) => connectedId.equals(peerId)), 1e4);
|
|
65
|
+
return this.connections.get(peerId);
|
|
66
|
+
}
|
|
67
|
+
async testConnection(peerId, message) {
|
|
68
|
+
await (await this.waitForConnection(peerId)).test(message);
|
|
69
|
+
}
|
|
70
|
+
async openStream(peerId, streamTag, streamLoadInterval, streamLoadChunkSize) {
|
|
71
|
+
if (!this.streamConnections.has(peerId)) throw new Error("Connection does not exist.");
|
|
72
|
+
return this.streamConnections.get(peerId).addNewStream(streamLoadInterval, streamLoadChunkSize, streamTag);
|
|
73
|
+
}
|
|
74
|
+
async closeStream(peerId, streamTag) {
|
|
75
|
+
if (!this.streamConnections.has(peerId)) throw new Error("Connection does not exist.");
|
|
76
|
+
return this.streamConnections.get(peerId).closeStream(streamTag);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/testing/test-builder.ts
|
|
81
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/network-manager/src/testing/test-builder.ts";
|
|
82
|
+
/**
|
|
83
|
+
* Builder used to construct networks and peers.
|
|
84
|
+
*/
|
|
85
|
+
var TestBuilder = class {
|
|
86
|
+
options;
|
|
87
|
+
_signalContext = new MemorySignalManagerContext();
|
|
88
|
+
constructor(options = {}) {
|
|
89
|
+
this.options = options;
|
|
90
|
+
}
|
|
91
|
+
createSignalManager() {
|
|
92
|
+
return new MemorySignalManager(this._signalContext);
|
|
93
|
+
}
|
|
94
|
+
createPeer(peerId = PublicKey.random()) {
|
|
95
|
+
return new TestPeer(this, peerId, this.options.transport);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Testing network peer.
|
|
100
|
+
*/
|
|
101
|
+
var TestPeer = class {
|
|
102
|
+
testBuilder;
|
|
103
|
+
peerId;
|
|
104
|
+
transport;
|
|
105
|
+
_swarms = new ComplexMap(PublicKey.hash);
|
|
106
|
+
/**
|
|
107
|
+
* @internal
|
|
108
|
+
*/
|
|
109
|
+
_signalManager;
|
|
110
|
+
/**
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
_networkManager;
|
|
114
|
+
_proxy;
|
|
115
|
+
_service;
|
|
116
|
+
constructor(testBuilder, peerId, transport = TransportKind.MEMORY) {
|
|
117
|
+
this.testBuilder = testBuilder;
|
|
118
|
+
this.peerId = peerId;
|
|
119
|
+
this.transport = transport;
|
|
120
|
+
this._signalManager = this.testBuilder.createSignalManager();
|
|
121
|
+
this._networkManager = this.createNetworkManager(this.transport);
|
|
122
|
+
this._networkManager.setPeerInfo({
|
|
123
|
+
identityDid: `did:halo:${peerId.toHex()}`,
|
|
124
|
+
peerKey: peerId.toHex()
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
createNetworkManager(transport) {
|
|
128
|
+
let transportFactory;
|
|
129
|
+
switch (transport) {
|
|
130
|
+
case TransportKind.MEMORY:
|
|
131
|
+
transportFactory = MemoryTransportFactory;
|
|
132
|
+
break;
|
|
133
|
+
case TransportKind.TCP:
|
|
134
|
+
transportFactory = TcpTransportFactory;
|
|
135
|
+
break;
|
|
136
|
+
case TransportKind.WEB_RTC:
|
|
137
|
+
transportFactory = createRtcTransportFactory();
|
|
138
|
+
break;
|
|
139
|
+
case TransportKind.WEB_RTC_PROXY:
|
|
140
|
+
{
|
|
141
|
+
const [proxyPort, servicePort] = createLinkedPorts();
|
|
142
|
+
this._proxy = createProtoRpcPeer({
|
|
143
|
+
port: proxyPort,
|
|
144
|
+
requested: { BridgeService: schema.getService("dxos.mesh.bridge.BridgeService") },
|
|
145
|
+
noHandshake: true,
|
|
146
|
+
encodingOptions: { preserveAny: true }
|
|
147
|
+
});
|
|
148
|
+
this._service = createProtoRpcPeer({
|
|
149
|
+
port: servicePort,
|
|
150
|
+
exposed: { BridgeService: schema.getService("dxos.mesh.bridge.BridgeService") },
|
|
151
|
+
handlers: { BridgeService: new RtcTransportService() },
|
|
152
|
+
noHandshake: true,
|
|
153
|
+
encodingOptions: { preserveAny: true }
|
|
154
|
+
});
|
|
155
|
+
transportFactory = new RtcTransportProxyFactory().setBridgeService(this._proxy.rpc.BridgeService);
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
default: throw new Error(`Unsupported transport: ${transport}`);
|
|
159
|
+
}
|
|
160
|
+
return new SwarmNetworkManager({
|
|
161
|
+
signalManager: this._signalManager,
|
|
162
|
+
transportFactory
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async open() {
|
|
166
|
+
await this._networkManager.open();
|
|
167
|
+
await this._proxy?.open();
|
|
168
|
+
await this._service?.open();
|
|
169
|
+
}
|
|
170
|
+
async close() {
|
|
171
|
+
await Promise.all(Array.from(this._swarms.values()).map((swarm) => swarm.leave()));
|
|
172
|
+
this._swarms.clear();
|
|
173
|
+
await this._proxy?.close();
|
|
174
|
+
await this._service?.close();
|
|
175
|
+
await this._networkManager.close(Context.default(void 0, {
|
|
176
|
+
"~LogMeta": "~LogMeta",
|
|
177
|
+
F: __dxlog_file,
|
|
178
|
+
L: 145
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
getSwarm(topic) {
|
|
182
|
+
const swarm = this._swarms.get(topic);
|
|
183
|
+
if (!swarm) throw new Error(`Swarm not found for topic: ${topic}`);
|
|
184
|
+
return swarm;
|
|
185
|
+
}
|
|
186
|
+
createSwarm(topic, extensionFactory = () => []) {
|
|
187
|
+
const swarm = new TestSwarmConnection(this, topic, extensionFactory);
|
|
188
|
+
this._swarms.set(topic, swarm);
|
|
189
|
+
return swarm;
|
|
190
|
+
}
|
|
191
|
+
async goOffline() {
|
|
192
|
+
await this._networkManager.setConnectionState(ConnectionState.OFFLINE);
|
|
193
|
+
}
|
|
194
|
+
async goOnline() {
|
|
195
|
+
await this._networkManager.setConnectionState(ConnectionState.ONLINE);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
var TestSwarmConnection = class {
|
|
199
|
+
peer;
|
|
200
|
+
topic;
|
|
201
|
+
extensionFactory;
|
|
202
|
+
protocol;
|
|
203
|
+
constructor(peer, topic, extensionFactory) {
|
|
204
|
+
this.peer = peer;
|
|
205
|
+
this.topic = topic;
|
|
206
|
+
this.extensionFactory = extensionFactory;
|
|
207
|
+
this.protocol = new TestWireProtocol(this.extensionFactory);
|
|
208
|
+
}
|
|
209
|
+
async join(topology = new FullyConnectedTopology()) {
|
|
210
|
+
await this.peer._networkManager.joinSwarm(Context.default(void 0, {
|
|
211
|
+
"~LogMeta": "~LogMeta",
|
|
212
|
+
F: __dxlog_file,
|
|
213
|
+
L: 194
|
|
214
|
+
}), {
|
|
215
|
+
topic: this.topic,
|
|
216
|
+
peerInfo: {
|
|
217
|
+
peerKey: this.peer.peerId.toHex(),
|
|
218
|
+
identityDid: `did:halo:${this.peer.peerId.toHex()}`
|
|
219
|
+
},
|
|
220
|
+
protocolProvider: this.protocol.factory,
|
|
221
|
+
topology
|
|
222
|
+
});
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
async leave() {
|
|
226
|
+
await this.peer._networkManager.leaveSwarm(Context.default(void 0, {
|
|
227
|
+
"~LogMeta": "~LogMeta",
|
|
228
|
+
F: __dxlog_file,
|
|
229
|
+
L: 205
|
|
230
|
+
}), this.topic);
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
//#endregion
|
|
235
|
+
export { TestBuilder, TestPeer, TestSwarmConnection };
|
|
236
|
+
|
|
237
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../../src/testing/test-wire-protocol.ts","../../src/testing/test-builder.ts"],"sourcesContent":["//\n// Copyright 2022 DXOS.org\n//\n\nimport { Event, asyncTimeout } from '@dxos/async';\nimport { PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { TestExtension, TestExtensionWithStreams } from '@dxos/teleport';\nimport type { TeleportExtension, TestStreamStats } from '@dxos/teleport';\nimport { ComplexMap } from '@dxos/util';\n\nimport { createTeleportProtocolFactory } from '../wire-protocol';\n\nexport type TestTeleportExtension = {\n name: string;\n extension: TeleportExtension;\n};\n\nexport type TestTeleportExtensionFactory = () => TestTeleportExtension[];\n\nexport class TestWireProtocol {\n public readonly connections = new ComplexMap<PublicKey, TestExtension>(PublicKey.hash);\n public readonly streamConnections = new ComplexMap<PublicKey, TestExtensionWithStreams>(PublicKey.hash);\n\n public readonly connected = new Event<PublicKey>();\n public readonly disconnected = new Event<PublicKey>();\n\n public readonly otherConnections = new ComplexMap<{ remotePeerId: PublicKey; extension: string }, TeleportExtension>(\n ({ remotePeerId, extension }) => remotePeerId.toHex() + extension,\n );\n\n constructor(private readonly _extensionFactory: TestTeleportExtensionFactory = () => []) {}\n\n readonly factory = createTeleportProtocolFactory(async (teleport) => {\n log('create', { remotePeerId: teleport.remotePeerId });\n const handleDisconnect = () => {\n this.connections.delete(teleport.remotePeerId);\n this.disconnected.emit(teleport.remotePeerId);\n };\n const extension = new TestExtension({\n onClose: async () => handleDisconnect(),\n onAbort: async () => handleDisconnect(),\n });\n this.connections.set(teleport.remotePeerId, extension);\n teleport.addExtension('test', extension);\n this.connected.emit(teleport.remotePeerId);\n\n const streamExtension = new TestExtensionWithStreams({\n onClose: async () => {\n this.streamConnections.delete(teleport.remotePeerId);\n },\n });\n this.streamConnections.set(teleport.remotePeerId, streamExtension);\n teleport.addExtension('test-stream', streamExtension);\n\n for (const { name, extension } of this._extensionFactory()) {\n this.otherConnections.set({ remotePeerId: teleport.remotePeerId, extension: name }, extension);\n teleport.addExtension(name, extension);\n }\n });\n\n async waitForConnection(peerId: PublicKey): Promise<TestExtension> {\n if (this.connections.has(peerId)) {\n return this.connections.get(peerId)!;\n }\n log('waitForConnection', { peerId });\n await asyncTimeout(\n this.connected.waitFor((connectedId) => connectedId.equals(peerId)),\n // TODO(nf): Make this configurable.\n 10_000,\n );\n return this.connections.get(peerId)!;\n }\n\n async testConnection(peerId: PublicKey, message?: string): Promise<void> {\n const connection = await this.waitForConnection(peerId);\n await connection.test(message);\n }\n\n async openStream(\n peerId: PublicKey,\n streamTag: string,\n streamLoadInterval: number,\n streamLoadChunkSize: number,\n ): Promise<string> {\n if (!this.streamConnections.has(peerId)) {\n throw new Error('Connection does not exist.');\n }\n const connection = this.streamConnections.get(peerId)!;\n return connection.addNewStream(streamLoadInterval, streamLoadChunkSize, streamTag);\n }\n\n async closeStream(peerId: PublicKey, streamTag: string): Promise<TestStreamStats> {\n if (!this.streamConnections.has(peerId)) {\n throw new Error('Connection does not exist.');\n }\n const connection = this.streamConnections.get(peerId)!;\n return connection.closeStream(streamTag);\n }\n}\n","//\n// Copyright 2022 DXOS.org\n//\n\nimport { Context } from '@dxos/context';\nimport { PublicKey } from '@dxos/keys';\nimport { MemorySignalManager, MemorySignalManagerContext, type SignalManager } from '@dxos/messaging';\nimport { schema } from '@dxos/protocols/proto';\nimport { ConnectionState } from '@dxos/protocols/proto/dxos/client/services';\nimport { type ProtoRpcPeer, createLinkedPorts, createProtoRpcPeer } from '@dxos/rpc';\nimport { ComplexMap } from '@dxos/util';\n\nimport { TcpTransportFactory } from '#tcp-transport';\n\nimport { SwarmNetworkManager } from '../network-manager';\nimport { FullyConnectedTopology } from '../topology';\nimport {\n MemoryTransportFactory,\n RtcTransportProxyFactory,\n RtcTransportService,\n type TransportFactory,\n TransportKind,\n createRtcTransportFactory,\n} from '../transport';\nimport { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';\n\nexport type TestBuilderOptions = {\n transport?: TransportKind;\n};\n\n/**\n * Builder used to construct networks and peers.\n */\nexport class TestBuilder {\n private _signalContext = new MemorySignalManagerContext();\n\n constructor(public readonly options: TestBuilderOptions = {}) {}\n\n createSignalManager(): MemorySignalManager {\n // KUBE `WebsocketSignalManager` was removed; signaling is always in-memory (the shared context\n // connects peers in-process). The transport is chosen independently via `options.transport`.\n return new MemorySignalManager(this._signalContext);\n }\n\n createPeer(peerId: PublicKey = PublicKey.random()): TestPeer {\n return new TestPeer(this, peerId, this.options.transport);\n }\n}\n\n/**\n * Testing network peer.\n */\nexport class TestPeer {\n private readonly _swarms = new ComplexMap<PublicKey, TestSwarmConnection>(PublicKey.hash);\n\n /**\n * @internal\n */\n readonly _signalManager: SignalManager;\n\n /**\n * @internal\n */\n readonly _networkManager: SwarmNetworkManager;\n\n private _proxy?: ProtoRpcPeer<any>;\n private _service?: ProtoRpcPeer<any>;\n\n constructor(\n private readonly testBuilder: TestBuilder,\n public readonly peerId: PublicKey,\n public readonly transport: TransportKind = TransportKind.MEMORY,\n ) {\n this._signalManager = this.testBuilder.createSignalManager();\n this._networkManager = this.createNetworkManager(this.transport);\n this._networkManager.setPeerInfo({ identityDid: `did:halo:${peerId.toHex()}`, peerKey: peerId.toHex() });\n }\n\n // TODO(burdon): Move to TestBuilder.\n createNetworkManager(transport: TransportKind): SwarmNetworkManager {\n let transportFactory: TransportFactory;\n switch (transport) {\n case TransportKind.MEMORY:\n transportFactory = MemoryTransportFactory;\n break;\n case TransportKind.TCP:\n transportFactory = TcpTransportFactory;\n break;\n case TransportKind.WEB_RTC:\n transportFactory = createRtcTransportFactory();\n break;\n case TransportKind.WEB_RTC_PROXY:\n {\n // Simulates bridge to shared worker.\n const [proxyPort, servicePort] = createLinkedPorts();\n\n this._proxy = createProtoRpcPeer({\n port: proxyPort,\n requested: {\n BridgeService: schema.getService('dxos.mesh.bridge.BridgeService'),\n },\n noHandshake: true,\n encodingOptions: {\n preserveAny: true,\n },\n });\n\n this._service = createProtoRpcPeer({\n port: servicePort,\n exposed: {\n BridgeService: schema.getService('dxos.mesh.bridge.BridgeService'),\n },\n handlers: { BridgeService: new RtcTransportService() },\n noHandshake: true,\n encodingOptions: {\n preserveAny: true,\n },\n });\n\n transportFactory = new RtcTransportProxyFactory().setBridgeService(this._proxy.rpc.BridgeService);\n }\n break;\n default:\n throw new Error(`Unsupported transport: ${transport}`);\n }\n\n return new SwarmNetworkManager({\n signalManager: this._signalManager,\n transportFactory,\n });\n }\n\n async open(): Promise<void> {\n await this._networkManager.open();\n await this._proxy?.open();\n await this._service?.open();\n }\n\n async close(): Promise<void> {\n await Promise.all(Array.from(this._swarms.values()).map((swarm) => swarm.leave()));\n this._swarms.clear();\n\n await this._proxy?.close();\n await this._service?.close();\n await this._networkManager.close(Context.default());\n }\n\n getSwarm(topic: PublicKey): TestSwarmConnection {\n const swarm = this._swarms.get(topic);\n if (!swarm) {\n throw new Error(`Swarm not found for topic: ${topic}`);\n }\n\n return swarm;\n }\n\n createSwarm(topic: PublicKey, extensionFactory: TestTeleportExtensionFactory = () => []): TestSwarmConnection {\n // TODO(burdon): Multiple.\n // if (this._swarms.get(topic)) {\n // throw new Error(`Swarm already exists for topic: ${topic.truncate()}`);\n // }\n\n const swarm = new TestSwarmConnection(this, topic, extensionFactory);\n this._swarms.set(topic, swarm);\n return swarm;\n }\n\n async goOffline(): Promise<void> {\n await this._networkManager.setConnectionState(ConnectionState.OFFLINE);\n }\n\n async goOnline(): Promise<void> {\n await this._networkManager.setConnectionState(ConnectionState.ONLINE);\n }\n}\n\n// TODO(burdon): Reconcile with new Swarm concept.\nexport class TestSwarmConnection {\n protocol: TestWireProtocol;\n\n constructor(\n readonly peer: TestPeer,\n readonly topic: PublicKey,\n readonly extensionFactory: TestTeleportExtensionFactory,\n ) {\n // TODO(burdon): Configure plugins.\n // TODO(burdon): Prevent reuse?\n this.protocol = new TestWireProtocol(this.extensionFactory);\n }\n\n // TODO(burdon): Need to create new plugin instance per swarm?\n // If so, then perhaps joinSwarm should return swarm object with access to plugins.\n async join(topology = new FullyConnectedTopology()): Promise<this> {\n await this.peer._networkManager.joinSwarm(Context.default(), {\n topic: this.topic,\n peerInfo: { peerKey: this.peer.peerId.toHex(), identityDid: `did:halo:${this.peer.peerId.toHex()}` },\n protocolProvider: this.protocol.factory,\n topology,\n });\n\n return this;\n }\n\n async leave(): Promise<this> {\n await this.peer._networkManager.leaveSwarm(Context.default(), this.topic);\n return this;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Event } from "@dxos/async";
|
|
2
|
+
import { ErrorStream } from "@dxos/debug";
|
|
3
|
+
//#region src/transport/tcp/tcp-transport.browser.ts
|
|
4
|
+
var TcpTransportFactory = { createTransport: () => new TcpTransport() };
|
|
5
|
+
/**
|
|
6
|
+
* NOTE: Browser stub.
|
|
7
|
+
*/
|
|
8
|
+
var TcpTransport = class {
|
|
9
|
+
closed = new Event();
|
|
10
|
+
connected = new Event();
|
|
11
|
+
errors = new ErrorStream();
|
|
12
|
+
get isOpen() {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
async open() {
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
async close() {
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
async onSignal() {
|
|
22
|
+
throw new Error("Method not implemented.");
|
|
23
|
+
}
|
|
24
|
+
async getStats() {
|
|
25
|
+
throw new Error("Method not implemented.");
|
|
26
|
+
}
|
|
27
|
+
async getDetails() {
|
|
28
|
+
throw new Error("Method not implemented.");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { TcpTransport, TcpTransportFactory };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=tcp-transport.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-transport.browser.mjs","names":[],"sources":["../../../../src/transport/tcp/tcp-transport.browser.ts"],"sourcesContent":["//\n// Copyright 2020 DXOS.org\n//\n\nimport { Event } from '@dxos/async';\nimport { ErrorStream } from '@dxos/debug';\n\nimport { type Transport, type TransportFactory, type TransportStats } from '../transport';\n\nexport const TcpTransportFactory: TransportFactory = {\n createTransport: () => new TcpTransport(),\n};\n\n/**\n * NOTE: Browser stub.\n */\nexport class TcpTransport implements Transport {\n public readonly closed = new Event<void>();\n public readonly connected = new Event<void>();\n public readonly errors = new ErrorStream();\n\n get isOpen() {\n return true;\n }\n\n async open(): Promise<this> {\n return this;\n }\n\n async close(): Promise<this> {\n return this;\n }\n\n async onSignal(): Promise<void> {\n throw new Error('Method not implemented.');\n }\n\n async getStats(): Promise<TransportStats> {\n throw new Error('Method not implemented.');\n }\n\n async getDetails(): Promise<string> {\n throw new Error('Method not implemented.');\n }\n}\n"],"mappings":";;;AASA,IAAa,sBAAwC,EACnD,uBAAuB,IAAI,aAAa,EAC1C;;;;AAKA,IAAa,eAAb,MAA+C;CAC7C,SAAyB,IAAI,MAAY;CACzC,YAA4B,IAAI,MAAY;CAC5C,SAAyB,IAAI,YAAY;CAEzC,IAAI,SAAS;EACX,OAAO;CACT;CAEA,MAAM,OAAsB;EAC1B,OAAO;CACT;CAEA,MAAM,QAAuB;EAC3B,OAAO;CACT;CAEA,MAAM,WAA0B;EAC9B,MAAM,IAAI,MAAM,yBAAyB;CAC3C;CAEA,MAAM,WAAoC;EACxC,MAAM,IAAI,MAAM,yBAAyB;CAC3C;CAEA,MAAM,aAA8B;EAClC,MAAM,IAAI,MAAM,yBAAyB;CAC3C;AACF"}
|