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.
Files changed (105) hide show
  1. package/dist/index.min.js +30 -30
  2. package/dist/src/autonat/index.d.ts +1 -2
  3. package/dist/src/autonat/index.d.ts.map +1 -1
  4. package/dist/src/autonat/index.js +4 -6
  5. package/dist/src/autonat/index.js.map +1 -1
  6. package/dist/src/circuit-relay/transport/reservation-store.d.ts +1 -1
  7. package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
  8. package/dist/src/circuit-relay/utils.d.ts.map +1 -1
  9. package/dist/src/circuit-relay/utils.js +3 -1
  10. package/dist/src/circuit-relay/utils.js.map +1 -1
  11. package/dist/src/components.d.ts +1 -6
  12. package/dist/src/components.d.ts.map +1 -1
  13. package/dist/src/components.js +0 -10
  14. package/dist/src/components.js.map +1 -1
  15. package/dist/src/config.d.ts.map +1 -1
  16. package/dist/src/config.js +0 -9
  17. package/dist/src/config.js.map +1 -1
  18. package/dist/src/connection-manager/auto-dial.d.ts +36 -0
  19. package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
  20. package/dist/src/connection-manager/auto-dial.js +122 -0
  21. package/dist/src/connection-manager/auto-dial.js.map +1 -0
  22. package/dist/src/connection-manager/connection-pruner.d.ts +28 -0
  23. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
  24. package/dist/src/connection-manager/connection-pruner.js +96 -0
  25. package/dist/src/connection-manager/connection-pruner.js.map +1 -0
  26. package/dist/src/connection-manager/constants.d.ts +49 -0
  27. package/dist/src/connection-manager/constants.d.ts.map +1 -0
  28. package/dist/src/connection-manager/constants.js +49 -0
  29. package/dist/src/connection-manager/constants.js.map +1 -0
  30. package/dist/src/connection-manager/dial-queue.d.ts +77 -0
  31. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
  32. package/dist/src/connection-manager/dial-queue.js +366 -0
  33. package/dist/src/connection-manager/dial-queue.js.map +1 -0
  34. package/dist/src/connection-manager/index.d.ts +65 -69
  35. package/dist/src/connection-manager/index.d.ts.map +1 -1
  36. package/dist/src/connection-manager/index.js +116 -234
  37. package/dist/src/connection-manager/index.js.map +1 -1
  38. package/dist/src/connection-manager/utils.d.ts +9 -0
  39. package/dist/src/connection-manager/utils.d.ts.map +1 -0
  40. package/dist/src/connection-manager/utils.js +66 -0
  41. package/dist/src/connection-manager/utils.js.map +1 -0
  42. package/dist/src/fetch/index.js +3 -3
  43. package/dist/src/fetch/index.js.map +1 -1
  44. package/dist/src/identify/index.js +5 -5
  45. package/dist/src/identify/index.js.map +1 -1
  46. package/dist/src/insecure/index.d.ts.map +1 -1
  47. package/dist/src/insecure/index.js +3 -1
  48. package/dist/src/insecure/index.js.map +1 -1
  49. package/dist/src/libp2p.d.ts +10 -2
  50. package/dist/src/libp2p.d.ts.map +1 -1
  51. package/dist/src/libp2p.js +7 -13
  52. package/dist/src/libp2p.js.map +1 -1
  53. package/dist/src/upgrader.d.ts +1 -1
  54. package/dist/src/upgrader.d.ts.map +1 -1
  55. package/dist/src/upgrader.js +2 -1
  56. package/dist/src/upgrader.js.map +1 -1
  57. package/dist/typedoc-urls.json +1 -1
  58. package/package.json +18 -18
  59. package/src/autonat/index.ts +6 -9
  60. package/src/circuit-relay/transport/reservation-store.ts +1 -1
  61. package/src/circuit-relay/utils.ts +3 -1
  62. package/src/components.ts +1 -17
  63. package/src/config.ts +0 -9
  64. package/src/connection-manager/auto-dial.ts +171 -0
  65. package/src/connection-manager/connection-pruner.ts +137 -0
  66. package/src/connection-manager/constants.ts +60 -0
  67. package/src/connection-manager/dial-queue.ts +504 -0
  68. package/src/connection-manager/index.ts +190 -323
  69. package/src/connection-manager/utils.ts +76 -0
  70. package/src/fetch/index.ts +4 -4
  71. package/src/identify/index.ts +5 -5
  72. package/src/insecure/index.ts +5 -1
  73. package/src/libp2p.ts +17 -15
  74. package/src/upgrader.ts +3 -2
  75. package/src/version.ts +1 -1
  76. package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
  77. package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
  78. package/dist/src/connection-manager/auto-dialler.js +0 -105
  79. package/dist/src/connection-manager/auto-dialler.js.map +0 -1
  80. package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
  81. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
  82. package/dist/src/connection-manager/dialer/dial-request.js +0 -114
  83. package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
  84. package/dist/src/connection-manager/dialer/index.d.ts +0 -121
  85. package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
  86. package/dist/src/connection-manager/dialer/index.js +0 -324
  87. package/dist/src/connection-manager/dialer/index.js.map +0 -1
  88. package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
  89. package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
  90. package/dist/src/connection-manager/latency-monitor.js +0 -220
  91. package/dist/src/connection-manager/latency-monitor.js.map +0 -1
  92. package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
  93. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
  94. package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
  95. package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
  96. package/dist/src/constants.d.ts +0 -27
  97. package/dist/src/constants.d.ts.map +0 -1
  98. package/dist/src/constants.js +0 -31
  99. package/dist/src/constants.js.map +0 -1
  100. package/src/connection-manager/auto-dialler.ts +0 -158
  101. package/src/connection-manager/dialer/dial-request.ts +0 -144
  102. package/src/connection-manager/dialer/index.ts +0 -461
  103. package/src/connection-manager/latency-monitor.ts +0 -319
  104. package/src/connection-manager/visibility-change-emitter.ts +0 -135
  105. package/src/constants.ts +0 -36
