@streamr/dht 103.3.0 → 103.6.0-rc.0
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/exports-browser.cjs +549 -100
- package/dist/exports-browser.cjs.map +1 -1
- package/dist/exports-browser.d.ts +6 -4
- package/dist/exports-browser.js +530 -101
- package/dist/exports-browser.js.map +1 -1
- package/dist/exports-nodejs.cjs +10 -1
- package/dist/exports-nodejs.cjs.map +1 -1
- package/dist/exports-nodejs.d.ts +9 -4
- package/dist/exports-nodejs.js +10 -2
- package/dist/exports-nodejs.js.map +1 -1
- package/package.json +13 -8
package/dist/exports-browser.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import 'timers-browserify';
|
|
1
2
|
import { binaryToHex, hexToBinary, randomBytes, areEqualBinaries, Logger, computeMd5, Defer, MetricsContext, CountMetric, LevelMetric, RateMetric, waitForEvent, setAbortableTimeout, raceForEvent, ipv4ToNumber, wait, EcdsaSecp256k1Evm, Gate, withTimeout, scheduleAtInterval, MapWithTtl, executeSafePromise, merge, addManagedEventListener, until } from '@streamr/utils';
|
|
2
3
|
import { EventEmitter } from 'eventemitter3';
|
|
3
4
|
import sample from 'lodash/sample';
|
|
@@ -8,6 +9,7 @@ import { ServiceType, stackIntercept } from '@protobuf-ts/runtime-rpc';
|
|
|
8
9
|
import { v4 } from 'uuid';
|
|
9
10
|
import { ProtoCallContext, RpcCommunicator, toProtoRpcClient, protoClasses as protoClasses$1, RpcError } from '@streamr/proto-rpc';
|
|
10
11
|
import ipaddr from 'ipaddr.js';
|
|
12
|
+
import * as Comlink from 'comlink';
|
|
11
13
|
import { w3cwebsocket } from 'websocket';
|
|
12
14
|
import { SERVICE_ID } from '@streamr/autocertifier-client';
|
|
13
15
|
import shuffle from 'lodash/shuffle';
|
|
@@ -1797,7 +1799,7 @@ const createRandomConnectionId = () => {
|
|
|
1797
1799
|
return v4();
|
|
1798
1800
|
};
|
|
1799
1801
|
|
|
1800
|
-
const logger$
|
|
1802
|
+
const logger$D = new Logger('ManagedConnection');
|
|
1801
1803
|
// ManagedConnection is a component used as a wrapper for IConnection after they have been successfully handshaked.
|
|
1802
1804
|
// Should only be used in the ConnectionManager.
|
|
1803
1805
|
class ManagedConnection extends EventEmitter {
|
|
@@ -1827,7 +1829,7 @@ class ManagedConnection extends EventEmitter {
|
|
|
1827
1829
|
this.remotePeerDescriptor = peerDescriptor;
|
|
1828
1830
|
}
|
|
1829
1831
|
onDisconnected(gracefulLeave) {
|
|
1830
|
-
logger$
|
|
1832
|
+
logger$D.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' onDisconnected() ' + gracefulLeave);
|
|
1831
1833
|
if (!this.replacedAsDuplicate) {
|
|
1832
1834
|
this.emit('disconnected', gracefulLeave);
|
|
1833
1835
|
}
|
|
@@ -1836,7 +1838,7 @@ class ManagedConnection extends EventEmitter {
|
|
|
1836
1838
|
// TODO: Can this be removed if ManagedConnections can never be duplicates?
|
|
1837
1839
|
// Handle duplicates in the ConncetorFacade and no longer have PendingConnections in ConnectionManager
|
|
1838
1840
|
replaceAsDuplicate() {
|
|
1839
|
-
logger$
|
|
1841
|
+
logger$D.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
|
|
1840
1842
|
this.replacedAsDuplicate = true;
|
|
1841
1843
|
}
|
|
1842
1844
|
send(data) {
|
|
@@ -1983,10 +1985,10 @@ class RpcRemote {
|
|
|
1983
1985
|
}
|
|
1984
1986
|
}
|
|
1985
1987
|
|
|
1986
|
-
const logger$
|
|
1988
|
+
const logger$C = new Logger('ConnectionLockRpcRemote');
|
|
1987
1989
|
class ConnectionLockRpcRemote extends RpcRemote {
|
|
1988
1990
|
async lockRequest(lockId) {
|
|
1989
|
-
logger$
|
|
1991
|
+
logger$C.trace(`Requesting locked connection to ${toNodeId(this.getPeerDescriptor())}`);
|
|
1990
1992
|
const request = {
|
|
1991
1993
|
lockId
|
|
1992
1994
|
};
|
|
@@ -1996,12 +1998,12 @@ class ConnectionLockRpcRemote extends RpcRemote {
|
|
|
1996
1998
|
return res.accepted;
|
|
1997
1999
|
}
|
|
1998
2000
|
catch (err) {
|
|
1999
|
-
logger$
|
|
2001
|
+
logger$C.debug('Connection lock rejected', { err });
|
|
2000
2002
|
return false;
|
|
2001
2003
|
}
|
|
2002
2004
|
}
|
|
2003
2005
|
unlockRequest(lockId) {
|
|
2004
|
-
logger$
|
|
2006
|
+
logger$C.trace(`Requesting connection to be unlocked from ${toNodeId(this.getPeerDescriptor())}`);
|
|
2005
2007
|
const request = {
|
|
2006
2008
|
lockId
|
|
2007
2009
|
};
|
|
@@ -2009,11 +2011,11 @@ class ConnectionLockRpcRemote extends RpcRemote {
|
|
|
2009
2011
|
notification: true
|
|
2010
2012
|
});
|
|
2011
2013
|
this.getClient().unlockRequest(request, options).catch((_e) => {
|
|
2012
|
-
logger$
|
|
2014
|
+
logger$C.trace('failed to send unlockRequest');
|
|
2013
2015
|
});
|
|
2014
2016
|
}
|
|
2015
2017
|
async gracefulDisconnect(disconnectMode) {
|
|
2016
|
-
logger$
|
|
2018
|
+
logger$C.trace(`Notifying a graceful disconnect to ${toNodeId(this.getPeerDescriptor())}`);
|
|
2017
2019
|
const request = {
|
|
2018
2020
|
disconnectMode
|
|
2019
2021
|
};
|
|
@@ -2025,7 +2027,7 @@ class ConnectionLockRpcRemote extends RpcRemote {
|
|
|
2025
2027
|
await this.getClient().gracefulDisconnect(request, options);
|
|
2026
2028
|
}
|
|
2027
2029
|
async setPrivate(isPrivate) {
|
|
2028
|
-
logger$
|
|
2030
|
+
logger$C.trace(`Setting isPrivate: ${isPrivate} for ${toNodeId(this.getPeerDescriptor())}`);
|
|
2029
2031
|
const request = {
|
|
2030
2032
|
isPrivate
|
|
2031
2033
|
};
|
|
@@ -2037,7 +2039,7 @@ class ConnectionLockRpcRemote extends RpcRemote {
|
|
|
2037
2039
|
}
|
|
2038
2040
|
}
|
|
2039
2041
|
|
|
2040
|
-
const logger$
|
|
2042
|
+
const logger$B = new Logger('ConnectionLockRpcLocal');
|
|
2041
2043
|
class ConnectionLockRpcLocal {
|
|
2042
2044
|
options;
|
|
2043
2045
|
constructor(options) {
|
|
@@ -2066,7 +2068,7 @@ class ConnectionLockRpcLocal {
|
|
|
2066
2068
|
}
|
|
2067
2069
|
async gracefulDisconnect(disconnectNotice, context) {
|
|
2068
2070
|
const senderPeerDescriptor = context.incomingSourceDescriptor;
|
|
2069
|
-
logger$
|
|
2071
|
+
logger$B.trace(getNodeIdOrUnknownFromPeerDescriptor(senderPeerDescriptor) + ' received gracefulDisconnect notice');
|
|
2070
2072
|
if (disconnectNotice.disconnectMode === DisconnectMode.LEAVING) {
|
|
2071
2073
|
await this.options.closeConnection(senderPeerDescriptor, true, 'graceful leave notified');
|
|
2072
2074
|
}
|
|
@@ -2117,7 +2119,7 @@ var NatType;
|
|
|
2117
2119
|
NatType["OPEN_INTERNET"] = "open_internet";
|
|
2118
2120
|
NatType["UNKNOWN"] = "unknown";
|
|
2119
2121
|
})(NatType || (NatType = {}));
|
|
2120
|
-
const logger$
|
|
2122
|
+
const logger$A = new Logger('ConnectionManager');
|
|
2121
2123
|
var ConnectionManagerState;
|
|
2122
2124
|
(function (ConnectionManagerState) {
|
|
2123
2125
|
ConnectionManagerState["IDLE"] = "idle";
|
|
@@ -2167,7 +2169,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2167
2169
|
getLocalPeerDescriptor: () => this.getLocalPeerDescriptor(),
|
|
2168
2170
|
setPrivate: (id, isPrivate) => {
|
|
2169
2171
|
if (!this.options.allowIncomingPrivateConnections) {
|
|
2170
|
-
logger$
|
|
2172
|
+
logger$A.debug(`node ${id} attemted to set a connection as private, but it is not allowed`);
|
|
2171
2173
|
return;
|
|
2172
2174
|
}
|
|
2173
2175
|
if (isPrivate) {
|
|
@@ -2201,7 +2203,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2201
2203
|
const connection = endpoint.connection;
|
|
2202
2204
|
const nodeId = connection.getNodeId();
|
|
2203
2205
|
if (!this.locks.isLocked(nodeId) && !this.locks.isPrivate(nodeId) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
|
|
2204
|
-
logger$
|
|
2206
|
+
logger$A.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()));
|
|
2205
2207
|
disconnectionCandidates.addContact(connection);
|
|
2206
2208
|
}
|
|
2207
2209
|
}
|
|
@@ -2209,7 +2211,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2209
2211
|
const disconnectables = disconnectionCandidates.getFurthestContacts(this.endpoints.size - maxConnections);
|
|
2210
2212
|
for (const disconnectable of disconnectables) {
|
|
2211
2213
|
const peerDescriptor = disconnectable.getPeerDescriptor();
|
|
2212
|
-
logger$
|
|
2214
|
+
logger$A.trace('garbageCollecting ' + toNodeId(peerDescriptor));
|
|
2213
2215
|
this.gracefullyDisconnectAsync(peerDescriptor, DisconnectMode.NORMAL).catch((_e) => { });
|
|
2214
2216
|
}
|
|
2215
2217
|
}
|
|
@@ -2218,11 +2220,11 @@ class ConnectionManager extends EventEmitter {
|
|
|
2218
2220
|
throw new CouldNotStart(`Cannot start already ${this.state} module`);
|
|
2219
2221
|
}
|
|
2220
2222
|
this.state = ConnectionManagerState.RUNNING;
|
|
2221
|
-
logger$
|
|
2223
|
+
logger$A.trace(`Starting ConnectionManager...`);
|
|
2222
2224
|
await this.connectorFacade.start((connection) => this.onNewConnection(connection), (nodeId) => this.hasConnection(nodeId), this);
|
|
2223
2225
|
// Garbage collection of connections
|
|
2224
2226
|
this.disconnectorIntervalRef = setInterval(() => {
|
|
2225
|
-
logger$
|
|
2227
|
+
logger$A.trace('disconnectorInterval');
|
|
2226
2228
|
const LAST_USED_LIMIT = 20000;
|
|
2227
2229
|
this.garbageCollectConnections(this.options.maxConnections ?? 80, LAST_USED_LIMIT);
|
|
2228
2230
|
}, 5000); // TODO use options option or named constant?
|
|
@@ -2232,7 +2234,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2232
2234
|
return;
|
|
2233
2235
|
}
|
|
2234
2236
|
this.state = ConnectionManagerState.STOPPING;
|
|
2235
|
-
logger$
|
|
2237
|
+
logger$A.trace(`Stopping ConnectionManager`);
|
|
2236
2238
|
if (this.disconnectorIntervalRef) {
|
|
2237
2239
|
clearInterval(this.disconnectorIntervalRef);
|
|
2238
2240
|
}
|
|
@@ -2242,23 +2244,23 @@ class ConnectionManager extends EventEmitter {
|
|
|
2242
2244
|
await this.gracefullyDisconnectAsync(endpoint.connection.getPeerDescriptor(), DisconnectMode.LEAVING);
|
|
2243
2245
|
}
|
|
2244
2246
|
catch (e) {
|
|
2245
|
-
logger$
|
|
2247
|
+
logger$A.error(e);
|
|
2246
2248
|
}
|
|
2247
2249
|
}
|
|
2248
2250
|
else {
|
|
2249
2251
|
const connection = endpoint.connection;
|
|
2250
|
-
logger$
|
|
2252
|
+
logger$A.trace('handshake of connection not completed, force-closing');
|
|
2251
2253
|
// TODO use options option or named constant?
|
|
2252
2254
|
const eventReceived = waitForEvent(connection, 'disconnected', 2000);
|
|
2253
2255
|
// TODO should we have some handling for this floating promise?
|
|
2254
2256
|
connection.close(true);
|
|
2255
2257
|
try {
|
|
2256
2258
|
await eventReceived;
|
|
2257
|
-
logger$
|
|
2259
|
+
logger$A.trace('resolving after receiving disconnected event from non-handshaked connection');
|
|
2258
2260
|
}
|
|
2259
2261
|
catch (e) {
|
|
2260
2262
|
endpoint.buffer.reject();
|
|
2261
|
-
logger$
|
|
2263
|
+
logger$A.trace('force-closing non-handshaked connection timed out ' + e);
|
|
2262
2264
|
}
|
|
2263
2265
|
}
|
|
2264
2266
|
}));
|
|
@@ -2287,7 +2289,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2287
2289
|
throw new CannotConnectToSelf('Cannot send to self');
|
|
2288
2290
|
}
|
|
2289
2291
|
const nodeId = toNodeId(peerDescriptor);
|
|
2290
|
-
logger$
|
|
2292
|
+
logger$A.trace(`Sending message to: ${nodeId}`);
|
|
2291
2293
|
message = {
|
|
2292
2294
|
...message,
|
|
2293
2295
|
sourceDescriptor: this.getLocalPeerDescriptor()
|
|
@@ -2342,13 +2344,13 @@ class ConnectionManager extends EventEmitter {
|
|
|
2342
2344
|
}
|
|
2343
2345
|
handleMessage(message) {
|
|
2344
2346
|
const messageType = message.body.oneofKind;
|
|
2345
|
-
logger$
|
|
2347
|
+
logger$A.trace('Received message of type ' + messageType);
|
|
2346
2348
|
if (messageType !== 'rpcMessage') {
|
|
2347
|
-
logger$
|
|
2349
|
+
logger$A.trace('Filtered out non-RPC message of type ' + messageType);
|
|
2348
2350
|
return;
|
|
2349
2351
|
}
|
|
2350
2352
|
if (this.duplicateMessageDetector.isMostLikelyDuplicate(message.messageId)) {
|
|
2351
|
-
logger$
|
|
2353
|
+
logger$A.trace('handleMessage filtered duplicate ' + toNodeId(message.sourceDescriptor)
|
|
2352
2354
|
+ ' ' + message.serviceId + ' ' + message.messageId);
|
|
2353
2355
|
return;
|
|
2354
2356
|
}
|
|
@@ -2357,7 +2359,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2357
2359
|
this.rpcCommunicator?.handleMessageFromPeer(message);
|
|
2358
2360
|
}
|
|
2359
2361
|
else {
|
|
2360
|
-
logger$
|
|
2362
|
+
logger$A.trace('emit "message" ' + toNodeId(message.sourceDescriptor)
|
|
2361
2363
|
+ ' ' + message.serviceId + ' ' + message.messageId);
|
|
2362
2364
|
this.emit('message', message);
|
|
2363
2365
|
}
|
|
@@ -2374,7 +2376,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2374
2376
|
}
|
|
2375
2377
|
catch (e) {
|
|
2376
2378
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
2377
|
-
logger$
|
|
2379
|
+
logger$A.debug(`Parsing incoming data into Message failed: ${e}`);
|
|
2378
2380
|
return;
|
|
2379
2381
|
}
|
|
2380
2382
|
message.sourceDescriptor = peerDescriptor;
|
|
@@ -2383,7 +2385,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2383
2385
|
}
|
|
2384
2386
|
catch (e) {
|
|
2385
2387
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
2386
|
-
logger$
|
|
2388
|
+
logger$A.debug(`Handling incoming data failed: ${e}`);
|
|
2387
2389
|
}
|
|
2388
2390
|
}
|
|
2389
2391
|
onConnected(peerDescriptor, connection) {
|
|
@@ -2396,7 +2398,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2396
2398
|
const pendingConnection = endpoint.connection;
|
|
2397
2399
|
const buffer = outputBuffer.getBuffer();
|
|
2398
2400
|
while (buffer.length > 0) {
|
|
2399
|
-
logger$
|
|
2401
|
+
logger$A.trace('emptying buffer');
|
|
2400
2402
|
managedConnection.send(buffer.shift());
|
|
2401
2403
|
}
|
|
2402
2404
|
outputBuffer.resolve();
|
|
@@ -2413,7 +2415,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2413
2415
|
}
|
|
2414
2416
|
onDisconnected(peerDescriptor, gracefulLeave) {
|
|
2415
2417
|
const nodeId = toNodeId(peerDescriptor);
|
|
2416
|
-
logger$
|
|
2418
|
+
logger$A.trace(nodeId + ' onDisconnected() gracefulLeave: ' + gracefulLeave);
|
|
2417
2419
|
const endpoint = this.endpoints.get(nodeId);
|
|
2418
2420
|
if (endpoint) {
|
|
2419
2421
|
this.locks.clearAllLocks(nodeId);
|
|
@@ -2421,7 +2423,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2421
2423
|
endpoint.buffer.reject();
|
|
2422
2424
|
}
|
|
2423
2425
|
this.endpoints.delete(nodeId);
|
|
2424
|
-
logger$
|
|
2426
|
+
logger$A.trace(nodeId + ' deleted connection in onDisconnected() gracefulLeave: ' + gracefulLeave);
|
|
2425
2427
|
this.emit('disconnected', peerDescriptor, gracefulLeave);
|
|
2426
2428
|
this.onConnectionCountChange();
|
|
2427
2429
|
}
|
|
@@ -2430,7 +2432,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2430
2432
|
if (this.state === ConnectionManagerState.STOPPED) {
|
|
2431
2433
|
return false;
|
|
2432
2434
|
}
|
|
2433
|
-
logger$
|
|
2435
|
+
logger$A.trace('onNewConnection()');
|
|
2434
2436
|
if (!this.acceptNewConnection(connection)) {
|
|
2435
2437
|
return false;
|
|
2436
2438
|
}
|
|
@@ -2440,7 +2442,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2440
2442
|
}
|
|
2441
2443
|
acceptNewConnection(newConnection) {
|
|
2442
2444
|
const nodeId = toNodeId(newConnection.getPeerDescriptor());
|
|
2443
|
-
logger$
|
|
2445
|
+
logger$A.trace(nodeId + ' acceptNewConnection()');
|
|
2444
2446
|
if (this.endpoints.has(nodeId)) {
|
|
2445
2447
|
if (getOfferer(toNodeId(this.getLocalPeerDescriptor()), nodeId) === 'remote') {
|
|
2446
2448
|
let buffer;
|
|
@@ -2449,14 +2451,14 @@ class ConnectionManager extends EventEmitter {
|
|
|
2449
2451
|
// Could be related to WS client connections not realizing that they have been disconnected.
|
|
2450
2452
|
// Makes refactoring duplicate connection handling to the connectors very difficult.
|
|
2451
2453
|
if (this.endpoints.get(nodeId).connected) {
|
|
2452
|
-
logger$
|
|
2454
|
+
logger$A.debug('replacing connected connection', { nodeId });
|
|
2453
2455
|
buffer = new OutputBuffer();
|
|
2454
2456
|
}
|
|
2455
2457
|
else {
|
|
2456
2458
|
buffer = endpoint.buffer;
|
|
2457
2459
|
}
|
|
2458
2460
|
const oldConnection = endpoint.connection;
|
|
2459
|
-
logger$
|
|
2461
|
+
logger$A.trace('replaced: ' + nodeId);
|
|
2460
2462
|
oldConnection.replaceAsDuplicate();
|
|
2461
2463
|
this.endpoints.set(nodeId, { connected: false, connection: newConnection, buffer: buffer });
|
|
2462
2464
|
return true;
|
|
@@ -2465,7 +2467,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2465
2467
|
return false;
|
|
2466
2468
|
}
|
|
2467
2469
|
}
|
|
2468
|
-
logger$
|
|
2470
|
+
logger$A.trace(nodeId + ' added to connections at acceptNewConnection');
|
|
2469
2471
|
this.endpoints.set(nodeId, {
|
|
2470
2472
|
connected: false,
|
|
2471
2473
|
buffer: new OutputBuffer(),
|
|
@@ -2475,14 +2477,14 @@ class ConnectionManager extends EventEmitter {
|
|
|
2475
2477
|
}
|
|
2476
2478
|
async closeConnection(peerDescriptor, gracefulLeave, reason) {
|
|
2477
2479
|
const nodeId = toNodeId(peerDescriptor);
|
|
2478
|
-
logger$
|
|
2480
|
+
logger$A.trace(nodeId + ' ' + 'closeConnection() ' + reason);
|
|
2479
2481
|
this.locks.clearAllLocks(nodeId);
|
|
2480
2482
|
if (this.endpoints.has(nodeId)) {
|
|
2481
2483
|
const connectionToClose = this.endpoints.get(nodeId).connection;
|
|
2482
2484
|
await connectionToClose.close(gracefulLeave);
|
|
2483
2485
|
}
|
|
2484
2486
|
else {
|
|
2485
|
-
logger$
|
|
2487
|
+
logger$A.trace(nodeId + ' ' + 'closeConnection() this.endpoints did not have the id');
|
|
2486
2488
|
this.emit('disconnected', peerDescriptor, false);
|
|
2487
2489
|
}
|
|
2488
2490
|
}
|
|
@@ -2494,8 +2496,8 @@ class ConnectionManager extends EventEmitter {
|
|
|
2494
2496
|
const rpcRemote = new ConnectionLockRpcRemote(this.getLocalPeerDescriptor(), targetDescriptor, this.rpcCommunicator, ConnectionLockRpcClient);
|
|
2495
2497
|
this.locks.addLocalLocked(nodeId, lockId);
|
|
2496
2498
|
rpcRemote.lockRequest(lockId)
|
|
2497
|
-
.then((_accepted) => logger$
|
|
2498
|
-
.catch((err) => { logger$
|
|
2499
|
+
.then((_accepted) => logger$A.trace('LockRequest successful'))
|
|
2500
|
+
.catch((err) => { logger$A.debug(err); });
|
|
2499
2501
|
}
|
|
2500
2502
|
unlockConnection(targetDescriptor, lockId) {
|
|
2501
2503
|
if (this.state === ConnectionManagerState.STOPPED || areEqualPeerDescriptors(targetDescriptor, this.getLocalPeerDescriptor())) {
|
|
@@ -2547,7 +2549,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
2547
2549
|
async gracefullyDisconnectAsync(targetDescriptor, disconnectMode) {
|
|
2548
2550
|
const endpoint = this.endpoints.get(toNodeId(targetDescriptor));
|
|
2549
2551
|
if (!endpoint) {
|
|
2550
|
-
logger$
|
|
2552
|
+
logger$A.debug('gracefullyDisconnectedAsync() tried on a non-existing connection');
|
|
2551
2553
|
return;
|
|
2552
2554
|
}
|
|
2553
2555
|
if (endpoint.connected) {
|
|
@@ -2556,15 +2558,15 @@ class ConnectionManager extends EventEmitter {
|
|
|
2556
2558
|
// TODO use options option or named constant?
|
|
2557
2559
|
// eslint-disable-next-line promise/catch-or-return
|
|
2558
2560
|
waitForEvent(connection, 'disconnected', 2000).then(() => {
|
|
2559
|
-
logger$
|
|
2561
|
+
logger$A.trace('disconnected event received in gracefullyDisconnectAsync()');
|
|
2560
2562
|
})
|
|
2561
2563
|
.catch((e) => {
|
|
2562
|
-
logger$
|
|
2564
|
+
logger$A.trace('force-closing connection after timeout ' + e);
|
|
2563
2565
|
// TODO should we have some handling for this floating promise?
|
|
2564
2566
|
connection.close(true);
|
|
2565
2567
|
})
|
|
2566
2568
|
.finally(() => {
|
|
2567
|
-
logger$
|
|
2569
|
+
logger$A.trace('resolving after receiving disconnected event');
|
|
2568
2570
|
resolve();
|
|
2569
2571
|
});
|
|
2570
2572
|
});
|
|
@@ -2579,13 +2581,13 @@ class ConnectionManager extends EventEmitter {
|
|
|
2579
2581
|
}
|
|
2580
2582
|
async doGracefullyDisconnectAsync(targetDescriptor, disconnectMode) {
|
|
2581
2583
|
const nodeId = toNodeId(targetDescriptor);
|
|
2582
|
-
logger$
|
|
2584
|
+
logger$A.trace(nodeId + ' gracefullyDisconnectAsync()');
|
|
2583
2585
|
const rpcRemote = new ConnectionLockRpcRemote(this.getLocalPeerDescriptor(), targetDescriptor, this.rpcCommunicator, ConnectionLockRpcClient);
|
|
2584
2586
|
try {
|
|
2585
2587
|
await rpcRemote.gracefulDisconnect(disconnectMode);
|
|
2586
2588
|
}
|
|
2587
2589
|
catch (ex) {
|
|
2588
|
-
logger$
|
|
2590
|
+
logger$A.trace(nodeId + ' remote.gracefulDisconnect() failed' + ex);
|
|
2589
2591
|
}
|
|
2590
2592
|
}
|
|
2591
2593
|
getConnections() {
|
|
@@ -2652,7 +2654,7 @@ function protoToString(protoObj, objectType) {
|
|
|
2652
2654
|
return ret;
|
|
2653
2655
|
}
|
|
2654
2656
|
|
|
2655
|
-
const logger$
|
|
2657
|
+
const logger$z = new Logger('SimulatorConnection');
|
|
2656
2658
|
class SimulatorConnection extends Connection {
|
|
2657
2659
|
stopped = false;
|
|
2658
2660
|
localPeerDescriptor;
|
|
@@ -2674,46 +2676,46 @@ class SimulatorConnection extends Connection {
|
|
|
2674
2676
|
this.doDisconnect = this.doDisconnect.bind(this);
|
|
2675
2677
|
}
|
|
2676
2678
|
send(data) {
|
|
2677
|
-
logger$
|
|
2679
|
+
logger$z.trace('send()');
|
|
2678
2680
|
if (!this.stopped) {
|
|
2679
2681
|
this.simulator.send(this, data);
|
|
2680
2682
|
}
|
|
2681
2683
|
else {
|
|
2682
2684
|
const localNodeId = toNodeId(this.localPeerDescriptor);
|
|
2683
2685
|
const targetNodeId = toNodeId(this.targetPeerDescriptor);
|
|
2684
|
-
logger$
|
|
2686
|
+
logger$z.error(localNodeId + ', ' + targetNodeId + 'tried to send() on a stopped connection');
|
|
2685
2687
|
}
|
|
2686
2688
|
}
|
|
2687
2689
|
async close(gracefulLeave) {
|
|
2688
2690
|
const localNodeId = toNodeId(this.localPeerDescriptor);
|
|
2689
2691
|
const targetNodeId = toNodeId(this.targetPeerDescriptor);
|
|
2690
|
-
logger$
|
|
2692
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' close()');
|
|
2691
2693
|
if (!this.stopped) {
|
|
2692
|
-
logger$
|
|
2694
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' close() not stopped');
|
|
2693
2695
|
this.stopped = true;
|
|
2694
2696
|
try {
|
|
2695
|
-
logger$
|
|
2697
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' close() calling simulator.disconnect()');
|
|
2696
2698
|
this.simulator.close(this);
|
|
2697
|
-
logger$
|
|
2699
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' close() simulator.disconnect returned');
|
|
2698
2700
|
}
|
|
2699
2701
|
catch (e) {
|
|
2700
|
-
logger$
|
|
2702
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + 'close aborted' + e);
|
|
2701
2703
|
}
|
|
2702
2704
|
finally {
|
|
2703
|
-
logger$
|
|
2705
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' calling this.doDisconnect');
|
|
2704
2706
|
this.doDisconnect(gracefulLeave);
|
|
2705
2707
|
}
|
|
2706
2708
|
}
|
|
2707
2709
|
else {
|
|
2708
|
-
logger$
|
|
2710
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' close() tried to close a stopped connection');
|
|
2709
2711
|
}
|
|
2710
2712
|
}
|
|
2711
2713
|
connect() {
|
|
2712
2714
|
if (!this.stopped) {
|
|
2713
|
-
logger$
|
|
2715
|
+
logger$z.trace('connect() called');
|
|
2714
2716
|
this.simulator.connect(this, this.targetPeerDescriptor, (error) => {
|
|
2715
2717
|
if (error !== undefined) {
|
|
2716
|
-
logger$
|
|
2718
|
+
logger$z.trace(error);
|
|
2717
2719
|
this.doDisconnect(false);
|
|
2718
2720
|
}
|
|
2719
2721
|
else {
|
|
@@ -2722,46 +2724,46 @@ class SimulatorConnection extends Connection {
|
|
|
2722
2724
|
});
|
|
2723
2725
|
}
|
|
2724
2726
|
else {
|
|
2725
|
-
logger$
|
|
2727
|
+
logger$z.trace('tried to connect() a stopped connection');
|
|
2726
2728
|
}
|
|
2727
2729
|
}
|
|
2728
2730
|
handleIncomingData(data) {
|
|
2729
2731
|
if (!this.stopped) {
|
|
2730
|
-
logger$
|
|
2732
|
+
logger$z.trace('handleIncomingData() ' + protoToString(Message.fromBinary(data), Message));
|
|
2731
2733
|
this.emit('data', data);
|
|
2732
2734
|
}
|
|
2733
2735
|
else {
|
|
2734
|
-
logger$
|
|
2736
|
+
logger$z.trace('tried to call handleIncomingData() a stopped connection');
|
|
2735
2737
|
}
|
|
2736
2738
|
}
|
|
2737
2739
|
handleIncomingDisconnection() {
|
|
2738
2740
|
if (!this.stopped) {
|
|
2739
2741
|
const localNodeId = toNodeId(this.localPeerDescriptor);
|
|
2740
|
-
logger$
|
|
2742
|
+
logger$z.trace(localNodeId + ' handleIncomingDisconnection()');
|
|
2741
2743
|
this.stopped = true;
|
|
2742
2744
|
this.doDisconnect(false);
|
|
2743
2745
|
}
|
|
2744
2746
|
else {
|
|
2745
|
-
logger$
|
|
2747
|
+
logger$z.trace('tried to call handleIncomingDisconnection() a stopped connection');
|
|
2746
2748
|
}
|
|
2747
2749
|
}
|
|
2748
2750
|
destroy() {
|
|
2749
2751
|
const localNodeId = toNodeId(this.localPeerDescriptor);
|
|
2750
2752
|
if (!this.stopped) {
|
|
2751
|
-
logger$
|
|
2753
|
+
logger$z.trace(localNodeId + ' destroy()');
|
|
2752
2754
|
this.removeAllListeners();
|
|
2753
2755
|
this.close(false).catch((_e) => { });
|
|
2754
2756
|
}
|
|
2755
2757
|
else {
|
|
2756
|
-
logger$
|
|
2758
|
+
logger$z.trace(localNodeId + ' tried to call destroy() a stopped connection');
|
|
2757
2759
|
}
|
|
2758
2760
|
}
|
|
2759
2761
|
doDisconnect(gracefulLeave) {
|
|
2760
2762
|
const localNodeId = toNodeId(this.localPeerDescriptor);
|
|
2761
2763
|
const targetNodeId = toNodeId(this.targetPeerDescriptor);
|
|
2762
|
-
logger$
|
|
2764
|
+
logger$z.trace(localNodeId + ' doDisconnect()');
|
|
2763
2765
|
this.stopped = true;
|
|
2764
|
-
logger$
|
|
2766
|
+
logger$z.trace(localNodeId + ', ' + targetNodeId + ' doDisconnect emitting');
|
|
2765
2767
|
this.emit('disconnected', gracefulLeave);
|
|
2766
2768
|
}
|
|
2767
2769
|
}
|
|
@@ -2799,9 +2801,9 @@ const parseVersion = (version) => {
|
|
|
2799
2801
|
}
|
|
2800
2802
|
};
|
|
2801
2803
|
|
|
2802
|
-
var version = "103.
|
|
2804
|
+
var version = "103.6.0-rc.0";
|
|
2803
2805
|
|
|
2804
|
-
const logger$
|
|
2806
|
+
const logger$y = new Logger('Handshaker');
|
|
2805
2807
|
// Optimally the Outgoing and Incoming Handshakers could be their own separate classes
|
|
2806
2808
|
// However, in cases where the PeerDescriptor of the other end of the connection can be known
|
|
2807
2809
|
// only after a HandshakeRequest a base Handshaker class is needed as the IncomingHandshaker currently
|
|
@@ -2823,7 +2825,7 @@ const createOutgoingHandshaker = (localPeerDescriptor, pendingConnection, connec
|
|
|
2823
2825
|
}
|
|
2824
2826
|
};
|
|
2825
2827
|
const handshakeCompletedListener = (peerDescriptor) => {
|
|
2826
|
-
logger$
|
|
2828
|
+
logger$y.trace('handshake completed for outgoing connection, ' + toNodeId(peerDescriptor));
|
|
2827
2829
|
pendingConnection.onHandshakeCompleted(connection);
|
|
2828
2830
|
stopHandshaker();
|
|
2829
2831
|
};
|
|
@@ -2923,12 +2925,12 @@ class Handshaker extends EventEmitter {
|
|
|
2923
2925
|
try {
|
|
2924
2926
|
const message = Message.fromBinary(data);
|
|
2925
2927
|
if (message.body.oneofKind === 'handshakeRequest') {
|
|
2926
|
-
logger$
|
|
2928
|
+
logger$y.trace('handshake request received');
|
|
2927
2929
|
const handshake = message.body.handshakeRequest;
|
|
2928
2930
|
this.emit('handshakeRequest', handshake.sourcePeerDescriptor, handshake.protocolVersion, handshake.targetPeerDescriptor);
|
|
2929
2931
|
}
|
|
2930
2932
|
if (message.body.oneofKind === 'handshakeResponse') {
|
|
2931
|
-
logger$
|
|
2933
|
+
logger$y.trace('handshake response received');
|
|
2932
2934
|
const handshake = message.body.handshakeResponse;
|
|
2933
2935
|
const error = !isMaybeSupportedProtocolVersion(handshake.protocolVersion)
|
|
2934
2936
|
? HandshakeError.UNSUPPORTED_PROTOCOL_VERSION : handshake.error;
|
|
@@ -2941,18 +2943,18 @@ class Handshaker extends EventEmitter {
|
|
|
2941
2943
|
}
|
|
2942
2944
|
}
|
|
2943
2945
|
catch (err) {
|
|
2944
|
-
logger$
|
|
2946
|
+
logger$y.debug('error while parsing handshake message', err);
|
|
2945
2947
|
}
|
|
2946
2948
|
}
|
|
2947
2949
|
sendHandshakeRequest(remotePeerDescriptor) {
|
|
2948
2950
|
const msg = createHandshakeRequest(this.localPeerDescriptor, remotePeerDescriptor);
|
|
2949
2951
|
this.connection.send(Message.toBinary(msg));
|
|
2950
|
-
logger$
|
|
2952
|
+
logger$y.trace('handshake request sent');
|
|
2951
2953
|
}
|
|
2952
2954
|
sendHandshakeResponse(error) {
|
|
2953
2955
|
const msg = createHandshakeResponse(this.localPeerDescriptor, error);
|
|
2954
2956
|
this.connection.send(Message.toBinary(msg));
|
|
2955
|
-
logger$
|
|
2957
|
+
logger$y.trace('handshake response sent');
|
|
2956
2958
|
}
|
|
2957
2959
|
stop() {
|
|
2958
2960
|
this.connection.off('data', this.onDataListener);
|
|
@@ -2960,7 +2962,7 @@ class Handshaker extends EventEmitter {
|
|
|
2960
2962
|
}
|
|
2961
2963
|
}
|
|
2962
2964
|
|
|
2963
|
-
const logger$
|
|
2965
|
+
const logger$x = new Logger('PendingConnection');
|
|
2964
2966
|
// PendingConnection is used as a reference to a connection that should be opened and handshaked to a given PeerDescriptor
|
|
2965
2967
|
// It does not hold a connection internally. The public method onHandshakedCompleted should be called once a connection for the
|
|
2966
2968
|
// remotePeerDescriptor is opened and handshaked successfully.
|
|
@@ -2978,7 +2980,7 @@ class PendingConnection extends EventEmitter {
|
|
|
2978
2980
|
}, timeout, this.connectingAbortController.signal);
|
|
2979
2981
|
}
|
|
2980
2982
|
replaceAsDuplicate() {
|
|
2981
|
-
logger$
|
|
2983
|
+
logger$x.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
|
|
2982
2984
|
this.replacedAsDuplicate = true;
|
|
2983
2985
|
}
|
|
2984
2986
|
onHandshakeCompleted(connection) {
|
|
@@ -3009,7 +3011,7 @@ class PendingConnection extends EventEmitter {
|
|
|
3009
3011
|
}
|
|
3010
3012
|
}
|
|
3011
3013
|
|
|
3012
|
-
const logger$
|
|
3014
|
+
const logger$w = new Logger('SimulatorConnector');
|
|
3013
3015
|
class SimulatorConnector {
|
|
3014
3016
|
connectingConnections = new Map();
|
|
3015
3017
|
stopped = false;
|
|
@@ -3022,7 +3024,7 @@ class SimulatorConnector {
|
|
|
3022
3024
|
this.onNewConnection = onNewConnection;
|
|
3023
3025
|
}
|
|
3024
3026
|
connect(targetPeerDescriptor) {
|
|
3025
|
-
logger$
|
|
3027
|
+
logger$w.trace('connect() ' + toNodeId(targetPeerDescriptor));
|
|
3026
3028
|
const nodeId = toNodeId(targetPeerDescriptor);
|
|
3027
3029
|
const existingConnection = this.connectingConnections.get(nodeId);
|
|
3028
3030
|
if (existingConnection) {
|
|
@@ -3051,18 +3053,18 @@ class SimulatorConnector {
|
|
|
3051
3053
|
// connection is incoming, so remotePeerDescriptor is localPeerDescriptor
|
|
3052
3054
|
const remotePeerDescriptor = sourceConnection.localPeerDescriptor;
|
|
3053
3055
|
const remoteNodeId = toNodeId(sourceConnection.localPeerDescriptor);
|
|
3054
|
-
logger$
|
|
3056
|
+
logger$w.trace(remoteNodeId + ' incoming connection, stopped: ' + this.stopped);
|
|
3055
3057
|
if (this.stopped) {
|
|
3056
3058
|
return;
|
|
3057
3059
|
}
|
|
3058
3060
|
const connection = new SimulatorConnection(this.localPeerDescriptor, remotePeerDescriptor, ConnectionType.SIMULATOR_SERVER, this.simulator);
|
|
3059
3061
|
const pendingConnection = new PendingConnection(remotePeerDescriptor);
|
|
3060
3062
|
const handshaker = createIncomingHandshaker(this.localPeerDescriptor, pendingConnection, connection);
|
|
3061
|
-
logger$
|
|
3063
|
+
logger$w.trace('connected');
|
|
3062
3064
|
handshaker.once('handshakeRequest', () => {
|
|
3063
|
-
logger$
|
|
3065
|
+
logger$w.trace(remoteNodeId + ' incoming handshake request');
|
|
3064
3066
|
if (this.onNewConnection(pendingConnection)) {
|
|
3065
|
-
logger$
|
|
3067
|
+
logger$w.trace(remoteNodeId + ' calling acceptHandshake');
|
|
3066
3068
|
acceptHandshake(handshaker, pendingConnection, connection);
|
|
3067
3069
|
}
|
|
3068
3070
|
else {
|
|
@@ -3102,6 +3104,8 @@ class ListeningRpcCommunicator extends RoutingRpcCommunicator {
|
|
|
3102
3104
|
}
|
|
3103
3105
|
}
|
|
3104
3106
|
|
|
3107
|
+
const isWorkerEnvironment = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
|
|
3108
|
+
|
|
3105
3109
|
var RtcDescription;
|
|
3106
3110
|
(function (RtcDescription) {
|
|
3107
3111
|
RtcDescription["OFFER"] = "offer";
|
|
@@ -3116,8 +3120,8 @@ var DisconnectedRtcPeerConnectionStateEnum;
|
|
|
3116
3120
|
DisconnectedRtcPeerConnectionStateEnum["FAILED"] = "failed";
|
|
3117
3121
|
DisconnectedRtcPeerConnectionStateEnum["CLOSED"] = "closed";
|
|
3118
3122
|
})(DisconnectedRtcPeerConnectionStateEnum || (DisconnectedRtcPeerConnectionStateEnum = {}));
|
|
3119
|
-
const logger$
|
|
3120
|
-
class
|
|
3123
|
+
const logger$v = new Logger('DirectWebrtcConnection (browser)');
|
|
3124
|
+
class DirectWebrtcConnection extends EventEmitter {
|
|
3121
3125
|
connectionId;
|
|
3122
3126
|
connectionType = ConnectionType.WEBRTC;
|
|
3123
3127
|
// We need to keep track of connection state ourselves because
|
|
@@ -3155,7 +3159,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3155
3159
|
}
|
|
3156
3160
|
};
|
|
3157
3161
|
this.peerConnection.onicegatheringstatechange = () => {
|
|
3158
|
-
logger$
|
|
3162
|
+
logger$v.trace(`conn.onGatheringStateChange: ${this.peerConnection?.iceGatheringState}`);
|
|
3159
3163
|
};
|
|
3160
3164
|
this.peerConnection.onconnectionstatechange = () => this.onStateChange();
|
|
3161
3165
|
if (isOffering) {
|
|
@@ -3166,7 +3170,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3166
3170
|
await this.peerConnection.setLocalDescription();
|
|
3167
3171
|
}
|
|
3168
3172
|
catch (err) {
|
|
3169
|
-
logger$
|
|
3173
|
+
logger$v.warn('Failed to set local description', { err });
|
|
3170
3174
|
}
|
|
3171
3175
|
if (this.peerConnection.localDescription !== null) {
|
|
3172
3176
|
this.emit('localDescription', this.peerConnection.localDescription?.sdp, this.peerConnection.localDescription?.type);
|
|
@@ -3194,14 +3198,14 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3194
3198
|
clearTimeout(this.earlyTimeout);
|
|
3195
3199
|
}
|
|
3196
3200
|
catch (err) {
|
|
3197
|
-
logger$
|
|
3201
|
+
logger$v.warn('Failed to set remote description', { err });
|
|
3198
3202
|
}
|
|
3199
3203
|
if ((type.toLowerCase() === RtcDescription.OFFER) && (this.peerConnection !== undefined)) {
|
|
3200
3204
|
try {
|
|
3201
3205
|
await this.peerConnection.setLocalDescription();
|
|
3202
3206
|
}
|
|
3203
3207
|
catch (err) {
|
|
3204
|
-
logger$
|
|
3208
|
+
logger$v.warn('Failed to set local description', { err });
|
|
3205
3209
|
}
|
|
3206
3210
|
if (this.peerConnection.localDescription !== null) {
|
|
3207
3211
|
this.emit('localDescription', this.peerConnection.localDescription.sdp, this.peerConnection.localDescription.type);
|
|
@@ -3211,7 +3215,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3211
3215
|
addRemoteCandidate(candidate, mid) {
|
|
3212
3216
|
this.peerConnection?.addIceCandidate({ candidate: candidate, sdpMid: mid })
|
|
3213
3217
|
.catch((err) => {
|
|
3214
|
-
logger$
|
|
3218
|
+
logger$v.warn('Failed to add ICE candidate', { err });
|
|
3215
3219
|
});
|
|
3216
3220
|
}
|
|
3217
3221
|
isOpen() {
|
|
@@ -3234,7 +3238,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3234
3238
|
this.dataChannel.close();
|
|
3235
3239
|
}
|
|
3236
3240
|
catch (err) {
|
|
3237
|
-
logger$
|
|
3241
|
+
logger$v.warn('Failed to close data channel', { err });
|
|
3238
3242
|
}
|
|
3239
3243
|
}
|
|
3240
3244
|
this.dataChannel = undefined;
|
|
@@ -3243,7 +3247,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3243
3247
|
this.peerConnection.close();
|
|
3244
3248
|
}
|
|
3245
3249
|
catch (err) {
|
|
3246
|
-
logger$
|
|
3250
|
+
logger$v.warn('Failed to close connection', { err });
|
|
3247
3251
|
}
|
|
3248
3252
|
}
|
|
3249
3253
|
this.peerConnection = undefined;
|
|
@@ -3263,7 +3267,7 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3263
3267
|
}
|
|
3264
3268
|
}
|
|
3265
3269
|
else {
|
|
3266
|
-
logger$
|
|
3270
|
+
logger$v.warn('Tried to send on a connection with last state ' + this.lastState);
|
|
3267
3271
|
}
|
|
3268
3272
|
}
|
|
3269
3273
|
setupDataChannel(dataChannel) {
|
|
@@ -3271,22 +3275,22 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3271
3275
|
this.dataChannel.binaryType = 'arraybuffer';
|
|
3272
3276
|
this.dataChannel.bufferedAmountLowThreshold = this.bufferThresholdLow;
|
|
3273
3277
|
dataChannel.onopen = () => {
|
|
3274
|
-
logger$
|
|
3278
|
+
logger$v.trace('dc.onOpen');
|
|
3275
3279
|
this.onDataChannelOpen();
|
|
3276
3280
|
};
|
|
3277
3281
|
dataChannel.onclose = () => {
|
|
3278
|
-
logger$
|
|
3282
|
+
logger$v.trace('dc.onClosed');
|
|
3279
3283
|
this.doClose(false);
|
|
3280
3284
|
};
|
|
3281
3285
|
dataChannel.onerror = (err) => {
|
|
3282
|
-
logger$
|
|
3286
|
+
logger$v.warn('Data channel error', { err });
|
|
3283
3287
|
};
|
|
3284
3288
|
dataChannel.onmessage = (msg) => {
|
|
3285
|
-
logger$
|
|
3289
|
+
logger$v.trace('dc.onmessage');
|
|
3286
3290
|
this.emit('data', new Uint8Array(msg.data));
|
|
3287
3291
|
};
|
|
3288
3292
|
dataChannel.onbufferedamountlow = () => {
|
|
3289
|
-
logger$
|
|
3293
|
+
logger$v.trace('dc.onBufferedAmountLow');
|
|
3290
3294
|
while (this.messageQueue.length > 0 && this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
|
|
3291
3295
|
const data = this.messageQueue.shift();
|
|
3292
3296
|
this.dataChannel.send(data);
|
|
@@ -3325,6 +3329,431 @@ class WebrtcConnection extends EventEmitter {
|
|
|
3325
3329
|
}
|
|
3326
3330
|
}
|
|
3327
3331
|
|
|
3332
|
+
/**
|
|
3333
|
+
* WebrtcBridge — runs on the MAIN THREAD.
|
|
3334
|
+
*
|
|
3335
|
+
* Manages RTCPeerConnection instances on behalf of a worker that cannot
|
|
3336
|
+
* access them directly. Each logical connection is identified by a
|
|
3337
|
+
* `connectionId` string supplied by the worker.
|
|
3338
|
+
*
|
|
3339
|
+
* Signaling (ICE candidates, SDP offers/answers, connection-state changes)
|
|
3340
|
+
* is relayed to the worker through Comlink proxy callbacks.
|
|
3341
|
+
*
|
|
3342
|
+
* Once a DataChannel is created (offerer) or received (answerer) it is
|
|
3343
|
+
* **transferred** to the worker so that all data-path events fire inside
|
|
3344
|
+
* the worker's event loop — the main thread never touches data traffic.
|
|
3345
|
+
*/
|
|
3346
|
+
// ── Bridge implementation ───────────────────────────────────────────
|
|
3347
|
+
class WebrtcBridge {
|
|
3348
|
+
connections = new Map();
|
|
3349
|
+
async start(connectionId, iceServers, isOffering, callbacks) {
|
|
3350
|
+
const pc = new RTCPeerConnection({ iceServers });
|
|
3351
|
+
const conn = {
|
|
3352
|
+
pc,
|
|
3353
|
+
callbacks,
|
|
3354
|
+
isOffering,
|
|
3355
|
+
makingOffer: false,
|
|
3356
|
+
};
|
|
3357
|
+
this.connections.set(connectionId, conn);
|
|
3358
|
+
// ── ICE candidates ──────────────────────────────────────
|
|
3359
|
+
pc.onicecandidate = (event) => {
|
|
3360
|
+
if (event.candidate !== null && event.candidate.sdpMid !== null) {
|
|
3361
|
+
callbacks.onLocalCandidate(event.candidate.candidate, event.candidate.sdpMid);
|
|
3362
|
+
}
|
|
3363
|
+
};
|
|
3364
|
+
// ── Connection state → forwarded to worker ──────────────
|
|
3365
|
+
pc.onconnectionstatechange = () => {
|
|
3366
|
+
callbacks.onConnectionStateChange(pc.connectionState);
|
|
3367
|
+
};
|
|
3368
|
+
// ── Offerer path ────────────────────────────────────────
|
|
3369
|
+
if (isOffering) {
|
|
3370
|
+
pc.onnegotiationneeded = async () => {
|
|
3371
|
+
conn.makingOffer = true;
|
|
3372
|
+
try {
|
|
3373
|
+
await pc.setLocalDescription();
|
|
3374
|
+
}
|
|
3375
|
+
catch (_err) {
|
|
3376
|
+
// intentionally swallowed – mirrors DirectWebrtcConnection
|
|
3377
|
+
}
|
|
3378
|
+
if (pc.localDescription !== null) {
|
|
3379
|
+
callbacks.onLocalDescription(pc.localDescription.sdp, pc.localDescription.type);
|
|
3380
|
+
}
|
|
3381
|
+
conn.makingOffer = false;
|
|
3382
|
+
};
|
|
3383
|
+
const dc = pc.createDataChannel('streamrDataChannel');
|
|
3384
|
+
// Transfer DataChannel ownership to the worker immediately.
|
|
3385
|
+
// The worker will attach onopen/onclose/onmessage handlers.
|
|
3386
|
+
callbacks.onDataChannel(Comlink.transfer(dc, [dc]));
|
|
3387
|
+
}
|
|
3388
|
+
else {
|
|
3389
|
+
// ── Answerer path ───────────────────────────────────
|
|
3390
|
+
pc.ondatachannel = (event) => {
|
|
3391
|
+
callbacks.onDataChannel(Comlink.transfer(event.channel, [event.channel]));
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
async setRemoteDescription(connectionId, description, type) {
|
|
3396
|
+
const conn = this.connections.get(connectionId);
|
|
3397
|
+
if (!conn) {
|
|
3398
|
+
return false;
|
|
3399
|
+
}
|
|
3400
|
+
const lowerType = type.toLowerCase();
|
|
3401
|
+
// Perfect-negotiation collision detection
|
|
3402
|
+
const offerCollision = lowerType === 'offer' &&
|
|
3403
|
+
(conn.makingOffer || conn.pc.signalingState !== 'stable');
|
|
3404
|
+
if (conn.isOffering && offerCollision) {
|
|
3405
|
+
return false;
|
|
3406
|
+
}
|
|
3407
|
+
try {
|
|
3408
|
+
await conn.pc.setRemoteDescription({ sdp: description, type: lowerType });
|
|
3409
|
+
}
|
|
3410
|
+
catch (_err) {
|
|
3411
|
+
return false;
|
|
3412
|
+
}
|
|
3413
|
+
// If we received an offer, create an answer
|
|
3414
|
+
if (lowerType === 'offer') {
|
|
3415
|
+
try {
|
|
3416
|
+
await conn.pc.setLocalDescription();
|
|
3417
|
+
}
|
|
3418
|
+
catch (_err) {
|
|
3419
|
+
// intentionally swallowed
|
|
3420
|
+
}
|
|
3421
|
+
if (conn.pc.localDescription !== null) {
|
|
3422
|
+
conn.callbacks.onLocalDescription(conn.pc.localDescription.sdp, conn.pc.localDescription.type);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
return true;
|
|
3426
|
+
}
|
|
3427
|
+
async addRemoteCandidate(connectionId, candidate, mid) {
|
|
3428
|
+
const conn = this.connections.get(connectionId);
|
|
3429
|
+
if (!conn) {
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
try {
|
|
3433
|
+
await conn.pc.addIceCandidate({ candidate, sdpMid: mid });
|
|
3434
|
+
}
|
|
3435
|
+
catch (_err) {
|
|
3436
|
+
// intentionally swallowed
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
async renameConnection(oldId, newId) {
|
|
3440
|
+
const conn = this.connections.get(oldId);
|
|
3441
|
+
if (conn) {
|
|
3442
|
+
this.connections.delete(oldId);
|
|
3443
|
+
this.connections.set(newId, conn);
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
async close(connectionId) {
|
|
3447
|
+
const conn = this.connections.get(connectionId);
|
|
3448
|
+
if (!conn) {
|
|
3449
|
+
return;
|
|
3450
|
+
}
|
|
3451
|
+
this.connections.delete(connectionId);
|
|
3452
|
+
// Tear down event handlers
|
|
3453
|
+
conn.pc.onicecandidate = null;
|
|
3454
|
+
conn.pc.onconnectionstatechange = null;
|
|
3455
|
+
conn.pc.onnegotiationneeded = null;
|
|
3456
|
+
conn.pc.ondatachannel = null;
|
|
3457
|
+
try {
|
|
3458
|
+
conn.pc.close();
|
|
3459
|
+
}
|
|
3460
|
+
catch (_err) {
|
|
3461
|
+
// intentionally swallowed
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
/**
|
|
3467
|
+
* Call this function on the **main thread** before the worker starts using
|
|
3468
|
+
* WebRTC connections. It creates a dedicated `MessageChannel`, exposes a
|
|
3469
|
+
* {@link WebrtcBridge} instance on one port, and sends the other port to
|
|
3470
|
+
* the worker so that `WorkerWebrtcConnection` can reach the bridge.
|
|
3471
|
+
*
|
|
3472
|
+
* @example
|
|
3473
|
+
* ```ts
|
|
3474
|
+
* import { installWebrtcBridge } from '@streamr/dht'
|
|
3475
|
+
*
|
|
3476
|
+
* const worker = new Worker('./my-worker.ts', { type: 'module' })
|
|
3477
|
+
* installWebrtcBridge(worker)
|
|
3478
|
+
* ```
|
|
3479
|
+
*/
|
|
3480
|
+
const WEBRTC_BRIDGE_PORT_MESSAGE_TYPE = 'streamr-webrtc-bridge-port';
|
|
3481
|
+
function installWebrtcBridge(worker) {
|
|
3482
|
+
const bridge = new WebrtcBridge();
|
|
3483
|
+
const channel = new MessageChannel();
|
|
3484
|
+
// Expose the bridge API on port1 — the worker will Comlink.wrap(port2).
|
|
3485
|
+
Comlink.expose(bridge, channel.port1);
|
|
3486
|
+
// Send port2 to the worker. It is transferred (not cloned).
|
|
3487
|
+
worker.postMessage({ type: WEBRTC_BRIDGE_PORT_MESSAGE_TYPE, port: channel.port2 }, [channel.port2]);
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
/**
|
|
3491
|
+
* WorkerWebrtcConnection — runs inside a **Web Worker**.
|
|
3492
|
+
*
|
|
3493
|
+
* Implements the same IWebrtcConnection + IConnection interfaces as
|
|
3494
|
+
* DirectWebrtcConnection, but delegates RTCPeerConnection management to
|
|
3495
|
+
* the main-thread {@link WebrtcBridge} via Comlink.
|
|
3496
|
+
*
|
|
3497
|
+
* The RTCDataChannel is **transferred** from the main thread and lives
|
|
3498
|
+
* entirely in the worker — all data events (onmessage, onopen, onclose,
|
|
3499
|
+
* onbufferedamountlow) fire in the worker's event loop. The main thread
|
|
3500
|
+
* is never involved in the data path.
|
|
3501
|
+
*/
|
|
3502
|
+
// ── Module-level bridge client (initialized once per worker) ────────
|
|
3503
|
+
let resolveBridgeProxy;
|
|
3504
|
+
const bridgeProxyPromise = new Promise((resolve) => {
|
|
3505
|
+
resolveBridgeProxy = resolve;
|
|
3506
|
+
});
|
|
3507
|
+
// Listen for the bridge port message from the main thread.
|
|
3508
|
+
// This is guarded so it only runs inside a worker context.
|
|
3509
|
+
if (isWorkerEnvironment) {
|
|
3510
|
+
const handler = (e) => {
|
|
3511
|
+
if (e.data?.type === WEBRTC_BRIDGE_PORT_MESSAGE_TYPE && e.data.port) {
|
|
3512
|
+
const proxy = Comlink.wrap(e.data.port);
|
|
3513
|
+
resolveBridgeProxy(proxy);
|
|
3514
|
+
self.removeEventListener('message', handler);
|
|
3515
|
+
}
|
|
3516
|
+
};
|
|
3517
|
+
self.addEventListener('message', handler);
|
|
3518
|
+
}
|
|
3519
|
+
function getBridgeProxy() {
|
|
3520
|
+
return bridgeProxyPromise;
|
|
3521
|
+
}
|
|
3522
|
+
// ── Disconnection states ────────────────────────────────────────────
|
|
3523
|
+
var DisconnectedState;
|
|
3524
|
+
(function (DisconnectedState) {
|
|
3525
|
+
DisconnectedState["DISCONNECTED"] = "disconnected";
|
|
3526
|
+
DisconnectedState["FAILED"] = "failed";
|
|
3527
|
+
DisconnectedState["CLOSED"] = "closed";
|
|
3528
|
+
})(DisconnectedState || (DisconnectedState = {}));
|
|
3529
|
+
const logger$u = new Logger('WorkerWebrtcConnection');
|
|
3530
|
+
// ── WorkerWebrtcConnection ──────────────────────────────────────────
|
|
3531
|
+
class WorkerWebrtcConnection extends EventEmitter {
|
|
3532
|
+
connectionId;
|
|
3533
|
+
connectionType = ConnectionType.WEBRTC;
|
|
3534
|
+
iceServers;
|
|
3535
|
+
bufferThresholdHigh;
|
|
3536
|
+
bufferThresholdLow;
|
|
3537
|
+
dataChannel;
|
|
3538
|
+
bridge;
|
|
3539
|
+
closed = false;
|
|
3540
|
+
connected = false;
|
|
3541
|
+
earlyTimeout;
|
|
3542
|
+
messageQueue = [];
|
|
3543
|
+
startPromise;
|
|
3544
|
+
constructor(params) {
|
|
3545
|
+
super();
|
|
3546
|
+
this.connectionId = createRandomConnectionId();
|
|
3547
|
+
this.iceServers = params.iceServers ?? [];
|
|
3548
|
+
this.bufferThresholdHigh = params.bufferThresholdHigh ?? 2 ** 17;
|
|
3549
|
+
this.bufferThresholdLow = params.bufferThresholdLow ?? 2 ** 15;
|
|
3550
|
+
this.earlyTimeout = setTimeout(() => {
|
|
3551
|
+
this.doClose(false, 'timed out due to remote descriptor not being set');
|
|
3552
|
+
}, EARLY_TIMEOUT);
|
|
3553
|
+
}
|
|
3554
|
+
// ── IWebrtcConnection ───────────────────────────────────────
|
|
3555
|
+
start(isOffering) {
|
|
3556
|
+
this.startPromise = this.doStart(isOffering);
|
|
3557
|
+
this.startPromise.catch((err) => {
|
|
3558
|
+
logger$u.warn('Failed to start worker WebRTC connection', { err });
|
|
3559
|
+
this.doClose(false, 'Failed to start');
|
|
3560
|
+
});
|
|
3561
|
+
}
|
|
3562
|
+
async doStart(isOffering) {
|
|
3563
|
+
this.bridge = await getBridgeProxy();
|
|
3564
|
+
const iceServers = this.iceServers.map(({ url, port, username, password }) => ({
|
|
3565
|
+
urls: `${url}:${port}`,
|
|
3566
|
+
username,
|
|
3567
|
+
credential: password,
|
|
3568
|
+
}));
|
|
3569
|
+
await this.bridge.start(this.connectionId, iceServers, isOffering, Comlink.proxy({
|
|
3570
|
+
onLocalCandidate: (candidate, mid) => {
|
|
3571
|
+
if (!this.closed) {
|
|
3572
|
+
this.emit('localCandidate', candidate, mid);
|
|
3573
|
+
}
|
|
3574
|
+
},
|
|
3575
|
+
onLocalDescription: (description, type) => {
|
|
3576
|
+
if (!this.closed) {
|
|
3577
|
+
this.emit('localDescription', description, type);
|
|
3578
|
+
}
|
|
3579
|
+
},
|
|
3580
|
+
onConnectionStateChange: (state) => {
|
|
3581
|
+
if (state === DisconnectedState.CLOSED ||
|
|
3582
|
+
state === DisconnectedState.DISCONNECTED ||
|
|
3583
|
+
state === DisconnectedState.FAILED) {
|
|
3584
|
+
this.doClose(false);
|
|
3585
|
+
}
|
|
3586
|
+
},
|
|
3587
|
+
onDataChannel: (channel) => {
|
|
3588
|
+
if (!this.closed) {
|
|
3589
|
+
this.setupDataChannel(channel);
|
|
3590
|
+
// If the channel was already open at transfer time
|
|
3591
|
+
if (channel.readyState === 'open') {
|
|
3592
|
+
this.onDataChannelOpen();
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
},
|
|
3596
|
+
}));
|
|
3597
|
+
}
|
|
3598
|
+
async setRemoteDescription(description, type) {
|
|
3599
|
+
if (this.startPromise) {
|
|
3600
|
+
await this.startPromise;
|
|
3601
|
+
}
|
|
3602
|
+
if (!this.bridge || this.closed) {
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
const wasSet = await this.bridge.setRemoteDescription(this.connectionId, description, type);
|
|
3606
|
+
if (wasSet) {
|
|
3607
|
+
clearTimeout(this.earlyTimeout);
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
addRemoteCandidate(candidate, mid) {
|
|
3611
|
+
this.doAddRemoteCandidate(candidate, mid).catch((err) => {
|
|
3612
|
+
logger$u.warn('Failed to add remote candidate via bridge', { err });
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3615
|
+
async doAddRemoteCandidate(candidate, mid) {
|
|
3616
|
+
if (this.startPromise) {
|
|
3617
|
+
await this.startPromise;
|
|
3618
|
+
}
|
|
3619
|
+
if (!this.bridge || this.closed) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
await this.bridge.addRemoteCandidate(this.connectionId, candidate, mid);
|
|
3623
|
+
}
|
|
3624
|
+
isOpen() {
|
|
3625
|
+
return this.connected;
|
|
3626
|
+
}
|
|
3627
|
+
// ── IConnection ─────────────────────────────────────────────
|
|
3628
|
+
async close(gracefulLeave, reason) {
|
|
3629
|
+
this.doClose(gracefulLeave, reason);
|
|
3630
|
+
}
|
|
3631
|
+
destroy() {
|
|
3632
|
+
this.removeAllListeners();
|
|
3633
|
+
this.doClose(false);
|
|
3634
|
+
}
|
|
3635
|
+
send(data) {
|
|
3636
|
+
if (this.connected && this.dataChannel) {
|
|
3637
|
+
if (this.dataChannel.bufferedAmount > this.bufferThresholdHigh) {
|
|
3638
|
+
this.messageQueue.push(data);
|
|
3639
|
+
}
|
|
3640
|
+
else {
|
|
3641
|
+
this.dataChannel.send(data);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
else if (!this.closed) {
|
|
3645
|
+
this.messageQueue.push(data);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
setConnectionId(connectionId) {
|
|
3649
|
+
const oldId = this.connectionId;
|
|
3650
|
+
this.connectionId = connectionId;
|
|
3651
|
+
if (this.bridge && oldId !== connectionId) {
|
|
3652
|
+
this.bridge.renameConnection(oldId, connectionId).catch(() => { });
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
// ── DataChannel handling (runs entirely in the worker) ──────
|
|
3656
|
+
setupDataChannel(dataChannel) {
|
|
3657
|
+
this.dataChannel = dataChannel;
|
|
3658
|
+
this.dataChannel.binaryType = 'arraybuffer';
|
|
3659
|
+
this.dataChannel.bufferedAmountLowThreshold = this.bufferThresholdLow;
|
|
3660
|
+
dataChannel.onopen = () => {
|
|
3661
|
+
logger$u.trace('dc.onOpen (worker)');
|
|
3662
|
+
this.onDataChannelOpen();
|
|
3663
|
+
};
|
|
3664
|
+
dataChannel.onclose = () => {
|
|
3665
|
+
logger$u.trace('dc.onClosed (worker)');
|
|
3666
|
+
this.doClose(false);
|
|
3667
|
+
};
|
|
3668
|
+
dataChannel.onerror = (err) => {
|
|
3669
|
+
logger$u.warn('Data channel error (worker)', { err });
|
|
3670
|
+
};
|
|
3671
|
+
dataChannel.onmessage = (msg) => {
|
|
3672
|
+
logger$u.trace('dc.onmessage (worker)');
|
|
3673
|
+
this.emit('data', new Uint8Array(msg.data));
|
|
3674
|
+
};
|
|
3675
|
+
dataChannel.onbufferedamountlow = () => {
|
|
3676
|
+
logger$u.trace('dc.onBufferedAmountLow (worker)');
|
|
3677
|
+
while (this.messageQueue.length > 0 &&
|
|
3678
|
+
this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
|
|
3679
|
+
const data = this.messageQueue.shift();
|
|
3680
|
+
this.dataChannel.send(data);
|
|
3681
|
+
}
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
onDataChannelOpen() {
|
|
3685
|
+
this.connected = true;
|
|
3686
|
+
this.flushMessageQueue();
|
|
3687
|
+
this.emit('connected');
|
|
3688
|
+
}
|
|
3689
|
+
flushMessageQueue() {
|
|
3690
|
+
while (this.messageQueue.length > 0 &&
|
|
3691
|
+
this.dataChannel &&
|
|
3692
|
+
this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
|
|
3693
|
+
const data = this.messageQueue.shift();
|
|
3694
|
+
this.dataChannel.send(data);
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
// ── Teardown ────────────────────────────────────────────────
|
|
3698
|
+
doClose(gracefulLeave, reason) {
|
|
3699
|
+
if (!this.closed) {
|
|
3700
|
+
this.closed = true;
|
|
3701
|
+
this.connected = false;
|
|
3702
|
+
this.messageQueue.length = 0;
|
|
3703
|
+
clearTimeout(this.earlyTimeout);
|
|
3704
|
+
this.stopListening();
|
|
3705
|
+
this.emit('disconnected', gracefulLeave, undefined, reason);
|
|
3706
|
+
this.removeAllListeners();
|
|
3707
|
+
if (this.dataChannel !== undefined) {
|
|
3708
|
+
try {
|
|
3709
|
+
this.dataChannel.close();
|
|
3710
|
+
}
|
|
3711
|
+
catch (err) {
|
|
3712
|
+
logger$u.warn('Failed to close data channel (worker)', { err });
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
this.dataChannel = undefined;
|
|
3716
|
+
// Tell the main-thread bridge to tear down the RTCPeerConnection.
|
|
3717
|
+
// Fire-and-forget — we don't block on this.
|
|
3718
|
+
this.bridge
|
|
3719
|
+
?.close(this.connectionId)
|
|
3720
|
+
.catch(() => {
|
|
3721
|
+
// intentionally swallowed
|
|
3722
|
+
});
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
stopListening() {
|
|
3726
|
+
if (this.dataChannel !== undefined) {
|
|
3727
|
+
this.dataChannel.onopen = null;
|
|
3728
|
+
this.dataChannel.onclose = null;
|
|
3729
|
+
this.dataChannel.onerror = null;
|
|
3730
|
+
this.dataChannel.onbufferedamountlow = null;
|
|
3731
|
+
this.dataChannel.onmessage = null;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
/**
|
|
3737
|
+
* Conditional re-export of the browser WebrtcConnection.
|
|
3738
|
+
*
|
|
3739
|
+
* At module-load time we detect whether we are running inside a Web Worker.
|
|
3740
|
+
* - **Main thread** → use {@link DirectWebrtcConnection} which owns the
|
|
3741
|
+
* `RTCPeerConnection` and `RTCDataChannel` directly.
|
|
3742
|
+
* - **Worker thread** → use {@link WorkerWebrtcConnection} which delegates
|
|
3743
|
+
* `RTCPeerConnection` signaling to the main thread via a Comlink bridge
|
|
3744
|
+
* and receives a transferred `RTCDataChannel` that lives entirely in the
|
|
3745
|
+
* worker.
|
|
3746
|
+
*
|
|
3747
|
+
* Both classes implement `IWebrtcConnection & IConnection` and expose the
|
|
3748
|
+
* same public API, so upstream code (WebrtcConnector, etc.) is unaffected.
|
|
3749
|
+
*/
|
|
3750
|
+
// The constructor — points to the right class based on the runtime
|
|
3751
|
+
// environment. The type assertion is safe because both implementations
|
|
3752
|
+
// share the same public interface surface.
|
|
3753
|
+
const WebrtcConnection = (isWorkerEnvironment
|
|
3754
|
+
? WorkerWebrtcConnection
|
|
3755
|
+
: DirectWebrtcConnection);
|
|
3756
|
+
|
|
3328
3757
|
const logger$t = new Logger('WebrtcConnectorRpcRemote');
|
|
3329
3758
|
class WebrtcConnectorRpcRemote extends RpcRemote {
|
|
3330
3759
|
requestConnection() {
|
|
@@ -7607,5 +8036,5 @@ class SimulatorTransport extends ConnectionManager {
|
|
|
7607
8036
|
}
|
|
7608
8037
|
}
|
|
7609
8038
|
|
|
7610
|
-
export { ConnectionManager, ConnectionType, DataEntry, DefaultConnectorFacade, DhtCallContext, DhtNode, EXISTING_CONNECTION_TIMEOUT, LatencyType, ListeningRpcCommunicator, ManagedConnection, Message, NodeType, PeerDescriptor, PendingConnection, RoutingRpcCommunicator, RpcRemote, Simulator, SimulatorTransport, WebsocketClientConnection, areEqualPeerDescriptors, createOutgoingHandshaker, getRandomRegion, getRegionDelayMatrix, randomDhtAddress, toDhtAddress, toDhtAddressRaw, toNodeId };
|
|
8039
|
+
export { ConnectionManager, ConnectionType, DataEntry, DefaultConnectorFacade, DhtCallContext, DhtNode, EXISTING_CONNECTION_TIMEOUT, LatencyType, ListeningRpcCommunicator, ManagedConnection, Message, NodeType, PeerDescriptor, PendingConnection, RoutingRpcCommunicator, RpcRemote, Simulator, SimulatorTransport, WebsocketClientConnection, areEqualPeerDescriptors, createOutgoingHandshaker, getRandomRegion, getRegionDelayMatrix, installWebrtcBridge, randomDhtAddress, toDhtAddress, toDhtAddressRaw, toNodeId };
|
|
7611
8040
|
//# sourceMappingURL=exports-browser.js.map
|