libp2p 0.43.4 → 0.44.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/index.min.js +30 -30
- package/dist/src/autonat/index.d.ts +1 -2
- package/dist/src/autonat/index.d.ts.map +1 -1
- package/dist/src/autonat/index.js +4 -6
- package/dist/src/autonat/index.js.map +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.d.ts +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/circuit-relay/utils.d.ts.map +1 -1
- package/dist/src/circuit-relay/utils.js +3 -1
- package/dist/src/circuit-relay/utils.js.map +1 -1
- package/dist/src/components.d.ts +1 -6
- package/dist/src/components.d.ts.map +1 -1
- package/dist/src/components.js +0 -10
- package/dist/src/components.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +0 -9
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/auto-dial.d.ts +36 -0
- package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
- package/dist/src/connection-manager/auto-dial.js +122 -0
- package/dist/src/connection-manager/auto-dial.js.map +1 -0
- package/dist/src/connection-manager/connection-pruner.d.ts +28 -0
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
- package/dist/src/connection-manager/connection-pruner.js +96 -0
- package/dist/src/connection-manager/connection-pruner.js.map +1 -0
- package/dist/src/connection-manager/constants.d.ts +49 -0
- package/dist/src/connection-manager/constants.d.ts.map +1 -0
- package/dist/src/connection-manager/constants.js +49 -0
- package/dist/src/connection-manager/constants.js.map +1 -0
- package/dist/src/connection-manager/dial-queue.d.ts +77 -0
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
- package/dist/src/connection-manager/dial-queue.js +366 -0
- package/dist/src/connection-manager/dial-queue.js.map +1 -0
- package/dist/src/connection-manager/index.d.ts +65 -69
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +116 -234
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts +9 -0
- package/dist/src/connection-manager/utils.d.ts.map +1 -0
- package/dist/src/connection-manager/utils.js +66 -0
- package/dist/src/connection-manager/utils.js.map +1 -0
- package/dist/src/fetch/index.js +3 -3
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/index.js +5 -5
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/insecure/index.d.ts.map +1 -1
- package/dist/src/insecure/index.js +3 -1
- package/dist/src/insecure/index.js.map +1 -1
- package/dist/src/libp2p.d.ts +10 -2
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +7 -13
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/upgrader.d.ts +1 -1
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +2 -1
- package/dist/src/upgrader.js.map +1 -1
- package/dist/typedoc-urls.json +1 -1
- package/package.json +18 -18
- package/src/autonat/index.ts +6 -9
- package/src/circuit-relay/transport/reservation-store.ts +1 -1
- package/src/circuit-relay/utils.ts +3 -1
- package/src/components.ts +1 -17
- package/src/config.ts +0 -9
- package/src/connection-manager/auto-dial.ts +171 -0
- package/src/connection-manager/connection-pruner.ts +137 -0
- package/src/connection-manager/constants.ts +60 -0
- package/src/connection-manager/dial-queue.ts +504 -0
- package/src/connection-manager/index.ts +190 -323
- package/src/connection-manager/utils.ts +76 -0
- package/src/fetch/index.ts +4 -4
- package/src/identify/index.ts +5 -5
- package/src/insecure/index.ts +5 -1
- package/src/libp2p.ts +17 -15
- package/src/upgrader.ts +3 -2
- package/src/version.ts +1 -1
- package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
- package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
- package/dist/src/connection-manager/auto-dialler.js +0 -105
- package/dist/src/connection-manager/auto-dialler.js.map +0 -1
- package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
- package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
- package/dist/src/connection-manager/dialer/dial-request.js +0 -114
- package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
- package/dist/src/connection-manager/dialer/index.d.ts +0 -121
- package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
- package/dist/src/connection-manager/dialer/index.js +0 -324
- package/dist/src/connection-manager/dialer/index.js.map +0 -1
- package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
- package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
- package/dist/src/connection-manager/latency-monitor.js +0 -220
- package/dist/src/connection-manager/latency-monitor.js.map +0 -1
- package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
- package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
- package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
- package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
- package/dist/src/constants.d.ts +0 -27
- package/dist/src/constants.d.ts.map +0 -1
- package/dist/src/constants.js +0 -31
- package/dist/src/constants.js.map +0 -1
- package/src/connection-manager/auto-dialler.ts +0 -158
- package/src/connection-manager/dialer/dial-request.ts +0 -144
- package/src/connection-manager/dialer/index.ts +0 -461
- package/src/connection-manager/latency-monitor.ts +0 -319
- package/src/connection-manager/visibility-change-emitter.ts +0 -135
- package/src/constants.ts +0 -36
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { logger } from '@libp2p/logger';
|
|
2
|
+
import { PeerMap } from '@libp2p/peer-collections';
|
|
3
|
+
import { MAX_CONNECTIONS } from './constants.js';
|
|
4
|
+
import { CustomEvent } from '@libp2p/interfaces/events';
|
|
5
|
+
const log = logger('libp2p:connection-manager:connection-pruner');
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
maxConnections: MAX_CONNECTIONS,
|
|
8
|
+
allow: []
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* If we go over the max connections limit, choose some connections to close
|
|
12
|
+
*/
|
|
13
|
+
export class ConnectionPruner {
|
|
14
|
+
constructor(components, init = {}) {
|
|
15
|
+
this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections;
|
|
16
|
+
this.allow = init.allow ?? defaultOptions.allow;
|
|
17
|
+
this.connectionManager = components.connectionManager;
|
|
18
|
+
this.peerStore = components.peerStore;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* If we have more connections than our maximum, select some excess connections
|
|
22
|
+
* to prune based on peer value
|
|
23
|
+
*/
|
|
24
|
+
async maybePruneConnections() {
|
|
25
|
+
const connections = this.connectionManager.getConnections();
|
|
26
|
+
const numConnections = connections.length;
|
|
27
|
+
const toPrune = Math.max(numConnections - this.maxConnections, 0);
|
|
28
|
+
log.trace('checking max connections limit %d/%d', numConnections, this.maxConnections);
|
|
29
|
+
if (numConnections <= this.maxConnections) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
log('max connections limit exceeded %d/%d, pruning %d connection(s)', numConnections, this.maxConnections, toPrune);
|
|
33
|
+
const peerValues = new PeerMap();
|
|
34
|
+
// work out peer values
|
|
35
|
+
for (const connection of connections) {
|
|
36
|
+
const remotePeer = connection.remotePeer;
|
|
37
|
+
if (peerValues.has(remotePeer)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const tags = await this.peerStore.getTags(remotePeer);
|
|
41
|
+
// sum all tag values
|
|
42
|
+
peerValues.set(remotePeer, tags.reduce((acc, curr) => {
|
|
43
|
+
return acc + curr.value;
|
|
44
|
+
}, 0));
|
|
45
|
+
}
|
|
46
|
+
// sort by value, lowest to highest
|
|
47
|
+
const sortedConnections = connections.sort((a, b) => {
|
|
48
|
+
const peerAValue = peerValues.get(a.remotePeer) ?? 0;
|
|
49
|
+
const peerBValue = peerValues.get(b.remotePeer) ?? 0;
|
|
50
|
+
if (peerAValue > peerBValue) {
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
if (peerAValue < peerBValue) {
|
|
54
|
+
return -1;
|
|
55
|
+
}
|
|
56
|
+
// if the peers have an equal tag value then we want to close short-lived connections first
|
|
57
|
+
const connectionALifespan = a.stat.timeline.open;
|
|
58
|
+
const connectionBLifespan = b.stat.timeline.open;
|
|
59
|
+
if (connectionALifespan < connectionBLifespan) {
|
|
60
|
+
return 1;
|
|
61
|
+
}
|
|
62
|
+
if (connectionALifespan > connectionBLifespan) {
|
|
63
|
+
return -1;
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
});
|
|
67
|
+
// close some connections
|
|
68
|
+
const toClose = [];
|
|
69
|
+
for (const connection of sortedConnections) {
|
|
70
|
+
log('too many connections open - closing a connection to %p', connection.remotePeer);
|
|
71
|
+
// check allow list
|
|
72
|
+
const connectionInAllowList = this.allow.some((ma) => {
|
|
73
|
+
return connection.remoteAddr.toString().startsWith(ma.toString());
|
|
74
|
+
});
|
|
75
|
+
// Connections in the allow list should be excluded from pruning
|
|
76
|
+
if (!connectionInAllowList) {
|
|
77
|
+
toClose.push(connection);
|
|
78
|
+
}
|
|
79
|
+
if (toClose.length === toPrune) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// close connections
|
|
84
|
+
await Promise.all(toClose.map(async (connection) => {
|
|
85
|
+
try {
|
|
86
|
+
await connection.close();
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
log.error(err);
|
|
90
|
+
}
|
|
91
|
+
}));
|
|
92
|
+
// despatch prune event
|
|
93
|
+
this.connectionManager.dispatchEvent(new CustomEvent('peer:prune', { detail: toClose.map(conn => conn.remotePeer) }));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=connection-pruner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-pruner.js","sourceRoot":"","sources":["../../../src/connection-manager/connection-pruner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#dialTimeout
|
|
3
|
+
*/
|
|
4
|
+
export declare const DIAL_TIMEOUT = 30000;
|
|
5
|
+
/**
|
|
6
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundUpgradeTimeout
|
|
7
|
+
*/
|
|
8
|
+
export declare const INBOUND_UPGRADE_TIMEOUT = 30000;
|
|
9
|
+
/**
|
|
10
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials
|
|
11
|
+
*/
|
|
12
|
+
export declare const MAX_PARALLEL_DIALS = 100;
|
|
13
|
+
/**
|
|
14
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxPeerAddrsToDial
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_PEER_ADDRS_TO_DIAL = 25;
|
|
17
|
+
/**
|
|
18
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDialsPerPeer
|
|
19
|
+
*/
|
|
20
|
+
export declare const MAX_PARALLEL_DIALS_PER_PEER = 10;
|
|
21
|
+
/**
|
|
22
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#minConnections
|
|
23
|
+
*/
|
|
24
|
+
export declare const MIN_CONNECTIONS = 50;
|
|
25
|
+
/**
|
|
26
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections
|
|
27
|
+
*/
|
|
28
|
+
export declare const MAX_CONNECTIONS = 300;
|
|
29
|
+
/**
|
|
30
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialInterval
|
|
31
|
+
*/
|
|
32
|
+
export declare const AUTO_DIAL_INTERVAL = 5000;
|
|
33
|
+
/**
|
|
34
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialConcurrency
|
|
35
|
+
*/
|
|
36
|
+
export declare const AUTO_DIAL_CONCURRENCY = 25;
|
|
37
|
+
/**
|
|
38
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialPriority
|
|
39
|
+
*/
|
|
40
|
+
export declare const AUTO_DIAL_PRIORITY = 0;
|
|
41
|
+
/**
|
|
42
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundConnectionThreshold
|
|
43
|
+
*/
|
|
44
|
+
export declare const INBOUND_CONNECTION_THRESHOLD = 5;
|
|
45
|
+
/**
|
|
46
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxIncomingPendingConnections
|
|
47
|
+
*/
|
|
48
|
+
export declare const MAX_INCOMING_PENDING_CONNECTIONS = 10;
|
|
49
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/connection-manager/constants.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,eAAO,MAAM,YAAY,QAAO,CAAA;AAEhC;;GAEG;AACH,eAAO,MAAM,uBAAuB,QAAO,CAAA;AAE3C;;GAEG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC;;GAEG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC;;GAEG;AACH,eAAO,MAAM,2BAA2B,KAAK,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,eAAe,KAAK,CAAA;AAEjC;;GAEG;AACH,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;GAEG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC;;GAEG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAA;AAEvC;;GAEG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC;;GAEG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,gCAAgC,KAAK,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#dialTimeout
|
|
3
|
+
*/
|
|
4
|
+
export const DIAL_TIMEOUT = 30e3;
|
|
5
|
+
/**
|
|
6
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundUpgradeTimeout
|
|
7
|
+
*/
|
|
8
|
+
export const INBOUND_UPGRADE_TIMEOUT = 30e3;
|
|
9
|
+
/**
|
|
10
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials
|
|
11
|
+
*/
|
|
12
|
+
export const MAX_PARALLEL_DIALS = 100;
|
|
13
|
+
/**
|
|
14
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxPeerAddrsToDial
|
|
15
|
+
*/
|
|
16
|
+
export const MAX_PEER_ADDRS_TO_DIAL = 25;
|
|
17
|
+
/**
|
|
18
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDialsPerPeer
|
|
19
|
+
*/
|
|
20
|
+
export const MAX_PARALLEL_DIALS_PER_PEER = 10;
|
|
21
|
+
/**
|
|
22
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#minConnections
|
|
23
|
+
*/
|
|
24
|
+
export const MIN_CONNECTIONS = 50;
|
|
25
|
+
/**
|
|
26
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections
|
|
27
|
+
*/
|
|
28
|
+
export const MAX_CONNECTIONS = 300;
|
|
29
|
+
/**
|
|
30
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialInterval
|
|
31
|
+
*/
|
|
32
|
+
export const AUTO_DIAL_INTERVAL = 5000;
|
|
33
|
+
/**
|
|
34
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialConcurrency
|
|
35
|
+
*/
|
|
36
|
+
export const AUTO_DIAL_CONCURRENCY = 25;
|
|
37
|
+
/**
|
|
38
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#autoDialPriority
|
|
39
|
+
*/
|
|
40
|
+
export const AUTO_DIAL_PRIORITY = 0;
|
|
41
|
+
/**
|
|
42
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundConnectionThreshold
|
|
43
|
+
*/
|
|
44
|
+
export const INBOUND_CONNECTION_THRESHOLD = 5;
|
|
45
|
+
/**
|
|
46
|
+
* @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxIncomingPendingConnections
|
|
47
|
+
*/
|
|
48
|
+
export const MAX_INCOMING_PENDING_CONNECTIONS = 10;
|
|
49
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/connection-manager/constants.ts"],"names":[],"mappings":"AACA;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAA;AAEhC;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAA;AAE3C;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAA;AAErC;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAExC;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAA;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAA;AAEjC;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAA;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAA;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAA;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAA;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,EAAE,CAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Multiaddr, Resolver } from '@multiformats/multiaddr';
|
|
2
|
+
import type { Connection } from '@libp2p/interface-connection';
|
|
3
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
4
|
+
import type { PeerId } from '@libp2p/interface-peer-id';
|
|
5
|
+
import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store';
|
|
6
|
+
import type { Metrics } from '@libp2p/interface-metrics';
|
|
7
|
+
import type { TransportManager } from '@libp2p/interface-transport';
|
|
8
|
+
import type { ConnectionGater } from '@libp2p/interface-connection-gater';
|
|
9
|
+
import PQueue from 'p-queue';
|
|
10
|
+
export type PendingDialStatus = 'queued' | 'active' | 'error' | 'success';
|
|
11
|
+
export interface PendingDial {
|
|
12
|
+
id: string;
|
|
13
|
+
status: PendingDialStatus;
|
|
14
|
+
peerId?: PeerId;
|
|
15
|
+
multiaddrs: Multiaddr[];
|
|
16
|
+
promise: Promise<Connection>;
|
|
17
|
+
}
|
|
18
|
+
export interface PendingDialTarget {
|
|
19
|
+
resolve: (value: any) => void;
|
|
20
|
+
reject: (err: Error) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface DialOptions extends AbortOptions {
|
|
23
|
+
priority?: number;
|
|
24
|
+
}
|
|
25
|
+
interface DialerInit {
|
|
26
|
+
addressSorter?: AddressSorter;
|
|
27
|
+
maxParallelDials?: number;
|
|
28
|
+
maxPeerAddrsToDial?: number;
|
|
29
|
+
maxParallelDialsPerPeer?: number;
|
|
30
|
+
dialTimeout?: number;
|
|
31
|
+
resolvers?: Record<string, Resolver>;
|
|
32
|
+
}
|
|
33
|
+
interface DialQueueComponents {
|
|
34
|
+
peerId: PeerId;
|
|
35
|
+
metrics?: Metrics;
|
|
36
|
+
peerStore: PeerStore;
|
|
37
|
+
transportManager: TransportManager;
|
|
38
|
+
connectionGater: ConnectionGater;
|
|
39
|
+
}
|
|
40
|
+
export declare class DialQueue {
|
|
41
|
+
pendingDials: PendingDial[];
|
|
42
|
+
queue: PQueue;
|
|
43
|
+
private readonly peerId;
|
|
44
|
+
private readonly peerStore;
|
|
45
|
+
private readonly connectionGater;
|
|
46
|
+
private readonly transportManager;
|
|
47
|
+
private readonly addressSorter;
|
|
48
|
+
private readonly maxPeerAddrsToDial;
|
|
49
|
+
private readonly maxParallelDialsPerPeer;
|
|
50
|
+
private readonly dialTimeout;
|
|
51
|
+
private readonly inProgressDialCount?;
|
|
52
|
+
private readonly pendingDialCount?;
|
|
53
|
+
private readonly shutDownController;
|
|
54
|
+
constructor(components: DialQueueComponents, init?: DialerInit);
|
|
55
|
+
/**
|
|
56
|
+
* Clears any pending dials
|
|
57
|
+
*/
|
|
58
|
+
stop(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Connects to a given peer, multiaddr or list of multiaddrs.
|
|
61
|
+
*
|
|
62
|
+
* If a peer is passed, all known multiaddrs will be tried. If a multiaddr or
|
|
63
|
+
* multiaddrs are passed only those will be dialled.
|
|
64
|
+
*
|
|
65
|
+
* Where a list of multiaddrs is passed, if any contain a peer id then all
|
|
66
|
+
* multiaddrs in the list must contain the same peer id.
|
|
67
|
+
*
|
|
68
|
+
* The dial to the first address that is successfully able to upgrade a connection
|
|
69
|
+
* will be used, all other dials will be aborted when that happens.
|
|
70
|
+
*/
|
|
71
|
+
dial(peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options?: DialOptions): Promise<Connection>;
|
|
72
|
+
private createDialAbortControllers;
|
|
73
|
+
private calculateMultiaddrs;
|
|
74
|
+
private performDial;
|
|
75
|
+
}
|
|
76
|
+
export {};
|
|
77
|
+
//# sourceMappingURL=dial-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dial-queue.d.ts","sourceRoot":"","sources":["../../../src/connection-manager/dial-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { logger } from '@libp2p/logger';
|
|
2
|
+
import { AbortError, CodeError } from '@libp2p/interfaces/errors';
|
|
3
|
+
import { resolvers } from '@multiformats/multiaddr';
|
|
4
|
+
import { TimeoutController } from 'timeout-abort-controller';
|
|
5
|
+
import { publicAddressesFirst } from '@libp2p/utils/address-sort';
|
|
6
|
+
import { codes } from '../errors.js';
|
|
7
|
+
import { DIAL_TIMEOUT, MAX_PARALLEL_DIALS_PER_PEER, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL } from './constants.js';
|
|
8
|
+
import { getPeerAddress } from '../get-peer.js';
|
|
9
|
+
import PQueue from 'p-queue';
|
|
10
|
+
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers';
|
|
11
|
+
import { combineSignals, resolveMultiaddrs } from './utils.js';
|
|
12
|
+
import pDefer from 'p-defer';
|
|
13
|
+
const log = logger('libp2p:connection-manager:dial-queue');
|
|
14
|
+
const defaultOptions = {
|
|
15
|
+
addressSorter: publicAddressesFirst,
|
|
16
|
+
maxParallelDials: MAX_PARALLEL_DIALS,
|
|
17
|
+
maxPeerAddrsToDial: MAX_PEER_ADDRS_TO_DIAL,
|
|
18
|
+
maxParallelDialsPerPeer: MAX_PARALLEL_DIALS_PER_PEER,
|
|
19
|
+
dialTimeout: DIAL_TIMEOUT,
|
|
20
|
+
resolvers: {
|
|
21
|
+
dnsaddr: dnsaddrResolver
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export class DialQueue {
|
|
25
|
+
constructor(components, init = {}) {
|
|
26
|
+
this.addressSorter = init.addressSorter ?? defaultOptions.addressSorter;
|
|
27
|
+
this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial;
|
|
28
|
+
this.maxParallelDialsPerPeer = init.maxParallelDialsPerPeer ?? defaultOptions.maxParallelDialsPerPeer;
|
|
29
|
+
this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout;
|
|
30
|
+
this.peerId = components.peerId;
|
|
31
|
+
this.peerStore = components.peerStore;
|
|
32
|
+
this.connectionGater = components.connectionGater;
|
|
33
|
+
this.transportManager = components.transportManager;
|
|
34
|
+
this.shutDownController = new AbortController();
|
|
35
|
+
this.pendingDialCount = components.metrics?.registerMetric('libp2p_dialler_pending_dials');
|
|
36
|
+
this.inProgressDialCount = components.metrics?.registerMetric('libp2p_dialler_in_progress_dials');
|
|
37
|
+
this.pendingDials = [];
|
|
38
|
+
for (const [key, value] of Object.entries(init.resolvers ?? {})) {
|
|
39
|
+
resolvers.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
// controls dial concurrency
|
|
42
|
+
this.queue = new PQueue({
|
|
43
|
+
concurrency: init.maxParallelDials ?? defaultOptions.maxParallelDials
|
|
44
|
+
});
|
|
45
|
+
// a job was added to the queue
|
|
46
|
+
this.queue.on('add', () => {
|
|
47
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
48
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
49
|
+
});
|
|
50
|
+
// a queued job started
|
|
51
|
+
this.queue.on('active', () => {
|
|
52
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
53
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
54
|
+
});
|
|
55
|
+
// a started job completed without error
|
|
56
|
+
this.queue.on('completed', () => {
|
|
57
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
58
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
59
|
+
});
|
|
60
|
+
// a started job errored
|
|
61
|
+
this.queue.on('error', (err) => {
|
|
62
|
+
log.error('error in dial queue', err);
|
|
63
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
64
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
65
|
+
});
|
|
66
|
+
// all queued jobs have been started
|
|
67
|
+
this.queue.on('empty', () => {
|
|
68
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
69
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
70
|
+
});
|
|
71
|
+
// add started jobs have run and the queue is empty
|
|
72
|
+
this.queue.on('idle', () => {
|
|
73
|
+
this.pendingDialCount?.update(this.queue.size);
|
|
74
|
+
this.inProgressDialCount?.update(this.queue.pending);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Clears any pending dials
|
|
79
|
+
*/
|
|
80
|
+
stop() {
|
|
81
|
+
this.shutDownController.abort();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Connects to a given peer, multiaddr or list of multiaddrs.
|
|
85
|
+
*
|
|
86
|
+
* If a peer is passed, all known multiaddrs will be tried. If a multiaddr or
|
|
87
|
+
* multiaddrs are passed only those will be dialled.
|
|
88
|
+
*
|
|
89
|
+
* Where a list of multiaddrs is passed, if any contain a peer id then all
|
|
90
|
+
* multiaddrs in the list must contain the same peer id.
|
|
91
|
+
*
|
|
92
|
+
* The dial to the first address that is successfully able to upgrade a connection
|
|
93
|
+
* will be used, all other dials will be aborted when that happens.
|
|
94
|
+
*/
|
|
95
|
+
async dial(peerIdOrMultiaddr, options = {}) {
|
|
96
|
+
const { peerId, multiaddrs } = getPeerAddress(peerIdOrMultiaddr);
|
|
97
|
+
const addrs = multiaddrs.map(multiaddr => ({
|
|
98
|
+
multiaddr,
|
|
99
|
+
isCertified: false
|
|
100
|
+
}));
|
|
101
|
+
// create abort conditions - need to do this before `calculateMultiaddrs` as we may be about to
|
|
102
|
+
// resolve a dns addr which can time out
|
|
103
|
+
const { timeoutController, signal } = this.createDialAbortControllers(options.signal);
|
|
104
|
+
let addrsToDial;
|
|
105
|
+
try {
|
|
106
|
+
// load addresses from address book, resolve and dnsaddrs, filter undiallables, add peer IDs, etc
|
|
107
|
+
addrsToDial = await this.calculateMultiaddrs(peerId, addrs, {
|
|
108
|
+
...options,
|
|
109
|
+
signal
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
signal.clear();
|
|
114
|
+
timeoutController.clear();
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
// ready to dial, all async work finished - make sure we don't have any
|
|
118
|
+
// pending dials in progress for this peer or set of multiaddrs
|
|
119
|
+
const existingDial = this.pendingDials.find(dial => {
|
|
120
|
+
// is the dial for the same peer id?
|
|
121
|
+
if (dial.peerId != null && peerId != null && dial.peerId.equals(peerId)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
// is the dial for the same set of multiaddrs?
|
|
125
|
+
if (addrsToDial.map(({ multiaddr }) => multiaddr.toString()).join() === dial.multiaddrs.map(multiaddr => multiaddr.toString()).join()) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
});
|
|
130
|
+
if (existingDial != null) {
|
|
131
|
+
log('joining existing dial target for %p', peerId);
|
|
132
|
+
signal.clear();
|
|
133
|
+
timeoutController.clear();
|
|
134
|
+
return await existingDial.promise;
|
|
135
|
+
}
|
|
136
|
+
log('creating dial target for', addrsToDial.map(({ multiaddr }) => multiaddr.toString()));
|
|
137
|
+
// @ts-expect-error .promise property is set below
|
|
138
|
+
const pendingDial = {
|
|
139
|
+
id: randomId(),
|
|
140
|
+
status: 'queued',
|
|
141
|
+
peerId,
|
|
142
|
+
multiaddrs: addrsToDial.map(({ multiaddr }) => multiaddr)
|
|
143
|
+
};
|
|
144
|
+
pendingDial.promise = this.performDial(pendingDial, {
|
|
145
|
+
...options,
|
|
146
|
+
signal
|
|
147
|
+
})
|
|
148
|
+
.finally(() => {
|
|
149
|
+
// remove our pending dial entry
|
|
150
|
+
this.pendingDials = this.pendingDials.filter(p => p.id !== pendingDial.id);
|
|
151
|
+
// clean up abort signals/controllers
|
|
152
|
+
signal.clear();
|
|
153
|
+
timeoutController.clear();
|
|
154
|
+
})
|
|
155
|
+
.catch(err => {
|
|
156
|
+
log.error('dial failed to %s', addrsToDial.map(({ multiaddr }) => multiaddr.toString()).join(', '), err);
|
|
157
|
+
// Error is a timeout
|
|
158
|
+
if (timeoutController.signal.aborted) {
|
|
159
|
+
const error = new CodeError(err.message, codes.ERR_TIMEOUT);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
throw err;
|
|
163
|
+
});
|
|
164
|
+
// let other dials join this one
|
|
165
|
+
this.pendingDials.push(pendingDial);
|
|
166
|
+
return await pendingDial.promise;
|
|
167
|
+
}
|
|
168
|
+
createDialAbortControllers(userSignal) {
|
|
169
|
+
// ensure we throw if the dial takes longer than the dial timeout
|
|
170
|
+
const timeoutController = new TimeoutController(this.dialTimeout);
|
|
171
|
+
// let any signal abort the dial
|
|
172
|
+
const signal = combineSignals(timeoutController.signal, this.shutDownController.signal, userSignal);
|
|
173
|
+
return { timeoutController, signal };
|
|
174
|
+
}
|
|
175
|
+
async calculateMultiaddrs(peerId, addrs = [], options = {}) {
|
|
176
|
+
// if a peer id or multiaddr(s) with a peer id, make sure it isn't our peer id and that we are allowed to dial it
|
|
177
|
+
if (peerId != null) {
|
|
178
|
+
if (this.peerId.equals(peerId)) {
|
|
179
|
+
throw new CodeError('Tried to dial self', codes.ERR_DIALED_SELF);
|
|
180
|
+
}
|
|
181
|
+
if ((await this.connectionGater.denyDialPeer?.(peerId)) === true) {
|
|
182
|
+
throw new CodeError('The dial request is blocked by gater.allowDialPeer', codes.ERR_PEER_DIAL_INTERCEPTED);
|
|
183
|
+
}
|
|
184
|
+
// if just a peer id was passed, load available multiaddrs for this peer from the address book
|
|
185
|
+
if (addrs.length === 0) {
|
|
186
|
+
log('loading multiaddrs for %p', peerId);
|
|
187
|
+
addrs.push(...(await this.peerStore.addressBook.get(peerId)));
|
|
188
|
+
log('loaded multiaddrs for %p', peerId, addrs.map(({ multiaddr }) => multiaddr.toString()));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// resolve addresses - this can result in a one-to-many translation when dnsaddrs are resolved
|
|
192
|
+
const resolvedAddresses = (await Promise.all(addrs.map(async (addr) => {
|
|
193
|
+
const result = await resolveMultiaddrs(addr.multiaddr, options);
|
|
194
|
+
if (result.length === 1 && result[0].equals(addr.multiaddr)) {
|
|
195
|
+
return addr;
|
|
196
|
+
}
|
|
197
|
+
return result.map(multiaddr => ({
|
|
198
|
+
multiaddr,
|
|
199
|
+
isCertified: false
|
|
200
|
+
}));
|
|
201
|
+
})))
|
|
202
|
+
.flat();
|
|
203
|
+
// filter out any multiaddrs that we do not have transports for
|
|
204
|
+
const filteredAddrs = resolvedAddresses.filter(addr => Boolean(this.transportManager.transportForMultiaddr(addr.multiaddr)));
|
|
205
|
+
// deduplicate addresses
|
|
206
|
+
const dedupedAddrs = new Map();
|
|
207
|
+
for (const addr of filteredAddrs) {
|
|
208
|
+
const maStr = addr.multiaddr.toString();
|
|
209
|
+
const existing = dedupedAddrs.get(maStr);
|
|
210
|
+
if (existing != null) {
|
|
211
|
+
existing.isCertified = existing.isCertified || addr.isCertified || false;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
dedupedAddrs.set(maStr, addr);
|
|
215
|
+
}
|
|
216
|
+
let dedupedMultiaddrs = [...dedupedAddrs.values()];
|
|
217
|
+
if (dedupedMultiaddrs.length === 0 || dedupedMultiaddrs.length > this.maxPeerAddrsToDial) {
|
|
218
|
+
log('addresses for %p before filtering', peerId ?? 'unknown peer', resolvedAddresses.map(({ multiaddr }) => multiaddr.toString()));
|
|
219
|
+
log('addresses for %p after filtering', peerId ?? 'unknown peer', dedupedMultiaddrs.map(({ multiaddr }) => multiaddr.toString()));
|
|
220
|
+
}
|
|
221
|
+
// make sure we actually have some addresses to dial
|
|
222
|
+
if (dedupedMultiaddrs.length === 0) {
|
|
223
|
+
throw new CodeError('The dial request has no valid addresses', codes.ERR_NO_VALID_ADDRESSES);
|
|
224
|
+
}
|
|
225
|
+
// make sure we don't have too many addresses to dial
|
|
226
|
+
if (dedupedMultiaddrs.length > this.maxPeerAddrsToDial) {
|
|
227
|
+
throw new CodeError('dial with more addresses than allowed', codes.ERR_TOO_MANY_ADDRESSES);
|
|
228
|
+
}
|
|
229
|
+
// ensure the peer id is appended to the multiaddr
|
|
230
|
+
if (peerId != null) {
|
|
231
|
+
const peerIdMultiaddr = `/p2p/${peerId.toString()}`;
|
|
232
|
+
dedupedMultiaddrs = dedupedMultiaddrs.map(addr => {
|
|
233
|
+
const addressPeerId = addr.multiaddr.getPeerId();
|
|
234
|
+
const lastProto = addr.multiaddr.protos().pop();
|
|
235
|
+
// do not append peer id to path multiaddrs
|
|
236
|
+
if (lastProto?.path === true) {
|
|
237
|
+
return addr;
|
|
238
|
+
}
|
|
239
|
+
// append peer id to multiaddr if it is not already present
|
|
240
|
+
if (addressPeerId !== peerId.toString()) {
|
|
241
|
+
return {
|
|
242
|
+
multiaddr: addr.multiaddr.encapsulate(peerIdMultiaddr),
|
|
243
|
+
isCertified: addr.isCertified
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return addr;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
const gatedAdrs = [];
|
|
250
|
+
for (const addr of dedupedMultiaddrs) {
|
|
251
|
+
if (this.connectionGater.denyDialMultiaddr != null && await this.connectionGater.denyDialMultiaddr(addr.multiaddr)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
gatedAdrs.push(addr);
|
|
255
|
+
}
|
|
256
|
+
return gatedAdrs.sort(this.addressSorter);
|
|
257
|
+
}
|
|
258
|
+
async performDial(pendingDial, options = {}) {
|
|
259
|
+
const dialAbortControllers = pendingDial.multiaddrs.map(() => new AbortController());
|
|
260
|
+
try {
|
|
261
|
+
// internal peer dial queue to ensure we only dial the configured number of addresses
|
|
262
|
+
// per peer at the same time to prevent one peer with a lot of addresses swamping
|
|
263
|
+
// the dial queue
|
|
264
|
+
const peerDialQueue = new PQueue({
|
|
265
|
+
concurrency: this.maxParallelDialsPerPeer
|
|
266
|
+
});
|
|
267
|
+
peerDialQueue.on('error', (err) => {
|
|
268
|
+
log.error('error dialling', err);
|
|
269
|
+
});
|
|
270
|
+
const conn = await Promise.any(pendingDial.multiaddrs.map(async (addr, i) => {
|
|
271
|
+
const controller = dialAbortControllers[i];
|
|
272
|
+
if (controller == null) {
|
|
273
|
+
throw new CodeError('dialAction did not come with an AbortController', codes.ERR_INVALID_PARAMETERS);
|
|
274
|
+
}
|
|
275
|
+
// let any signal abort the dial
|
|
276
|
+
const signal = combineSignals(controller.signal, options.signal);
|
|
277
|
+
signal.addEventListener('abort', () => {
|
|
278
|
+
log('dial to %s aborted', addr);
|
|
279
|
+
});
|
|
280
|
+
const deferred = pDefer();
|
|
281
|
+
await peerDialQueue.add(async () => {
|
|
282
|
+
if (signal.aborted) {
|
|
283
|
+
log('dial to %s was aborted before reaching the head of the peer dial queue', addr);
|
|
284
|
+
deferred.reject(new AbortError());
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
// add the individual dial to the dial queue so we don't breach maxConcurrentDials
|
|
288
|
+
await this.queue.add(async () => {
|
|
289
|
+
try {
|
|
290
|
+
if (signal.aborted) {
|
|
291
|
+
log('dial to %s was aborted before reaching the head of the dial queue', addr);
|
|
292
|
+
deferred.reject(new AbortError());
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// update dial status
|
|
296
|
+
pendingDial.status = 'active';
|
|
297
|
+
const conn = await this.transportManager.dial(addr, {
|
|
298
|
+
...options,
|
|
299
|
+
signal
|
|
300
|
+
});
|
|
301
|
+
if (controller.signal.aborted) {
|
|
302
|
+
// another dial succeeded faster than this one
|
|
303
|
+
log('multiple dials succeeded, closing superfluous connection');
|
|
304
|
+
conn.close().catch(err => {
|
|
305
|
+
log.error('error closing superfluous connection', err);
|
|
306
|
+
});
|
|
307
|
+
deferred.reject(new AbortError());
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// remove the successful AbortController so it is not aborted
|
|
311
|
+
dialAbortControllers[i] = undefined;
|
|
312
|
+
// immediately abort any other dials
|
|
313
|
+
dialAbortControllers.forEach(c => {
|
|
314
|
+
if (c !== undefined) {
|
|
315
|
+
c.abort();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
log('dial to %s succeeded', addr);
|
|
319
|
+
// resolve the connection promise
|
|
320
|
+
deferred.resolve(conn);
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
// something only went wrong if our signal was not aborted
|
|
324
|
+
log.error('error during dial of %s', addr, err);
|
|
325
|
+
deferred.reject(err);
|
|
326
|
+
}
|
|
327
|
+
}, {
|
|
328
|
+
...options,
|
|
329
|
+
signal
|
|
330
|
+
}).catch(err => {
|
|
331
|
+
deferred.reject(err);
|
|
332
|
+
});
|
|
333
|
+
}, {
|
|
334
|
+
signal
|
|
335
|
+
}).catch(err => {
|
|
336
|
+
deferred.reject(err);
|
|
337
|
+
}).finally(() => {
|
|
338
|
+
signal.clear();
|
|
339
|
+
});
|
|
340
|
+
return await deferred.promise;
|
|
341
|
+
}));
|
|
342
|
+
// dial succeeded or failed
|
|
343
|
+
if (conn == null) {
|
|
344
|
+
throw new CodeError('successful dial led to empty object returned from peer dial queue', codes.ERR_TRANSPORT_DIAL_FAILED);
|
|
345
|
+
}
|
|
346
|
+
pendingDial.status = 'success';
|
|
347
|
+
return conn;
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
pendingDial.status = 'error';
|
|
351
|
+
// if we only dialled one address, unwrap the AggregateError to provide more
|
|
352
|
+
// useful feedback to the user
|
|
353
|
+
if (pendingDial.multiaddrs.length === 1 && err.name === 'AggregateError') {
|
|
354
|
+
throw err.errors[0];
|
|
355
|
+
}
|
|
356
|
+
throw err;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Returns a random string
|
|
362
|
+
*/
|
|
363
|
+
function randomId() {
|
|
364
|
+
return `${(parseInt(String(Math.random() * 1e9), 10)).toString()}${Date.now()}`;
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=dial-queue.js.map
|