@@ -1,144 +0,0 @@
1
- import { CodeError } from '@libp2p/interfaces/errors'
2
- import { anySignal } from 'any-signal'
3
- import FIFO from 'p-fifo'
4
- import { setMaxListeners } from 'events'
5
- import { codes } from '../../errors.js'
6
- import { logger } from '@libp2p/logger'
7
- import type { Multiaddr } from '@multiformats/multiaddr'
8
- import type { Connection } from '@libp2p/interface-connection'
9
- import type { AbortOptions } from '@libp2p/interfaces'
10
- import type { Dialer } from '@libp2p/interface-connection-manager'
11
-
12
- const log = logger('libp2p:dialer:dial-request')
13
-
14
- export interface DialAction {
15
- (m: Multiaddr, options: AbortOptions): Promise<Connection>
16
- }
17
-
18
- export interface DialRequestOptions {
19
- addrs: Multiaddr[]
20
- dialAction: DialAction
21
- dialer: Dialer
22
- }
23
-
24
- export class DialRequest {
25
- private readonly addrs: Multiaddr[]
26
- private readonly dialer: Dialer
27
- private readonly dialAction: DialAction
28
-
29
- /**
30
- * Manages running the `dialAction` on multiple provided `addrs` in parallel
31
- * up to a maximum determined by the number of tokens returned
32
- * from `dialer.getTokens`. Once a DialRequest is created, it can be
33
- * started using `DialRequest.run(options)`. Once a single dial has succeeded,
34
- * all other dials in the request will be cancelled.
35
- */
36
- constructor (options: DialRequestOptions) {
37
- const {
38
- addrs,
39
- dialAction,
40
- dialer
41
- } = options
42
-
43
- this.addrs = addrs
44
- this.dialer = dialer
45
- this.dialAction = dialAction
46
- }
47
-
48
- async run (options: AbortOptions = {}): Promise<Connection> {
49
- const tokens = this.dialer.getTokens(this.addrs.length)
50
-
51
- // If no tokens are available, throw
52
- if (tokens.length < 1) {
53
- throw new CodeError('No dial tokens available', codes.ERR_NO_DIAL_TOKENS)
54
- }
55
-
56
- const tokenHolder = new FIFO<number>()
57
-
58
- for (const token of tokens) {
59
- void tokenHolder.push(token).catch(err => {
60
- log.error(err)
61
- })
62
- }
63
-
64
- const dialAbortControllers: Array<(AbortController | undefined)> = this.addrs.map(() => {
65
- const controller = new AbortController()
66
- try {
67
- // fails on node < 15.4
68
- setMaxListeners?.(Infinity, controller.signal)
69
- } catch {}
70
-
71
- return controller
72
- })
73
-
74
- if (options.signal != null) {
75
- try {
76
- // fails on node < 15.4
77
- setMaxListeners?.(Infinity, options.signal)
78
- } catch {}
79
- }
80
-
81
- let completedDials = 0
82
- let done = false
83
-
84
- try {
85
- return await Promise.any(this.addrs.map(async (addr, i) => {
86
- const token = await tokenHolder.shift() // get token
87
- // End attempt once another attempt succeeded
88
- if (done) {
89
- this.dialer.releaseToken(tokens.splice(tokens.indexOf(token), 1)[0])
90
- throw new CodeError('dialAction already succeeded', codes.ERR_ALREADY_SUCCEEDED)
91
- }
92
-
93
- const controller = dialAbortControllers[i]
94
- if (controller == null) {
95
- throw new CodeError('dialAction did not come with an AbortController', codes.ERR_INVALID_PARAMETERS)
96
- }
97
- let conn
98
- try {
99
- const signal = controller.signal
100
- conn = await this.dialAction(addr, { ...options, signal: (options.signal != null) ? anySignal([signal, options.signal]) : signal })
101
- // Remove the successful AbortController so it is not aborted
102
- dialAbortControllers[i] = undefined
103
- } finally {
104
- completedDials++
105
- // If we have more or equal dials remaining than tokens, recycle the token, otherwise release it
106
- if (this.addrs.length - completedDials >= tokens.length) {
107
- void tokenHolder.push(token).catch(err => {
108
- log.error(err)
109
- })
110
- } else {
111
- this.dialer.releaseToken(tokens.splice(tokens.indexOf(token), 1)[0])
112
- }
113
- }
114
-
115
- if (conn == null) {
116
- // Notify Promise.any that attempt was not successful
117
- // to prevent from returning undefined despite there
118
- // were successful dial attempts
119
- throw new CodeError('dialAction led to empty object', codes.ERR_TRANSPORT_DIAL_FAILED)
120
- } else {
121
- // This dial succeeded, don't attempt anything else
122
- done = true
123
- }
124
-
125
- return conn
126
- }))
127
- } catch (err: any) {
128
- // if we only dialed one address, unwrap the AggregateError
129
- if (this.addrs.length === 1 && err.name === 'AggregateError') {
130
- throw err.errors[0]
131
- }
132
-
133
- throw err
134
- } finally {
135
- // success/failure happened, abort everything else
136
- dialAbortControllers.forEach(c => {
137
- if (c !== undefined) {
138
- c.abort()
139
- }
140
- })
141
- tokens.forEach(token => { this.dialer.releaseToken(token) }) // release tokens back to the dialer
142
- }
143
- }
144
- }
@@ -1,461 +0,0 @@
1
- import { logger } from '@libp2p/logger'
2
- import { CodeError } from '@libp2p/interfaces/errors'
3
- import { isMultiaddr, Multiaddr, Resolver, multiaddr, resolvers } from '@multiformats/multiaddr'
4
- import { TimeoutController } from 'timeout-abort-controller'
5
- import { anySignal } from 'any-signal'
6
- import { setMaxListeners } from 'events'
7
- import { DialAction, DialRequest } from './dial-request.js'
8
- import { publicAddressesFirst } from '@libp2p/utils/address-sort'
9
- import { trackedMap } from '@libp2p/tracked-map'
10
- import { codes } from '../../errors.js'
11
- import {
12
- DIAL_TIMEOUT,
13
- MAX_PARALLEL_DIALS,
14
- MAX_PER_PEER_DIALS,
15
- MAX_ADDRS_TO_DIAL
16
- } from '../../constants.js'
17
- import type { Connection } from '@libp2p/interface-connection'
18
- import type { AbortOptions } from '@libp2p/interfaces'
19
- import type { Startable } from '@libp2p/interfaces/startable'
20
- import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
21
- import { getPeerAddress, PeerAddress } from '../../get-peer.js'
22
- import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
23
- import type { Metrics } from '@libp2p/interface-metrics'
24
- import type { Dialer } from '@libp2p/interface-connection-manager'
25
- import type { TransportManager } from '@libp2p/interface-transport'
26
- import type { ConnectionGater } from '@libp2p/interface-connection-gater'
27
-
28
- const log = logger('libp2p:dialer')
29
-
30
- export interface DialTarget {
31
- id: string
32
- addrs: Multiaddr[]
33
- }
34
-
35
- export interface PendingDial {
36
- dialRequest: DialRequest
37
- controller: TimeoutController
38
- promise: Promise<Connection>
39
- destroy: () => void
40
- }
41
-
42
- export interface PendingDialTarget {
43
- resolve: (value: any) => void
44
- reject: (err: Error) => void
45
- }
46
-
47
- export interface DialerInit {
48
- /**
49
- * Sort the known addresses of a peer before trying to dial
50
- */
51
- addressSorter?: AddressSorter
52
-
53
- /**
54
- * Number of max concurrent dials
55
- */
56
- maxParallelDials?: number
57
-
58
- /**
59
- * Number of max addresses to dial for a given peer
60
- */
61
- maxAddrsToDial?: number
62
-
63
- /**
64
- * How long a dial attempt is allowed to take
65
- */
66
- dialTimeout?: number
67
-
68
- /**
69
- * Number of max concurrent dials per peer
70
- */
71
- maxDialsPerPeer?: number
72
-
73
- /**
74
- * Multiaddr resolvers to use when dialing
75
- */
76
- resolvers?: Record<string, Resolver>
77
- }
78
-
79
- export interface DefaultDialerComponents {
80
- peerId: PeerId
81
- metrics?: Metrics
82
- peerStore: PeerStore
83
- transportManager: TransportManager
84
- connectionGater: ConnectionGater
85
- }
86
-
87
- export class DefaultDialer implements Startable, Dialer {
88
- private readonly components: DefaultDialerComponents
89
- private readonly addressSorter: AddressSorter
90
- private readonly maxAddrsToDial: number
91
- private readonly timeout: number
92
- private readonly maxDialsPerPeer: number
93
- public tokens: number[]
94
- public pendingDials: Map<string, PendingDial>
95
- public pendingDialTargets: Map<string, AbortController>
96
- private started: boolean
97
-
98
- constructor (components: DefaultDialerComponents, init: DialerInit = {}) {
99
- this.started = false
100
- this.addressSorter = init.addressSorter ?? publicAddressesFirst
101
- this.maxAddrsToDial = init.maxAddrsToDial ?? MAX_ADDRS_TO_DIAL
102
- this.timeout = init.dialTimeout ?? DIAL_TIMEOUT
103
- this.maxDialsPerPeer = init.maxDialsPerPeer ?? MAX_PER_PEER_DIALS
104
- this.tokens = [...new Array(init.maxParallelDials ?? MAX_PARALLEL_DIALS)].map((_, index) => index)
105
- this.components = components
106
- this.pendingDials = trackedMap({
107
- name: 'libp2p_dialler_pending_dials',
108
- metrics: components.metrics
109
- })
110
- this.pendingDialTargets = trackedMap({
111
- name: 'libp2p_dialler_pending_dial_targets',
112
- metrics: components.metrics
113
- })
114
-
115
- for (const [key, value] of Object.entries(init.resolvers ?? {})) {
116
- resolvers.set(key, value)
117
- }
118
- }
119
-
120
- isStarted (): boolean {
121
- return this.started
122
- }
123
-
124
- async start (): Promise<void> {
125
- this.started = true
126
- }
127
-
128
- /**
129
- * Clears any pending dials
130
- */
131
- async stop (): Promise<void> {
132
- this.started = false
133
-
134
- for (const dial of this.pendingDials.values()) {
135
- try {
136
- dial.controller.abort()
137
- } catch (err: any) {
138
- log.error(err)
139
- }
140
- }
141
- this.pendingDials.clear()
142
-
143
- for (const pendingTarget of this.pendingDialTargets.values()) {
144
- pendingTarget.abort()
145
- }
146
- this.pendingDialTargets.clear()
147
- }
148
-
149
- /**
150
- * Connects to a given `peer` by dialing all of its known addresses.
151
- * The dial to the first address that is successfully able to upgrade a connection
152
- * will be used.
153
- */
154
- async dial (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: AbortOptions = {}): Promise<Connection> {
155
- const peerAddress = getPeerAddress(peerIdOrMultiaddr)
156
-
157
- if (peerAddress.peerId != null) {
158
- if (this.components.peerId.equals(peerAddress.peerId)) {
159
- throw new CodeError('Tried to dial self', codes.ERR_DIALED_SELF)
160
- }
161
-
162
- if (peerAddress.multiaddrs.length > 0) {
163
- log('storing multiaddrs %p', peerAddress.peerId, peerAddress.multiaddrs)
164
- await this.components.peerStore.addressBook.add(peerAddress.peerId, peerAddress.multiaddrs)
165
- }
166
-
167
- if ((await this.components.connectionGater.denyDialPeer?.(peerAddress.peerId)) === true) {
168
- throw new CodeError('The dial request is blocked by gater.allowDialPeer', codes.ERR_PEER_DIAL_INTERCEPTED)
169
- }
170
- }
171
-
172
- log('creating dial target for %p', peerAddress.peerId)
173
- return await this.createDialTarget(peerAddress, options)
174
- }
175
-
176
- async createDialTarget (peerAddress: PeerAddress, options: AbortOptions = {}): Promise<Connection> {
177
- // resolving multiaddrs can involve dns lookups so allow them to be aborted
178
- const controller = new AbortController()
179
- const controllerId = randomId()
180
-
181
- this.pendingDialTargets.set(controllerId, controller)
182
-
183
- let signal = controller.signal
184
-
185
- // merge with the passed signal, if any
186
- if (options.signal != null) {
187
- signal = anySignal([signal, options.signal])
188
- }
189
-
190
- let dialTarget: DialTarget
191
-
192
- try {
193
- dialTarget = await this._createDialTarget(peerAddress, {
194
- ...options,
195
- signal
196
- })
197
- } finally {
198
- // done resolving the multiaddrs so remove the abort controller
199
- this.pendingDialTargets.delete(controllerId)
200
- }
201
-
202
- if (dialTarget.addrs.length === 0) {
203
- throw new CodeError('The dial request has no valid addresses', codes.ERR_NO_VALID_ADDRESSES)
204
- }
205
-
206
- // try to join an in-flight dial for this peer if one is available
207
- const pendingDial = this.pendingDials.get(dialTarget.id) ?? this._createPendingDial(dialTarget, options)
208
-
209
- try {
210
- const connection = await pendingDial.promise
211
- log('dial succeeded to %s', dialTarget.id)
212
- return connection
213
- } catch (err: any) {
214
- log('dial failed to %s', dialTarget.id, err)
215
- // Error is a timeout
216
- if (pendingDial.controller.signal.aborted) {
217
- const error = new CodeError(err.message, codes.ERR_TIMEOUT)
218
- log.error(error)
219
- throw error
220
- }
221
- log.error(err)
222
- throw err
223
- } finally {
224
- pendingDial.destroy()
225
- }
226
- }
227
-
228
- /**
229
- * Get the current dial targets which are pending
230
- */
231
- getPendingDialTargets (): Map<string, AbortController> {
232
- return this.pendingDialTargets
233
- }
234
-
235
- /**
236
- * Returns true if the peer id is in the pending dials
237
- */
238
- hasPendingDial (peerId: PeerId | Multiaddr): boolean {
239
- if (isMultiaddr(peerId)) {
240
- return this.pendingDials.has(peerId.getPeerId() ?? '')
241
- }
242
-
243
- return this.pendingDials.has(peerId.toString())
244
- }
245
-
246
- /**
247
- * Creates a DialTarget. The DialTarget is used to create and track
248
- * the DialRequest to a given peer.
249
- *
250
- * If a multiaddr is received it should be the only address attempted.
251
- *
252
- * Multiaddrs not supported by the available transports will be filtered out.
253
- */
254
- async _createDialTarget (peerIdOrMultiaddr: PeerAddress, options: AbortOptions): Promise<DialTarget> {
255
- let addrs: Multiaddr[] = [
256
- ...peerIdOrMultiaddr.multiaddrs
257
- ]
258
-
259
- // load addresses if only a peer id was passed, otherwise just dial the passed multiaddrs
260
- if (peerIdOrMultiaddr.peerId != null && peerIdOrMultiaddr.multiaddrs.length === 0) {
261
- addrs.push(...await this._loadAddresses(peerIdOrMultiaddr.peerId))
262
- }
263
-
264
- // resolve addresses - this can result in a one-to-many translation when dnsaddrs are resolved
265
- addrs = (await Promise.all(
266
- addrs.map(async (ma) => await this._resolve(ma, options))
267
- ))
268
- .flat()
269
-
270
- // Multiaddrs not supported by the available transports will be filtered out.
271
- const filteredAddrs = addrs.filter(ma => Boolean(this.components.transportManager.transportForMultiaddr(ma)))
272
-
273
- // deduplicate addresses
274
- const dedupedAddrs = [...new Set(filteredAddrs.map(ma => ma.toString()))]
275
- let dedupedMultiaddrs = dedupedAddrs.map(ma => multiaddr(ma))
276
-
277
- if (dedupedMultiaddrs.length > this.maxAddrsToDial) {
278
- log('addresses after filtering', dedupedMultiaddrs.map(ma => ma.toString()))
279
- throw new CodeError('dial with more addresses than allowed', codes.ERR_TOO_MANY_ADDRESSES)
280
- }
281
-
282
- if (dedupedMultiaddrs.length === 0) {
283
- log('addresses before filtering', addrs.map(ma => ma.toString()))
284
- log('addresses after filtering', dedupedMultiaddrs.map(ma => ma.toString()))
285
- }
286
-
287
- const peerId = isPeerId(peerIdOrMultiaddr.peerId) ? peerIdOrMultiaddr.peerId : undefined
288
-
289
- if (peerId != null) {
290
- const peerIdMultiaddr = `/p2p/${peerId.toString()}`
291
- dedupedMultiaddrs = dedupedMultiaddrs.map(addr => {
292
- const addressPeerId = addr.getPeerId()
293
- const lastProto = addr.protos().pop()
294
-
295
- // do not append peer id to path multiaddrs
296
- if (lastProto?.path === true) {
297
- return addr
298
- }
299
-
300
- if (addressPeerId == null) {
301
- return addr.encapsulate(peerIdMultiaddr)
302
- }
303
-
304
- return addr
305
- })
306
- }
307
-
308
- return {
309
- id: peerId == null ? randomId() : peerId.toString(),
310
- addrs: dedupedMultiaddrs
311
- }
312
- }
313
-
314
- /**
315
- * Loads a list of addresses from the peer store for the passed peer id
316
- */
317
- async _loadAddresses (peer: PeerId): Promise<Multiaddr[]> {
318
- const addresses = await this.components.peerStore.addressBook.get(peer)
319
-
320
- return (await Promise.all(
321
- addresses.map(async address => {
322
- const deny = await this.components.connectionGater.denyDialMultiaddr?.(peer, address.multiaddr)
323
-
324
- if (deny === true) {
325
- return false
326
- }
327
-
328
- return address
329
- })
330
- ))
331
- .filter(isTruthy)
332
- // Sort addresses so, for example, we try certified public address first
333
- .sort(this.addressSorter)
334
- .map(address => address.multiaddr)
335
- }
336
-
337
- /**
338
- * Creates a PendingDial that wraps the underlying DialRequest
339
- */
340
- _createPendingDial (dialTarget: DialTarget, options: AbortOptions = {}): PendingDial {
341
- /**
342
- * @param {Multiaddr} addr
343
- * @param {{ signal: { aborted: any; }; }} options
344
- */
345
- const dialAction: DialAction = async (addr, options = {}) => {
346
- if (options.signal?.aborted === true) {
347
- throw new CodeError('already aborted', codes.ERR_ALREADY_ABORTED)
348
- }
349
-
350
- return await this.components.transportManager.dial(addr, options).catch(err => {
351
- log.error('dial to %s failed', addr, err)
352
- throw err
353
- })
354
- }
355
-
356
- const dialRequest = new DialRequest({
357
- addrs: dialTarget.addrs,
358
- dialAction,
359
- dialer: this
360
- })
361
-
362
- // Combine the timeout signal and options.signal, if provided
363
- const timeoutController = new TimeoutController(this.timeout)
364
-
365
- const signals = [timeoutController.signal]
366
- ;(options.signal != null) && signals.push(options.signal)
367
- const signal = anySignal(signals)
368
-
369
- // this signal will potentially be used while dialing lots of
370
- // peers so prevent MaxListenersExceededWarning appearing in the console
371
- try {
372
- // fails on node < 15.4
373
- setMaxListeners?.(Infinity, signal)
374
- } catch {}
375
-
376
- const pendingDial = {
377
- dialRequest,
378
- controller: timeoutController,
379
- promise: dialRequest.run({ ...options, signal }),
380
- destroy: () => {
381
- timeoutController.clear()
382
- this.pendingDials.delete(dialTarget.id)
383
- }
384
- }
385
- this.pendingDials.set(dialTarget.id, pendingDial)
386
-
387
- return pendingDial
388
- }
389
-
390
- getTokens (num: number): number[] {
391
- const total = Math.min(num, this.maxDialsPerPeer, this.tokens.length)
392
- const tokens = this.tokens.splice(0, total)
393
- log('%d tokens request, returning %d, %d remaining', num, total, this.tokens.length)
394
- return tokens
395
- }
396
-
397
- releaseToken (token: number): void {
398
- // Guard against duplicate releases
399
- if (this.tokens.includes(token)) {
400
- return
401
- }
402
-
403
- log('token %d released', token)
404
- this.tokens.push(token)
405
- }
406
-
407
- /**
408
- * Resolve multiaddr recursively
409
- */
410
- async _resolve (ma: Multiaddr, options: AbortOptions): Promise<Multiaddr[]> {
411
- // TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
412
- // Now only supporting resolve for dnsaddr
413
- const resolvableProto = ma.protoNames().includes('dnsaddr')
414
-
415
- // Multiaddr is not resolvable? End recursion!
416
- if (!resolvableProto) {
417
- return [ma]
418
- }
419
-
420
- const resolvedMultiaddrs = await this._resolveRecord(ma, options)
421
- const recursiveMultiaddrs = await Promise.all(resolvedMultiaddrs.map(async (nm) => {
422
- return await this._resolve(nm, options)
423
- }))
424
-
425
- const addrs = recursiveMultiaddrs.flat()
426
- return addrs.reduce<Multiaddr[]>((array, newM) => {
427
- if (array.find(m => m.equals(newM)) == null) {
428
- array.push(newM)
429
- }
430
- return array
431
- }, ([]))
432
- }
433
-
434
- /**
435
- * Resolve a given multiaddr. If this fails, an empty array will be returned
436
- */
437
- async _resolveRecord (ma: Multiaddr, options: AbortOptions): Promise<Multiaddr[]> {
438
- try {
439
- ma = multiaddr(ma.toString()) // Use current multiaddr module
440
- const multiaddrs = await ma.resolve(options)
441
- return multiaddrs
442
- } catch (err) {
443
- log.error(`multiaddr ${ma.toString()} could not be resolved`, err)
444
- return []
445
- }
446
- }
447
- }
448
-
449
- /**
450
- * Type safe version of `list.filter(Boolean)`
451
- */
452
- function isTruthy <T> (e: T | false | null | undefined): e is T {
453
- return Boolean(e)
454
- }
455
-
456
- /**
457
- * Returns a random string
458
- */
459
- function randomId (): string {
460
- return `${(parseInt(String(Math.random() * 1e9), 10)).toString()}${Date.now()}`
461
- }