libp2p 0.43.4 → 0.44.0-0d46c78f

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 (215) hide show
  1. package/dist/index.min.js +29 -29
  2. package/dist/src/address-manager/index.d.ts +4 -4
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/address-manager/index.js +9 -6
  5. package/dist/src/address-manager/index.js.map +1 -1
  6. package/dist/src/autonat/index.d.ts +1 -2
  7. package/dist/src/autonat/index.d.ts.map +1 -1
  8. package/dist/src/autonat/index.js +19 -19
  9. package/dist/src/autonat/index.js.map +1 -1
  10. package/dist/src/circuit-relay/server/advert-service.d.ts.map +1 -1
  11. package/dist/src/circuit-relay/server/advert-service.js +2 -2
  12. package/dist/src/circuit-relay/server/advert-service.js.map +1 -1
  13. package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
  14. package/dist/src/circuit-relay/server/index.js +7 -3
  15. package/dist/src/circuit-relay/server/index.js.map +1 -1
  16. package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
  17. package/dist/src/circuit-relay/transport/discovery.js +3 -1
  18. package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
  19. package/dist/src/circuit-relay/transport/index.d.ts +3 -0
  20. package/dist/src/circuit-relay/transport/index.d.ts.map +1 -1
  21. package/dist/src/circuit-relay/transport/index.js +6 -2
  22. package/dist/src/circuit-relay/transport/index.js.map +1 -1
  23. package/dist/src/circuit-relay/transport/listener.d.ts +3 -0
  24. package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
  25. package/dist/src/circuit-relay/transport/listener.js +5 -4
  26. package/dist/src/circuit-relay/transport/listener.js.map +1 -1
  27. package/dist/src/circuit-relay/transport/reservation-store.d.ts +4 -1
  28. package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
  29. package/dist/src/circuit-relay/transport/reservation-store.js +11 -6
  30. package/dist/src/circuit-relay/transport/reservation-store.js.map +1 -1
  31. package/dist/src/circuit-relay/utils.d.ts.map +1 -1
  32. package/dist/src/circuit-relay/utils.js +3 -1
  33. package/dist/src/circuit-relay/utils.js.map +1 -1
  34. package/dist/src/components.d.ts +7 -69
  35. package/dist/src/components.d.ts.map +1 -1
  36. package/dist/src/components.js +60 -174
  37. package/dist/src/components.js.map +1 -1
  38. package/dist/src/config/connection-gater.browser.d.ts +8 -0
  39. package/dist/src/config/connection-gater.browser.d.ts.map +1 -0
  40. package/dist/src/config/connection-gater.browser.js +27 -0
  41. package/dist/src/config/connection-gater.browser.js.map +1 -0
  42. package/dist/src/config/connection-gater.d.ts +6 -0
  43. package/dist/src/config/connection-gater.d.ts.map +1 -0
  44. package/dist/src/config/connection-gater.js +18 -0
  45. package/dist/src/config/connection-gater.js.map +1 -0
  46. package/dist/src/config.d.ts +2 -1
  47. package/dist/src/config.d.ts.map +1 -1
  48. package/dist/src/config.js +0 -71
  49. package/dist/src/config.js.map +1 -1
  50. package/dist/src/connection-manager/auto-dial.d.ts +39 -0
  51. package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
  52. package/dist/src/connection-manager/auto-dial.js +136 -0
  53. package/dist/src/connection-manager/auto-dial.js.map +1 -0
  54. package/dist/src/connection-manager/connection-pruner.d.ts +32 -0
  55. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
  56. package/dist/src/connection-manager/connection-pruner.js +111 -0
  57. package/dist/src/connection-manager/connection-pruner.js.map +1 -0
  58. package/dist/src/connection-manager/constants.d.ts +49 -0
  59. package/dist/src/connection-manager/constants.d.ts.map +1 -0
  60. package/dist/src/connection-manager/constants.js +49 -0
  61. package/dist/src/connection-manager/constants.js.map +1 -0
  62. package/dist/src/connection-manager/dial-queue.d.ts +78 -0
  63. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
  64. package/dist/src/connection-manager/dial-queue.js +372 -0
  65. package/dist/src/connection-manager/dial-queue.js.map +1 -0
  66. package/dist/src/connection-manager/index.d.ts +70 -73
  67. package/dist/src/connection-manager/index.d.ts.map +1 -1
  68. package/dist/src/connection-manager/index.js +118 -247
  69. package/dist/src/connection-manager/index.js.map +1 -1
  70. package/dist/src/connection-manager/utils.d.ts +9 -0
  71. package/dist/src/connection-manager/utils.d.ts.map +1 -0
  72. package/dist/src/connection-manager/utils.js +66 -0
  73. package/dist/src/connection-manager/utils.js.map +1 -0
  74. package/dist/src/content-routing/index.d.ts +0 -10
  75. package/dist/src/content-routing/index.d.ts.map +1 -1
  76. package/dist/src/content-routing/index.js +7 -42
  77. package/dist/src/content-routing/index.js.map +1 -1
  78. package/dist/src/content-routing/utils.d.ts.map +1 -1
  79. package/dist/src/content-routing/utils.js +3 -1
  80. package/dist/src/content-routing/utils.js.map +1 -1
  81. package/dist/src/fetch/index.d.ts +13 -35
  82. package/dist/src/fetch/index.d.ts.map +1 -1
  83. package/dist/src/fetch/index.js +10 -12
  84. package/dist/src/fetch/index.js.map +1 -1
  85. package/dist/src/identify/index.d.ts +16 -48
  86. package/dist/src/identify/index.d.ts.map +1 -1
  87. package/dist/src/identify/index.js +203 -201
  88. package/dist/src/identify/index.js.map +1 -1
  89. package/dist/src/index.d.ts +11 -67
  90. package/dist/src/index.d.ts.map +1 -1
  91. package/dist/src/index.js.map +1 -1
  92. package/dist/src/insecure/index.d.ts.map +1 -1
  93. package/dist/src/insecure/index.js +3 -1
  94. package/dist/src/insecure/index.js.map +1 -1
  95. package/dist/src/libp2p.d.ts +12 -35
  96. package/dist/src/libp2p.d.ts.map +1 -1
  97. package/dist/src/libp2p.js +141 -206
  98. package/dist/src/libp2p.js.map +1 -1
  99. package/dist/src/peer-routing.d.ts +1 -38
  100. package/dist/src/peer-routing.d.ts.map +1 -1
  101. package/dist/src/peer-routing.js +0 -59
  102. package/dist/src/peer-routing.js.map +1 -1
  103. package/dist/src/ping/constants.d.ts +4 -0
  104. package/dist/src/ping/constants.d.ts.map +1 -1
  105. package/dist/src/ping/constants.js +10 -0
  106. package/dist/src/ping/constants.js.map +1 -1
  107. package/dist/src/ping/index.d.ts +10 -27
  108. package/dist/src/ping/index.d.ts.map +1 -1
  109. package/dist/src/ping/index.js +18 -21
  110. package/dist/src/ping/index.js.map +1 -1
  111. package/dist/src/registrar.d.ts +5 -2
  112. package/dist/src/registrar.d.ts.map +1 -1
  113. package/dist/src/registrar.js +27 -25
  114. package/dist/src/registrar.js.map +1 -1
  115. package/dist/src/transport-manager.d.ts +15 -4
  116. package/dist/src/transport-manager.d.ts.map +1 -1
  117. package/dist/src/transport-manager.js +37 -12
  118. package/dist/src/transport-manager.js.map +1 -1
  119. package/dist/src/upgrader.d.ts +16 -11
  120. package/dist/src/upgrader.d.ts.map +1 -1
  121. package/dist/src/upgrader.js +38 -47
  122. package/dist/src/upgrader.js.map +1 -1
  123. package/dist/src/upnp-nat/index.d.ts +42 -0
  124. package/dist/src/upnp-nat/index.d.ts.map +1 -0
  125. package/dist/src/{nat-manager.js → upnp-nat/index.js} +11 -7
  126. package/dist/src/upnp-nat/index.js.map +1 -0
  127. package/package.json +70 -54
  128. package/src/address-manager/index.ts +12 -8
  129. package/src/autonat/index.ts +20 -22
  130. package/src/circuit-relay/server/advert-service.ts +2 -2
  131. package/src/circuit-relay/server/index.ts +7 -3
  132. package/src/circuit-relay/transport/discovery.ts +3 -1
  133. package/src/circuit-relay/transport/index.ts +10 -2
  134. package/src/circuit-relay/transport/listener.ts +8 -4
  135. package/src/circuit-relay/transport/reservation-store.ts +15 -7
  136. package/src/circuit-relay/utils.ts +3 -1
  137. package/src/components.ts +72 -251
  138. package/src/config/connection-gater.browser.ts +31 -0
  139. package/src/config/connection-gater.ts +19 -0
  140. package/src/config.ts +3 -73
  141. package/src/connection-manager/auto-dial.ts +189 -0
  142. package/src/connection-manager/connection-pruner.ts +157 -0
  143. package/src/connection-manager/constants.ts +60 -0
  144. package/src/connection-manager/dial-queue.ts +506 -0
  145. package/src/connection-manager/index.ts +194 -339
  146. package/src/connection-manager/utils.ts +76 -0
  147. package/src/content-routing/index.ts +7 -55
  148. package/src/content-routing/utils.ts +3 -1
  149. package/src/fetch/index.ts +55 -18
  150. package/src/identify/index.ts +238 -228
  151. package/src/index.ts +12 -76
  152. package/src/insecure/index.ts +9 -5
  153. package/src/libp2p.ts +146 -265
  154. package/src/peer-routing.ts +1 -101
  155. package/src/ping/constants.ts +11 -0
  156. package/src/ping/index.ts +32 -28
  157. package/src/registrar.ts +31 -27
  158. package/src/transport-manager.ts +49 -15
  159. package/src/upgrader.ts +62 -57
  160. package/src/{nat-manager.ts → upnp-nat/index.ts} +15 -16
  161. package/src/version.ts +1 -1
  162. package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
  163. package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
  164. package/dist/src/connection-manager/auto-dialler.js +0 -105
  165. package/dist/src/connection-manager/auto-dialler.js.map +0 -1
  166. package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
  167. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
  168. package/dist/src/connection-manager/dialer/dial-request.js +0 -114
  169. package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
  170. package/dist/src/connection-manager/dialer/index.d.ts +0 -121
  171. package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
  172. package/dist/src/connection-manager/dialer/index.js +0 -324
  173. package/dist/src/connection-manager/dialer/index.js.map +0 -1
  174. package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
  175. package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
  176. package/dist/src/connection-manager/latency-monitor.js +0 -220
  177. package/dist/src/connection-manager/latency-monitor.js.map +0 -1
  178. package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
  179. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
  180. package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
  181. package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
  182. package/dist/src/constants.d.ts +0 -27
  183. package/dist/src/constants.d.ts.map +0 -1
  184. package/dist/src/constants.js +0 -31
  185. package/dist/src/constants.js.map +0 -1
  186. package/dist/src/dht/dht-content-routing.d.ts +0 -17
  187. package/dist/src/dht/dht-content-routing.d.ts.map +0 -1
  188. package/dist/src/dht/dht-content-routing.js +0 -32
  189. package/dist/src/dht/dht-content-routing.js.map +0 -1
  190. package/dist/src/dht/dht-peer-routing.d.ts +0 -15
  191. package/dist/src/dht/dht-peer-routing.d.ts.map +0 -1
  192. package/dist/src/dht/dht-peer-routing.js +0 -26
  193. package/dist/src/dht/dht-peer-routing.js.map +0 -1
  194. package/dist/src/dht/dummy-dht.d.ts +0 -20
  195. package/dist/src/dht/dummy-dht.d.ts.map +0 -1
  196. package/dist/src/dht/dummy-dht.js +0 -46
  197. package/dist/src/dht/dummy-dht.js.map +0 -1
  198. package/dist/src/nat-manager.d.ts +0 -74
  199. package/dist/src/nat-manager.d.ts.map +0 -1
  200. package/dist/src/nat-manager.js.map +0 -1
  201. package/dist/src/peer-record-updater.d.ts +0 -24
  202. package/dist/src/peer-record-updater.d.ts.map +0 -1
  203. package/dist/src/peer-record-updater.js +0 -44
  204. package/dist/src/peer-record-updater.js.map +0 -1
  205. package/dist/typedoc-urls.json +0 -41
  206. package/src/connection-manager/auto-dialler.ts +0 -158
  207. package/src/connection-manager/dialer/dial-request.ts +0 -144
  208. package/src/connection-manager/dialer/index.ts +0 -461
  209. package/src/connection-manager/latency-monitor.ts +0 -319
  210. package/src/connection-manager/visibility-change-emitter.ts +0 -135
  211. package/src/constants.ts +0 -36
  212. package/src/dht/dht-content-routing.ts +0 -44
  213. package/src/dht/dht-peer-routing.ts +0 -36
  214. package/src/dht/dummy-dht.ts +0 -60
  215. package/src/peer-record-updater.ts +0 -65
@@ -0,0 +1,506 @@
1
+ import { logger } from '@libp2p/logger'
2
+ import { AbortError, CodeError } from '@libp2p/interfaces/errors'
3
+ import { Multiaddr, Resolver, resolvers } from '@multiformats/multiaddr'
4
+ import { publicAddressesFirst } from '@libp2p/utils/address-sort'
5
+ import { codes } from '../errors.js'
6
+ import {
7
+ DIAL_TIMEOUT,
8
+ MAX_PARALLEL_DIALS_PER_PEER,
9
+ MAX_PARALLEL_DIALS,
10
+ MAX_PEER_ADDRS_TO_DIAL
11
+ } from './constants.js'
12
+ import type { Connection } from '@libp2p/interface-connection'
13
+ import type { AbortOptions } from '@libp2p/interfaces'
14
+ import type { PeerId } from '@libp2p/interface-peer-id'
15
+ import { getPeerAddress } from '../get-peer.js'
16
+ import type { Address, PeerStore } from '@libp2p/interface-peer-store'
17
+ import type { Metric, Metrics } from '@libp2p/interface-metrics'
18
+ import type { TransportManager } from '@libp2p/interface-transport'
19
+ import type { ConnectionGater } from '@libp2p/interface-connection-gater'
20
+ import PQueue from 'p-queue'
21
+ import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
22
+ import { combineSignals, resolveMultiaddrs } from './utils.js'
23
+ import pDefer from 'p-defer'
24
+ import { ClearableSignal, anySignal } from 'any-signal'
25
+ import type { AddressSorter } from '@libp2p/interface-libp2p'
26
+
27
+ const log = logger('libp2p:connection-manager:dial-queue')
28
+
29
+ export type PendingDialStatus = 'queued' | 'active' | 'error' | 'success'
30
+
31
+ export interface PendingDial {
32
+ id: string
33
+ status: PendingDialStatus
34
+ peerId?: PeerId
35
+ multiaddrs: Multiaddr[]
36
+ promise: Promise<Connection>
37
+ }
38
+
39
+ export interface PendingDialTarget {
40
+ resolve: (value: any) => void
41
+ reject: (err: Error) => void
42
+ }
43
+
44
+ export interface DialOptions extends AbortOptions {
45
+ priority?: number
46
+ }
47
+
48
+ interface DialerInit {
49
+ addressSorter?: AddressSorter
50
+ maxParallelDials?: number
51
+ maxPeerAddrsToDial?: number
52
+ maxParallelDialsPerPeer?: number
53
+ dialTimeout?: number
54
+ resolvers?: Record<string, Resolver>
55
+ }
56
+
57
+ const defaultOptions = {
58
+ addressSorter: publicAddressesFirst,
59
+ maxParallelDials: MAX_PARALLEL_DIALS,
60
+ maxPeerAddrsToDial: MAX_PEER_ADDRS_TO_DIAL,
61
+ maxParallelDialsPerPeer: MAX_PARALLEL_DIALS_PER_PEER,
62
+ dialTimeout: DIAL_TIMEOUT,
63
+ resolvers: {
64
+ dnsaddr: dnsaddrResolver
65
+ }
66
+ }
67
+
68
+ interface DialQueueComponents {
69
+ peerId: PeerId
70
+ metrics?: Metrics
71
+ peerStore: PeerStore
72
+ transportManager: TransportManager
73
+ connectionGater: ConnectionGater
74
+ }
75
+
76
+ export class DialQueue {
77
+ public pendingDials: PendingDial[]
78
+ public queue: PQueue
79
+ private readonly peerId: PeerId
80
+ private readonly peerStore: PeerStore
81
+ private readonly connectionGater: ConnectionGater
82
+ private readonly transportManager: TransportManager
83
+ private readonly addressSorter: AddressSorter
84
+ private readonly maxPeerAddrsToDial: number
85
+ private readonly maxParallelDialsPerPeer: number
86
+ private readonly dialTimeout: number
87
+ private readonly inProgressDialCount?: Metric
88
+ private readonly pendingDialCount?: Metric
89
+ private readonly shutDownController: AbortController
90
+
91
+ constructor (components: DialQueueComponents, init: DialerInit = {}) {
92
+ this.addressSorter = init.addressSorter ?? defaultOptions.addressSorter
93
+ this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial
94
+ this.maxParallelDialsPerPeer = init.maxParallelDialsPerPeer ?? defaultOptions.maxParallelDialsPerPeer
95
+ this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout
96
+
97
+ this.peerId = components.peerId
98
+ this.peerStore = components.peerStore
99
+ this.connectionGater = components.connectionGater
100
+ this.transportManager = components.transportManager
101
+ this.shutDownController = new AbortController()
102
+
103
+ this.pendingDialCount = components.metrics?.registerMetric('libp2p_dialler_pending_dials')
104
+ this.inProgressDialCount = components.metrics?.registerMetric('libp2p_dialler_in_progress_dials')
105
+ this.pendingDials = []
106
+
107
+ for (const [key, value] of Object.entries(init.resolvers ?? {})) {
108
+ resolvers.set(key, value)
109
+ }
110
+
111
+ // controls dial concurrency
112
+ this.queue = new PQueue({
113
+ concurrency: init.maxParallelDials ?? defaultOptions.maxParallelDials
114
+ })
115
+
116
+ // a job was added to the queue
117
+ this.queue.on('add', () => {
118
+ this.pendingDialCount?.update(this.queue.size)
119
+ this.inProgressDialCount?.update(this.queue.pending)
120
+ })
121
+ // a queued job started
122
+ this.queue.on('active', () => {
123
+ this.pendingDialCount?.update(this.queue.size)
124
+ this.inProgressDialCount?.update(this.queue.pending)
125
+ })
126
+ // a started job completed without error
127
+ this.queue.on('completed', () => {
128
+ this.pendingDialCount?.update(this.queue.size)
129
+ this.inProgressDialCount?.update(this.queue.pending)
130
+ })
131
+ // a started job errored
132
+ this.queue.on('error', (err) => {
133
+ log.error('error in dial queue', err)
134
+ this.pendingDialCount?.update(this.queue.size)
135
+ this.inProgressDialCount?.update(this.queue.pending)
136
+ })
137
+ // all queued jobs have been started
138
+ this.queue.on('empty', () => {
139
+ this.pendingDialCount?.update(this.queue.size)
140
+ this.inProgressDialCount?.update(this.queue.pending)
141
+ })
142
+ // add started jobs have run and the queue is empty
143
+ this.queue.on('idle', () => {
144
+ this.pendingDialCount?.update(this.queue.size)
145
+ this.inProgressDialCount?.update(this.queue.pending)
146
+ })
147
+ }
148
+
149
+ /**
150
+ * Clears any pending dials
151
+ */
152
+ stop (): void {
153
+ this.shutDownController.abort()
154
+ }
155
+
156
+ /**
157
+ * Connects to a given peer, multiaddr or list of multiaddrs.
158
+ *
159
+ * If a peer is passed, all known multiaddrs will be tried. If a multiaddr or
160
+ * multiaddrs are passed only those will be dialled.
161
+ *
162
+ * Where a list of multiaddrs is passed, if any contain a peer id then all
163
+ * multiaddrs in the list must contain the same peer id.
164
+ *
165
+ * The dial to the first address that is successfully able to upgrade a connection
166
+ * will be used, all other dials will be aborted when that happens.
167
+ */
168
+ async dial (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: DialOptions = {}): Promise<Connection> {
169
+ const { peerId, multiaddrs } = getPeerAddress(peerIdOrMultiaddr)
170
+
171
+ const addrs: Address[] = multiaddrs.map(multiaddr => ({
172
+ multiaddr,
173
+ isCertified: false
174
+ }))
175
+
176
+ // create abort conditions - need to do this before `calculateMultiaddrs` as we may be about to
177
+ // resolve a dns addr which can time out
178
+ const signal = this.createDialAbortControllers(options.signal)
179
+ let addrsToDial: Address[]
180
+
181
+ try {
182
+ // load addresses from address book, resolve and dnsaddrs, filter undiallables, add peer IDs, etc
183
+ addrsToDial = await this.calculateMultiaddrs(peerId, addrs, {
184
+ ...options,
185
+ signal
186
+ })
187
+ } catch (err) {
188
+ signal.clear()
189
+ throw err
190
+ }
191
+
192
+ // ready to dial, all async work finished - make sure we don't have any
193
+ // pending dials in progress for this peer or set of multiaddrs
194
+ const existingDial = this.pendingDials.find(dial => {
195
+ // is the dial for the same peer id?
196
+ if (dial.peerId != null && peerId != null && dial.peerId.equals(peerId)) {
197
+ return true
198
+ }
199
+
200
+ // is the dial for the same set of multiaddrs?
201
+ if (addrsToDial.map(({ multiaddr }) => multiaddr.toString()).join() === dial.multiaddrs.map(multiaddr => multiaddr.toString()).join()) {
202
+ return true
203
+ }
204
+
205
+ return false
206
+ })
207
+
208
+ if (existingDial != null) {
209
+ log('joining existing dial target for %p', peerId)
210
+ signal.clear()
211
+ return await existingDial.promise
212
+ }
213
+
214
+ log('creating dial target for', addrsToDial.map(({ multiaddr }) => multiaddr.toString()))
215
+ // @ts-expect-error .promise property is set below
216
+ const pendingDial: PendingDial = {
217
+ id: randomId(),
218
+ status: 'queued',
219
+ peerId,
220
+ multiaddrs: addrsToDial.map(({ multiaddr }) => multiaddr)
221
+ }
222
+
223
+ pendingDial.promise = this.performDial(pendingDial, {
224
+ ...options,
225
+ signal
226
+ })
227
+ .finally(() => {
228
+ // remove our pending dial entry
229
+ this.pendingDials = this.pendingDials.filter(p => p.id !== pendingDial.id)
230
+
231
+ // clean up abort signals/controllers
232
+ signal.clear()
233
+ })
234
+ .catch(err => {
235
+ log.error('dial failed to %s', addrsToDial.map(({ multiaddr }) => multiaddr.toString()).join(', '), err)
236
+
237
+ // Error is a timeout
238
+ if (signal.aborted) {
239
+ const error = new CodeError(err.message, codes.ERR_TIMEOUT)
240
+ throw error
241
+ }
242
+
243
+ throw err
244
+ })
245
+
246
+ // let other dials join this one
247
+ this.pendingDials.push(pendingDial)
248
+
249
+ return await pendingDial.promise
250
+ }
251
+
252
+ private createDialAbortControllers (userSignal?: AbortSignal): ClearableSignal {
253
+ // let any signal abort the dial
254
+ const signal = anySignal(
255
+ [AbortSignal.timeout(this.dialTimeout),
256
+ this.shutDownController.signal,
257
+ userSignal
258
+ ]
259
+ )
260
+
261
+ return signal
262
+ }
263
+
264
+ private async calculateMultiaddrs (peerId?: PeerId, addrs: Address[] = [], options: DialOptions = {}): Promise<Address[]> {
265
+ // 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
266
+ if (peerId != null) {
267
+ if (this.peerId.equals(peerId)) {
268
+ throw new CodeError('Tried to dial self', codes.ERR_DIALED_SELF)
269
+ }
270
+
271
+ if ((await this.connectionGater.denyDialPeer?.(peerId)) === true) {
272
+ throw new CodeError('The dial request is blocked by gater.allowDialPeer', codes.ERR_PEER_DIAL_INTERCEPTED)
273
+ }
274
+
275
+ // if just a peer id was passed, load available multiaddrs for this peer from the address book
276
+ if (addrs.length === 0) {
277
+ log('loading multiaddrs for %p', peerId)
278
+ try {
279
+ const peer = await this.peerStore.get(peerId)
280
+ addrs.push(...peer.addresses)
281
+ log('loaded multiaddrs for %p', peerId, addrs.map(({ multiaddr }) => multiaddr.toString()))
282
+ } catch (err: any) {
283
+ if (err.code !== codes.ERR_NOT_FOUND) {
284
+ throw err
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ // resolve addresses - this can result in a one-to-many translation when dnsaddrs are resolved
291
+ const resolvedAddresses = (await Promise.all(
292
+ addrs.map(async addr => {
293
+ const result = await resolveMultiaddrs(addr.multiaddr, options)
294
+
295
+ if (result.length === 1 && result[0].equals(addr.multiaddr)) {
296
+ return addr
297
+ }
298
+
299
+ return result.map(multiaddr => ({
300
+ multiaddr,
301
+ isCertified: false
302
+ }))
303
+ })
304
+ ))
305
+ .flat()
306
+
307
+ // filter out any multiaddrs that we do not have transports for
308
+ const filteredAddrs = resolvedAddresses.filter(addr => Boolean(this.transportManager.transportForMultiaddr(addr.multiaddr)))
309
+
310
+ // deduplicate addresses
311
+ const dedupedAddrs: Map<string, Address> = new Map()
312
+
313
+ for (const addr of filteredAddrs) {
314
+ const maStr = addr.multiaddr.toString()
315
+ const existing = dedupedAddrs.get(maStr)
316
+
317
+ if (existing != null) {
318
+ existing.isCertified = existing.isCertified || addr.isCertified || false
319
+ continue
320
+ }
321
+
322
+ dedupedAddrs.set(maStr, addr)
323
+ }
324
+
325
+ let dedupedMultiaddrs = [...dedupedAddrs.values()]
326
+
327
+ if (dedupedMultiaddrs.length === 0 || dedupedMultiaddrs.length > this.maxPeerAddrsToDial) {
328
+ log('addresses for %p before filtering', peerId ?? 'unknown peer', resolvedAddresses.map(({ multiaddr }) => multiaddr.toString()))
329
+ log('addresses for %p after filtering', peerId ?? 'unknown peer', dedupedMultiaddrs.map(({ multiaddr }) => multiaddr.toString()))
330
+ }
331
+
332
+ // make sure we actually have some addresses to dial
333
+ if (dedupedMultiaddrs.length === 0) {
334
+ throw new CodeError('The dial request has no valid addresses', codes.ERR_NO_VALID_ADDRESSES)
335
+ }
336
+
337
+ // make sure we don't have too many addresses to dial
338
+ if (dedupedMultiaddrs.length > this.maxPeerAddrsToDial) {
339
+ throw new CodeError('dial with more addresses than allowed', codes.ERR_TOO_MANY_ADDRESSES)
340
+ }
341
+
342
+ // ensure the peer id is appended to the multiaddr
343
+ if (peerId != null) {
344
+ const peerIdMultiaddr = `/p2p/${peerId.toString()}`
345
+ dedupedMultiaddrs = dedupedMultiaddrs.map(addr => {
346
+ const addressPeerId = addr.multiaddr.getPeerId()
347
+ const lastProto = addr.multiaddr.protos().pop()
348
+
349
+ // do not append peer id to path multiaddrs
350
+ if (lastProto?.path === true) {
351
+ return addr
352
+ }
353
+
354
+ // append peer id to multiaddr if it is not already present
355
+ if (addressPeerId !== peerId.toString()) {
356
+ return {
357
+ multiaddr: addr.multiaddr.encapsulate(peerIdMultiaddr),
358
+ isCertified: addr.isCertified
359
+ }
360
+ }
361
+
362
+ return addr
363
+ })
364
+ }
365
+
366
+ const gatedAdrs: Address[] = []
367
+
368
+ for (const addr of dedupedMultiaddrs) {
369
+ if (this.connectionGater.denyDialMultiaddr != null && await this.connectionGater.denyDialMultiaddr(addr.multiaddr)) {
370
+ continue
371
+ }
372
+
373
+ gatedAdrs.push(addr)
374
+ }
375
+
376
+ return gatedAdrs.sort(this.addressSorter)
377
+ }
378
+
379
+ private async performDial (pendingDial: PendingDial, options: DialOptions = {}): Promise<Connection> {
380
+ const dialAbortControllers: Array<(AbortController | undefined)> = pendingDial.multiaddrs.map(() => new AbortController())
381
+
382
+ try {
383
+ // internal peer dial queue to ensure we only dial the configured number of addresses
384
+ // per peer at the same time to prevent one peer with a lot of addresses swamping
385
+ // the dial queue
386
+ const peerDialQueue = new PQueue({
387
+ concurrency: this.maxParallelDialsPerPeer
388
+ })
389
+ peerDialQueue.on('error', (err) => {
390
+ log.error('error dialling', err)
391
+ })
392
+
393
+ const conn = await Promise.any(pendingDial.multiaddrs.map(async (addr, i) => {
394
+ const controller = dialAbortControllers[i]
395
+
396
+ if (controller == null) {
397
+ throw new CodeError('dialAction did not come with an AbortController', codes.ERR_INVALID_PARAMETERS)
398
+ }
399
+
400
+ // let any signal abort the dial
401
+ const signal = combineSignals(controller.signal, options.signal)
402
+ signal.addEventListener('abort', () => {
403
+ log('dial to %s aborted', addr)
404
+ })
405
+ const deferred = pDefer<Connection>()
406
+
407
+ await peerDialQueue.add(async () => {
408
+ if (signal.aborted) {
409
+ log('dial to %s was aborted before reaching the head of the peer dial queue', addr)
410
+ deferred.reject(new AbortError())
411
+ return
412
+ }
413
+
414
+ // add the individual dial to the dial queue so we don't breach maxConcurrentDials
415
+ await this.queue.add(async () => {
416
+ try {
417
+ if (signal.aborted) {
418
+ log('dial to %s was aborted before reaching the head of the dial queue', addr)
419
+ deferred.reject(new AbortError())
420
+ return
421
+ }
422
+
423
+ // update dial status
424
+ pendingDial.status = 'active'
425
+
426
+ const conn = await this.transportManager.dial(addr, {
427
+ ...options,
428
+ signal
429
+ })
430
+
431
+ if (controller.signal.aborted) {
432
+ // another dial succeeded faster than this one
433
+ log('multiple dials succeeded, closing superfluous connection')
434
+
435
+ conn.close().catch(err => {
436
+ log.error('error closing superfluous connection', err)
437
+ })
438
+
439
+ deferred.reject(new AbortError())
440
+ return
441
+ }
442
+
443
+ // remove the successful AbortController so it is not aborted
444
+ dialAbortControllers[i] = undefined
445
+
446
+ // immediately abort any other dials
447
+ dialAbortControllers.forEach(c => {
448
+ if (c !== undefined) {
449
+ c.abort()
450
+ }
451
+ })
452
+
453
+ log('dial to %s succeeded', addr)
454
+
455
+ // resolve the connection promise
456
+ deferred.resolve(conn)
457
+ } catch (err: any) {
458
+ // something only went wrong if our signal was not aborted
459
+ log.error('error during dial of %s', addr, err)
460
+ deferred.reject(err)
461
+ }
462
+ }, {
463
+ ...options,
464
+ signal
465
+ }).catch(err => {
466
+ deferred.reject(err)
467
+ })
468
+ }, {
469
+ signal
470
+ }).catch(err => {
471
+ deferred.reject(err)
472
+ }).finally(() => {
473
+ signal.clear()
474
+ })
475
+
476
+ return await deferred.promise
477
+ }))
478
+
479
+ // dial succeeded or failed
480
+ if (conn == null) {
481
+ throw new CodeError('successful dial led to empty object returned from peer dial queue', codes.ERR_TRANSPORT_DIAL_FAILED)
482
+ }
483
+
484
+ pendingDial.status = 'success'
485
+
486
+ return conn
487
+ } catch (err: any) {
488
+ pendingDial.status = 'error'
489
+
490
+ // if we only dialled one address, unwrap the AggregateError to provide more
491
+ // useful feedback to the user
492
+ if (pendingDial.multiaddrs.length === 1 && err.name === 'AggregateError') {
493
+ throw err.errors[0]
494
+ }
495
+
496
+ throw err
497
+ }
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Returns a random string
503
+ */
504
+ function randomId (): string {
505
+ return `${(parseInt(String(Math.random() * 1e9), 10)).toString()}${Date.now()}`
506
+ }