libp2p 0.43.4 → 0.44.0-17eb162a

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 (162) 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 +4 -6
  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 +8 -6
  35. package/dist/src/components.d.ts.map +1 -1
  36. package/dist/src/components.js +10 -10
  37. package/dist/src/components.js.map +1 -1
  38. package/dist/src/config.d.ts.map +1 -1
  39. package/dist/src/config.js +0 -9
  40. package/dist/src/config.js.map +1 -1
  41. package/dist/src/connection-manager/auto-dial.d.ts +39 -0
  42. package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
  43. package/dist/src/connection-manager/auto-dial.js +131 -0
  44. package/dist/src/connection-manager/auto-dial.js.map +1 -0
  45. package/dist/src/connection-manager/connection-pruner.d.ts +32 -0
  46. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
  47. package/dist/src/connection-manager/connection-pruner.js +111 -0
  48. package/dist/src/connection-manager/connection-pruner.js.map +1 -0
  49. package/dist/src/connection-manager/constants.d.ts +49 -0
  50. package/dist/src/connection-manager/constants.d.ts.map +1 -0
  51. package/dist/src/connection-manager/constants.js +49 -0
  52. package/dist/src/connection-manager/constants.js.map +1 -0
  53. package/dist/src/connection-manager/dial-queue.d.ts +78 -0
  54. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
  55. package/dist/src/connection-manager/dial-queue.js +374 -0
  56. package/dist/src/connection-manager/dial-queue.js.map +1 -0
  57. package/dist/src/connection-manager/index.d.ts +70 -73
  58. package/dist/src/connection-manager/index.d.ts.map +1 -1
  59. package/dist/src/connection-manager/index.js +116 -248
  60. package/dist/src/connection-manager/index.js.map +1 -1
  61. package/dist/src/connection-manager/utils.d.ts +9 -0
  62. package/dist/src/connection-manager/utils.d.ts.map +1 -0
  63. package/dist/src/connection-manager/utils.js +66 -0
  64. package/dist/src/connection-manager/utils.js.map +1 -0
  65. package/dist/src/content-routing/index.js +1 -1
  66. package/dist/src/content-routing/index.js.map +1 -1
  67. package/dist/src/content-routing/utils.d.ts.map +1 -1
  68. package/dist/src/content-routing/utils.js +3 -1
  69. package/dist/src/content-routing/utils.js.map +1 -1
  70. package/dist/src/fetch/index.js +3 -3
  71. package/dist/src/fetch/index.js.map +1 -1
  72. package/dist/src/identify/index.d.ts +4 -0
  73. package/dist/src/identify/index.d.ts.map +1 -1
  74. package/dist/src/identify/index.js +104 -128
  75. package/dist/src/identify/index.js.map +1 -1
  76. package/dist/src/index.d.ts +2 -19
  77. package/dist/src/index.d.ts.map +1 -1
  78. package/dist/src/index.js.map +1 -1
  79. package/dist/src/insecure/index.d.ts.map +1 -1
  80. package/dist/src/insecure/index.js +3 -1
  81. package/dist/src/insecure/index.js.map +1 -1
  82. package/dist/src/libp2p.d.ts +5 -3
  83. package/dist/src/libp2p.d.ts.map +1 -1
  84. package/dist/src/libp2p.js +47 -50
  85. package/dist/src/libp2p.js.map +1 -1
  86. package/dist/src/registrar.d.ts +5 -2
  87. package/dist/src/registrar.d.ts.map +1 -1
  88. package/dist/src/registrar.js +25 -23
  89. package/dist/src/registrar.js.map +1 -1
  90. package/dist/src/transport-manager.d.ts +9 -3
  91. package/dist/src/transport-manager.d.ts.map +1 -1
  92. package/dist/src/transport-manager.js +23 -9
  93. package/dist/src/transport-manager.js.map +1 -1
  94. package/dist/src/upgrader.d.ts +14 -11
  95. package/dist/src/upgrader.d.ts.map +1 -1
  96. package/dist/src/upgrader.js +14 -10
  97. package/dist/src/upgrader.js.map +1 -1
  98. package/package.json +46 -45
  99. package/src/address-manager/index.ts +12 -8
  100. package/src/autonat/index.ts +6 -9
  101. package/src/circuit-relay/server/advert-service.ts +2 -2
  102. package/src/circuit-relay/server/index.ts +7 -3
  103. package/src/circuit-relay/transport/discovery.ts +3 -1
  104. package/src/circuit-relay/transport/index.ts +10 -2
  105. package/src/circuit-relay/transport/listener.ts +8 -4
  106. package/src/circuit-relay/transport/reservation-store.ts +15 -7
  107. package/src/circuit-relay/utils.ts +3 -1
  108. package/src/components.ts +19 -17
  109. package/src/config.ts +0 -9
  110. package/src/connection-manager/auto-dial.ts +183 -0
  111. package/src/connection-manager/connection-pruner.ts +157 -0
  112. package/src/connection-manager/constants.ts +60 -0
  113. package/src/connection-manager/dial-queue.ts +512 -0
  114. package/src/connection-manager/index.ts +191 -340
  115. package/src/connection-manager/utils.ts +76 -0
  116. package/src/content-routing/index.ts +1 -1
  117. package/src/content-routing/utils.ts +3 -1
  118. package/src/fetch/index.ts +4 -4
  119. package/src/identify/index.ts +100 -140
  120. package/src/index.ts +2 -20
  121. package/src/insecure/index.ts +9 -5
  122. package/src/libp2p.ts +54 -60
  123. package/src/registrar.ts +29 -25
  124. package/src/transport-manager.ts +31 -11
  125. package/src/upgrader.ts +31 -22
  126. package/src/version.ts +1 -1
  127. package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
  128. package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
  129. package/dist/src/connection-manager/auto-dialler.js +0 -105
  130. package/dist/src/connection-manager/auto-dialler.js.map +0 -1
  131. package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
  132. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
  133. package/dist/src/connection-manager/dialer/dial-request.js +0 -114
  134. package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
  135. package/dist/src/connection-manager/dialer/index.d.ts +0 -121
  136. package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
  137. package/dist/src/connection-manager/dialer/index.js +0 -324
  138. package/dist/src/connection-manager/dialer/index.js.map +0 -1
  139. package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
  140. package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
  141. package/dist/src/connection-manager/latency-monitor.js +0 -220
  142. package/dist/src/connection-manager/latency-monitor.js.map +0 -1
  143. package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
  144. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
  145. package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
  146. package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
  147. package/dist/src/constants.d.ts +0 -27
  148. package/dist/src/constants.d.ts.map +0 -1
  149. package/dist/src/constants.js +0 -31
  150. package/dist/src/constants.js.map +0 -1
  151. package/dist/src/peer-record-updater.d.ts +0 -24
  152. package/dist/src/peer-record-updater.d.ts.map +0 -1
  153. package/dist/src/peer-record-updater.js +0 -44
  154. package/dist/src/peer-record-updater.js.map +0 -1
  155. package/dist/typedoc-urls.json +0 -41
  156. package/src/connection-manager/auto-dialler.ts +0 -158
  157. package/src/connection-manager/dialer/dial-request.ts +0 -144
  158. package/src/connection-manager/dialer/index.ts +0 -461
  159. package/src/connection-manager/latency-monitor.ts +0 -319
  160. package/src/connection-manager/visibility-change-emitter.ts +0 -135
  161. package/src/constants.ts +0 -36
  162. package/src/peer-record-updater.ts +0 -65
@@ -1,69 +1,91 @@
1
1
  import { logger } from '@libp2p/logger'
2
2
  import { CodeError } from '@libp2p/interfaces/errors'
3
- import mergeOptions from 'merge-options'
4
- import { LatencyMonitor, SummaryObject } from './latency-monitor.js'
5
3
  import type { AbortOptions } from '@libp2p/interfaces'
6
- import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
4
+ import type { EventEmitter } from '@libp2p/interfaces/events'
7
5
  import type { Startable } from '@libp2p/interfaces/startable'
8
6
  import { codes } from '../errors.js'
9
- import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
10
- import { setMaxListeners } from 'events'
7
+ import type { PeerId } from '@libp2p/interface-peer-id'
11
8
  import type { Connection, MultiaddrConnection } from '@libp2p/interface-connection'
12
- import type { ConnectionManager, ConnectionManagerEvents, Dialer } from '@libp2p/interface-connection-manager'
13
- import * as STATUS from '@libp2p/interface-connection/status'
14
- import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
15
- import { multiaddr, Multiaddr, Resolver } from '@multiformats/multiaddr'
16
- import { PeerMap } from '@libp2p/peer-collections'
17
- import { TimeoutController } from 'timeout-abort-controller'
9
+ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
10
+ import type { PeerStore } from '@libp2p/interface-peer-store'
11
+ import { Multiaddr, Resolver, multiaddr } from '@multiformats/multiaddr'
18
12
  import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
19
13
  import { RateLimiterMemory } from 'rate-limiter-flexible'
20
14
  import type { Metrics } from '@libp2p/interface-metrics'
21
- import type { Upgrader } from '@libp2p/interface-transport'
15
+ import type { TransportManager } from '@libp2p/interface-transport'
22
16
  import { getPeerAddress } from '../get-peer.js'
17
+ import { AutoDial } from './auto-dial.js'
18
+ import { DialQueue } from './dial-queue.js'
19
+ import { ConnectionPruner } from './connection-pruner.js'
20
+ import type { ConnectionGater } from '@libp2p/interface-connection-gater'
21
+ import { PeerMap } from '@libp2p/peer-collections'
22
+ import { publicAddressesFirst } from '@libp2p/utils/address-sort'
23
+ import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js'
24
+ import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
25
+ import type { PendingDial, AddressSorter, Libp2pEvents } from '@libp2p/interface-libp2p'
23
26
 
24
27
  const log = logger('libp2p:connection-manager')
25
28
 
26
- export interface ConnectionManagerConfig {
29
+ const DEFAULT_DIAL_PRIORITY = 50
30
+
31
+ export interface ConnectionManagerInit {
27
32
  /**
28
- * The maximum number of connections libp2p is willing to have before it starts disconnecting. Defaults to `Infinity`
33
+ * The maximum number of connections libp2p is willing to have before it starts
34
+ * pruning connections to reduce resource usage. (default: 300)
29
35
  */
30
- maxConnections: number
36
+ maxConnections?: number
31
37
 
32
38
  /**
33
- * The minimum number of connections below which libp2p not activate preemptive disconnections. Defaults to `0`.
39
+ * The minimum number of connections below which libp2p will start to dial peers
40
+ * from the peer book. Setting this to 0 effectively disables this behaviour.
41
+ * (default: 50)
34
42
  */
35
- minConnections: number
43
+ minConnections?: number
36
44
 
37
45
  /**
38
- * Sets the maximum event loop delay (measured in milliseconds) this node is willing to endure before it starts disconnecting peers. Defaults to `Infinity`.
46
+ * How long to wait between attempting to keep our number of concurrent connections
47
+ * above minConnections (default: 5000)
39
48
  */
40
- maxEventLoopDelay?: number
49
+ autoDialInterval?: number
41
50
 
42
51
  /**
43
- * Sets the poll interval (in milliseconds) for assessing the current state and determining if this peer needs to force a disconnect. Defaults to `2000` (2 seconds).
52
+ * When dialling peers from the peer book to keep the number of open connections
53
+ * above `minConnections`, add dials for this many peers to the dial queue
54
+ * at once. (default: 25)
44
55
  */
45
- pollInterval?: number
56
+ autoDialConcurrency?: number
46
57
 
47
58
  /**
48
- * How long to wait between attempting to keep our number of concurrent connections
49
- * above minConnections
59
+ * To allow user dials to take priority over auto dials, use this value as the
60
+ * dial priority. (default: 0)
50
61
  */
51
- autoDialInterval: number
62
+ autoDialPriority?: number
52
63
 
53
64
  /**
54
- * Sort the known addresses of a peer before trying to dial
65
+ * Sort the known addresses of a peer before trying to dial, By default public
66
+ * addresses will be dialled before private (e.g. loopback or LAN) addresses.
55
67
  */
56
68
  addressSorter?: AddressSorter
57
69
 
58
70
  /**
59
- * Number of max concurrent dials
71
+ * The maximum number of dials across all peers to execute in parallel.
72
+ * (default: 100)
60
73
  */
61
74
  maxParallelDials?: number
62
75
 
63
76
  /**
64
- * Number of max addresses to dial for a given peer
77
+ * To prevent individual peers with large amounts of multiaddrs swamping the
78
+ * dial queue, this value controls how many addresses to dial in parallel per
79
+ * peer. So for example if two peers have 10 addresses and this value is set
80
+ * at 5, we will dial 5 addresses from each at a time. (default: 10)
65
81
  */
66
- maxAddrsToDial?: number
82
+ maxParallelDialsPerPeer?: number
83
+
84
+ /**
85
+ * Maximum number of addresses allowed for a given peer - if a peer has more
86
+ * addresses than this then the dial will fail. (default: 25)
87
+ */
88
+ maxPeerAddrsToDial?: number
67
89
 
68
90
  /**
69
91
  * How long a dial attempt is allowed to take, including DNS resolution
@@ -73,26 +95,15 @@ export interface ConnectionManagerConfig {
73
95
 
74
96
  /**
75
97
  * When a new inbound connection is opened, the upgrade process (e.g. protect,
76
- * encrypt, multiplex etc) must complete within this number of ms.
98
+ * encrypt, multiplex etc) must complete within this number of ms. (default: 30s)
77
99
  */
78
- inboundUpgradeTimeout: number
100
+ inboundUpgradeTimeout?: number
79
101
 
80
102
  /**
81
- * Number of max concurrent dials per peer
82
- */
83
- maxDialsPerPeer?: number
84
-
85
- /**
86
- * Multiaddr resolvers to use when dialing
103
+ * Multiaddr resolvers to use when dialling
87
104
  */
88
105
  resolvers?: Record<string, Resolver>
89
106
 
90
- /**
91
- * On startup we try to dial any peer that has previously been
92
- * tagged with KEEP_ALIVE up to this timeout in ms. (default: 60000)
93
- */
94
- startupReconnectTimeout?: number
95
-
96
107
  /**
97
108
  * A list of multiaddrs that will always be allowed (except if they are in the
98
109
  * deny list) to open connections to this node even if we've reached maxConnections
@@ -107,103 +118,133 @@ export interface ConnectionManagerConfig {
107
118
 
108
119
  /**
109
120
  * If more than this many connections are opened per second by a single
110
- * host, reject subsequent connections
121
+ * host, reject subsequent connections. (default: 5)
111
122
  */
112
123
  inboundConnectionThreshold?: number
113
124
 
114
125
  /**
115
126
  * The maximum number of parallel incoming connections allowed that have yet to
116
- * complete the connection upgrade - e.g. choosing connection encryption, muxer, etc
127
+ * complete the connection upgrade - e.g. choosing connection encryption, muxer, etc.
128
+ * (default: 10)
117
129
  */
118
130
  maxIncomingPendingConnections?: number
119
131
  }
120
132
 
121
- const defaultOptions: Partial<ConnectionManagerConfig> = {
122
- maxConnections: Infinity,
123
- minConnections: 0,
124
- maxEventLoopDelay: Infinity,
125
- pollInterval: 2000,
126
- autoDialInterval: 10000,
127
- inboundConnectionThreshold: 5,
128
- maxIncomingPendingConnections: 10
133
+ const defaultOptions = {
134
+ minConnections: MIN_CONNECTIONS,
135
+ maxConnections: MAX_CONNECTIONS,
136
+ inboundConnectionThreshold: INBOUND_CONNECTION_THRESHOLD,
137
+ maxIncomingPendingConnections: MAX_INCOMING_PENDING_CONNECTIONS,
138
+ autoDialConcurrency: AUTO_DIAL_CONCURRENCY,
139
+ autoDialPriority: AUTO_DIAL_PRIORITY
129
140
  }
130
141
 
131
- const STARTUP_RECONNECT_TIMEOUT = 60000
132
-
133
142
  export interface DefaultConnectionManagerComponents {
134
143
  peerId: PeerId
135
144
  metrics?: Metrics
136
- upgrader: Upgrader
137
145
  peerStore: PeerStore
138
- dialer: Dialer
146
+ transportManager: TransportManager
147
+ connectionGater: ConnectionGater
148
+ events: EventEmitter<Libp2pEvents>
139
149
  }
140
150
 
141
- export type ConnectionManagerInit = ConnectionManagerConfig
151
+ export interface OpenConnectionOptions extends AbortOptions {
152
+ priority?: number
153
+ }
142
154
 
143
155
  /**
144
156
  * Responsible for managing known connections.
145
157
  */
146
- export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Startable {
147
- private readonly components: DefaultConnectionManagerComponents
148
- private readonly opts: ConnectionManagerInit
149
- private readonly connections: Map<string, Connection[]>
158
+ export class DefaultConnectionManager implements ConnectionManager, Startable {
150
159
  private started: boolean
151
- private readonly latencyMonitor?: LatencyMonitor
152
- private readonly startupReconnectTimeout: number
153
- private connectOnStartupController?: TimeoutController
154
- private readonly dialTimeout: number
160
+ private readonly connections: PeerMap<Connection[]>
155
161
  private readonly allow: Multiaddr[]
156
162
  private readonly deny: Multiaddr[]
157
- private readonly inboundConnectionRateLimiter: RateLimiterMemory
163
+ private readonly maxIncomingPendingConnections: number
158
164
  private incomingPendingConnections: number
165
+ private readonly maxConnections: number
159
166
 
160
- constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerConfig) {
161
- super()
167
+ public readonly dialQueue: DialQueue
168
+ public readonly autoDial: AutoDial
169
+ public readonly connectionPruner: ConnectionPruner
170
+ private readonly inboundConnectionRateLimiter: RateLimiterMemory
171
+
172
+ private readonly peerStore: PeerStore
173
+ private readonly metrics?: Metrics
174
+ private readonly events: EventEmitter<Libp2pEvents>
162
175
 
163
- this.opts = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, init)
176
+ constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerInit = {}) {
177
+ this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
178
+ const minConnections = init.minConnections ?? defaultOptions.minConnections
164
179
 
165
- if (this.opts.maxConnections < this.opts.minConnections) {
180
+ if (this.maxConnections < minConnections) {
166
181
  throw new CodeError('Connection Manager maxConnections must be greater than minConnections', codes.ERR_INVALID_PARAMETERS)
167
182
  }
168
183
 
169
- log('options: %o', this.opts)
170
-
171
- this.components = components
172
-
173
184
  /**
174
185
  * Map of connections per peer
175
186
  */
176
- this.connections = new Map()
187
+ this.connections = new PeerMap()
177
188
 
178
189
  this.started = false
179
-
180
- if (init.maxEventLoopDelay != null && init.maxEventLoopDelay > 0 && init.maxEventLoopDelay !== Infinity) {
181
- this.latencyMonitor = new LatencyMonitor({
182
- latencyCheckIntervalMs: init.pollInterval,
183
- dataEmitIntervalMs: init.pollInterval
184
- })
185
- }
186
-
187
- try {
188
- // This emitter gets listened to a lot
189
- setMaxListeners?.(Infinity, this)
190
- } catch {}
190
+ this.peerStore = components.peerStore
191
+ this.metrics = components.metrics
192
+ this.events = components.events
191
193
 
192
194
  this.onConnect = this.onConnect.bind(this)
193
195
  this.onDisconnect = this.onDisconnect.bind(this)
196
+ this.events.addEventListener('connection:open', this.onConnect)
197
+ this.events.addEventListener('connection:close', this.onDisconnect)
194
198
 
195
- this.startupReconnectTimeout = init.startupReconnectTimeout ?? STARTUP_RECONNECT_TIMEOUT
196
- this.dialTimeout = init.dialTimeout ?? 30000
197
-
199
+ // allow/deny lists
198
200
  this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
199
201
  this.deny = (init.deny ?? []).map(ma => multiaddr(ma))
200
202
 
203
+ this.incomingPendingConnections = 0
204
+ this.maxIncomingPendingConnections = init.maxIncomingPendingConnections ?? defaultOptions.maxIncomingPendingConnections
205
+
206
+ // controls individual peers trying to dial us too quickly
201
207
  this.inboundConnectionRateLimiter = new RateLimiterMemory({
202
- points: this.opts.inboundConnectionThreshold,
208
+ points: init.inboundConnectionThreshold ?? defaultOptions.inboundConnectionThreshold,
203
209
  duration: 1
204
210
  })
205
211
 
206
- this.incomingPendingConnections = 0
212
+ // controls what happens when we don't have enough connections
213
+ this.autoDial = new AutoDial({
214
+ connectionManager: this,
215
+ peerStore: components.peerStore,
216
+ events: components.events
217
+ }, {
218
+ minConnections,
219
+ autoDialConcurrency: init.autoDialConcurrency ?? defaultOptions.autoDialConcurrency,
220
+ autoDialPriority: init.autoDialPriority ?? defaultOptions.autoDialPriority
221
+ })
222
+
223
+ // controls what happens when we have too many connections
224
+ this.connectionPruner = new ConnectionPruner({
225
+ connectionManager: this,
226
+ peerStore: components.peerStore,
227
+ events: components.events
228
+ }, {
229
+ maxConnections: this.maxConnections,
230
+ allow: this.allow
231
+ })
232
+
233
+ this.dialQueue = new DialQueue({
234
+ peerId: components.peerId,
235
+ metrics: components.metrics,
236
+ peerStore: components.peerStore,
237
+ transportManager: components.transportManager,
238
+ connectionGater: components.connectionGater
239
+ }, {
240
+ addressSorter: init.addressSorter ?? publicAddressesFirst,
241
+ maxParallelDials: init.maxParallelDials ?? MAX_PARALLEL_DIALS,
242
+ maxPeerAddrsToDial: init.maxPeerAddrsToDial ?? MAX_PEER_ADDRS_TO_DIAL,
243
+ dialTimeout: init.dialTimeout ?? DIAL_TIMEOUT,
244
+ resolvers: init.resolvers ?? {
245
+ dnsaddr: dnsaddrResolver
246
+ }
247
+ })
207
248
  }
208
249
 
209
250
  isStarted (): boolean {
@@ -216,7 +257,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
216
257
  */
217
258
  async start (): Promise<void> {
218
259
  // track inbound/outbound connections
219
- this.components.metrics?.registerMetricGroup('libp2p_connection_manager_connections', {
260
+ this.metrics?.registerMetricGroup('libp2p_connection_manager_connections', {
220
261
  calculate: () => {
221
262
  const metric = {
222
263
  inbound: 0,
@@ -238,7 +279,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
238
279
  })
239
280
 
240
281
  // track total number of streams per protocol
241
- this.components.metrics?.registerMetricGroup('libp2p_protocol_streams_total', {
282
+ this.metrics?.registerMetricGroup('libp2p_protocol_streams_total', {
242
283
  label: 'protocol',
243
284
  calculate: () => {
244
285
  const metric: Record<string, number> = {}
@@ -258,7 +299,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
258
299
  })
259
300
 
260
301
  // track 90th percentile of streams per protocol
261
- this.components.metrics?.registerMetricGroup('libp2p_connection_manager_protocol_streams_per_connection_90th_percentile', {
302
+ this.metrics?.registerMetricGroup('libp2p_connection_manager_protocol_streams_per_connection_90th_percentile', {
262
303
  label: 'protocol',
263
304
  calculate: () => {
264
305
  const allStreams: Record<string, number[]> = {}
@@ -293,46 +334,27 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
293
334
  }
294
335
  })
295
336
 
296
- // latency monitor
297
- this.latencyMonitor?.start()
298
- this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
299
- this.latencyMonitor?.addEventListener('data', this._onLatencyMeasure)
337
+ this.autoDial.start()
300
338
 
301
339
  this.started = true
302
340
  log('started')
303
341
  }
304
342
 
305
343
  async afterStart (): Promise<void> {
306
- this.components.upgrader.addEventListener('connection', this.onConnect)
307
- this.components.upgrader.addEventListener('connectionEnd', this.onDisconnect)
308
-
309
344
  // re-connect to any peers with the KEEP_ALIVE tag
310
345
  void Promise.resolve()
311
346
  .then(async () => {
312
347
  const keepAlivePeers: PeerId[] = []
313
348
 
314
- for (const peer of await this.components.peerStore.all()) {
315
- const tags = await this.components.peerStore.getTags(peer.id)
316
- const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
317
-
318
- if (hasKeepAlive) {
349
+ for (const peer of await this.peerStore.all()) {
350
+ if (peer.tags.has(KEEP_ALIVE)) {
319
351
  keepAlivePeers.push(peer.id)
320
352
  }
321
353
  }
322
354
 
323
- this.connectOnStartupController?.clear()
324
- this.connectOnStartupController = new TimeoutController(this.startupReconnectTimeout)
325
-
326
- try {
327
- // fails on node < 15.4
328
- setMaxListeners?.(Infinity, this.connectOnStartupController.signal)
329
- } catch {}
330
-
331
355
  await Promise.all(
332
356
  keepAlivePeers.map(async peer => {
333
- await this.openConnection(peer, {
334
- signal: this.connectOnStartupController?.signal
335
- })
357
+ await this.openConnection(peer)
336
358
  .catch(err => {
337
359
  log.error(err)
338
360
  })
@@ -342,34 +364,17 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
342
364
  .catch(err => {
343
365
  log.error(err)
344
366
  })
345
- .finally(() => {
346
- this.connectOnStartupController?.clear()
347
- })
348
- }
349
367
 
350
- async beforeStop (): Promise<void> {
351
- // if we are still dialing KEEP_ALIVE peers, abort those dials
352
- this.connectOnStartupController?.abort()
353
- this.components.upgrader.removeEventListener('connection', this.onConnect)
354
- this.components.upgrader.removeEventListener('connectionEnd', this.onDisconnect)
368
+ this.autoDial.afterStart()
355
369
  }
356
370
 
357
371
  /**
358
372
  * Stops the Connection Manager
359
373
  */
360
374
  async stop (): Promise<void> {
361
- this.latencyMonitor?.removeEventListener('data', this._onLatencyMeasure)
362
- this.latencyMonitor?.stop()
375
+ this.dialQueue.stop()
376
+ this.autoDial.stop()
363
377
 
364
- this.started = false
365
- await this._close()
366
- log('stopped')
367
- }
368
-
369
- /**
370
- * Cleans up the connections
371
- */
372
- async _close (): Promise<void> {
373
378
  // Close all connections we're tracking
374
379
  const tasks: Array<Promise<void>> = []
375
380
  for (const connectionList of this.connections.values()) {
@@ -387,6 +392,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
387
392
  log('closing %d connections', tasks.length)
388
393
  await Promise.all(tasks)
389
394
  this.connections.clear()
395
+
396
+ log('stopped')
390
397
  }
391
398
 
392
399
  onConnect (evt: CustomEvent<Connection>): void {
@@ -408,24 +415,26 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
408
415
  }
409
416
 
410
417
  const peerId = connection.remotePeer
411
- const peerIdStr = peerId.toString()
412
- const storedConns = this.connections.get(peerIdStr)
418
+ const storedConns = this.connections.get(peerId)
419
+ let isNewPeer = false
413
420
 
414
421
  if (storedConns != null) {
415
422
  storedConns.push(connection)
416
423
  } else {
417
- this.connections.set(peerIdStr, [connection])
424
+ isNewPeer = true
425
+ this.connections.set(peerId, [connection])
418
426
  }
419
427
 
420
- if (peerId.publicKey != null) {
421
- await this.components.peerStore.keyBook.set(peerId, peerId.publicKey)
428
+ // only need to store RSA public keys, all other types are embedded in the peer id
429
+ if (peerId.publicKey != null && peerId.type === 'RSA') {
430
+ await this.peerStore.patch(peerId, {
431
+ publicKey: peerId.publicKey
432
+ })
422
433
  }
423
434
 
424
- const numConnections = this.getConnections().length
425
- const toPrune = numConnections - this.opts.maxConnections
426
-
427
- await this._checkMaxLimit('maxConnections', numConnections, toPrune)
428
- this.dispatchEvent(new CustomEvent<Connection>('peer:connect', { detail: connection }))
435
+ if (isNewPeer) {
436
+ this.events.safeDispatchEvent('peer:connect', { detail: connection.remotePeer })
437
+ }
429
438
  }
430
439
 
431
440
  /**
@@ -439,7 +448,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
439
448
  return
440
449
  }
441
450
 
442
- const peerId = connection.remotePeer.toString()
451
+ const peerId = connection.remotePeer
443
452
  let storedConn = this.connections.get(peerId)
444
453
 
445
454
  if (storedConn != null && storedConn.length > 1) {
@@ -447,13 +456,13 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
447
456
  this.connections.set(peerId, storedConn)
448
457
  } else if (storedConn != null) {
449
458
  this.connections.delete(peerId)
450
- this.dispatchEvent(new CustomEvent<Connection>('peer:disconnect', { detail: connection }))
459
+ this.events.safeDispatchEvent('peer:disconnect', { detail: connection.remotePeer })
451
460
  }
452
461
  }
453
462
 
454
463
  getConnections (peerId?: PeerId): Connection[] {
455
464
  if (peerId != null) {
456
- return this.connections.get(peerId.toString()) ?? []
465
+ return this.connections.get(peerId) ?? []
457
466
  }
458
467
 
459
468
  let conns: Connection[] = []
@@ -465,19 +474,15 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
465
474
  return conns
466
475
  }
467
476
 
468
- getConnectionsMap (): Map<string, Connection[]> {
477
+ getConnectionsMap (): PeerMap<Connection[]> {
469
478
  return this.connections
470
479
  }
471
480
 
472
- async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: AbortOptions = {}): Promise<Connection> {
473
- const { peerId, multiaddrs } = getPeerAddress(peerIdOrMultiaddr)
474
-
475
- if (peerId == null && multiaddrs.length === 0) {
476
- throw new CodeError('Can only open connections to PeerIds or Multiaddrs', codes.ERR_INVALID_PARAMETERS)
477
- }
481
+ async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise<Connection> {
482
+ const { peerId } = getPeerAddress(peerIdOrMultiaddr)
478
483
 
479
484
  if (peerId != null) {
480
- log('dial to', peerId)
485
+ log('dial %p', peerId)
481
486
  const existingConnections = this.getConnections(peerId)
482
487
 
483
488
  if (existingConnections.length > 0) {
@@ -487,53 +492,37 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
487
492
  }
488
493
  }
489
494
 
490
- let timeoutController: TimeoutController | undefined
491
-
492
- if (options?.signal == null) {
493
- timeoutController = new TimeoutController(this.dialTimeout)
494
- options.signal = timeoutController.signal
495
+ const connection = await this.dialQueue.dial(peerIdOrMultiaddr, {
496
+ ...options,
497
+ priority: options.priority ?? DEFAULT_DIAL_PRIORITY
498
+ })
499
+ let peerConnections = this.connections.get(connection.remotePeer)
495
500
 
496
- try {
497
- // fails on node < 15.4
498
- setMaxListeners?.(Infinity, timeoutController.signal)
499
- } catch {}
501
+ if (peerConnections == null) {
502
+ peerConnections = []
503
+ this.connections.set(connection.remotePeer, peerConnections)
500
504
  }
501
505
 
502
- try {
503
- // @ts-expect-error until https://github.com/libp2p/js-libp2p-interfaces/pull/351 is merged
504
- const connection = await this.components.dialer.dial(peerIdOrMultiaddr, options)
505
- let peerConnections = this.connections.get(connection.remotePeer.toString())
506
-
507
- if (peerConnections == null) {
508
- peerConnections = []
509
- this.connections.set(connection.remotePeer.toString(), peerConnections)
510
- }
511
-
512
- // we get notified of connections via the Upgrader emitting "connection"
513
- // events, double check we aren't already tracking this connection before
514
- // storing it
515
- let trackedConnection = false
516
-
517
- for (const conn of peerConnections) {
518
- if (conn.id === connection.id) {
519
- trackedConnection = true
520
- }
521
- }
506
+ // we get notified of connections via the Upgrader emitting "connection"
507
+ // events, double check we aren't already tracking this connection before
508
+ // storing it
509
+ let trackedConnection = false
522
510
 
523
- if (!trackedConnection) {
524
- peerConnections.push(connection)
511
+ for (const conn of peerConnections) {
512
+ if (conn.id === connection.id) {
513
+ trackedConnection = true
525
514
  }
515
+ }
526
516
 
527
- return connection
528
- } finally {
529
- if (timeoutController != null) {
530
- timeoutController.clear()
531
- }
517
+ if (!trackedConnection) {
518
+ peerConnections.push(connection)
532
519
  }
520
+
521
+ return connection
533
522
  }
534
523
 
535
524
  async closeConnections (peerId: PeerId): Promise<void> {
536
- const connections = this.connections.get(peerId.toString()) ?? []
525
+ const connections = this.connections.get(peerId) ?? []
537
526
 
538
527
  await Promise.all(
539
528
  connections.map(async connection => {
@@ -542,148 +531,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
542
531
  )
543
532
  }
544
533
 
545
- /**
546
- * Get all open connections with a peer
547
- */
548
- getAll (peerId: PeerId): Connection[] {
549
- if (!isPeerId(peerId)) {
550
- throw new CodeError('peerId must be an instance of peer-id', codes.ERR_INVALID_PARAMETERS)
551
- }
552
-
553
- const id = peerId.toString()
554
- const connections = this.connections.get(id)
555
-
556
- // Return all open connections
557
- if (connections != null) {
558
- return connections.filter(connection => connection.stat.status === STATUS.OPEN)
559
- }
560
-
561
- return []
562
- }
563
-
564
- /**
565
- * If the event loop is slow, maybe close a connection
566
- */
567
- _onLatencyMeasure (evt: CustomEvent<SummaryObject>): void {
568
- const { detail: summary } = evt
569
-
570
- this._checkMaxLimit('maxEventLoopDelay', summary.avgMs, 1)
571
- .catch(err => {
572
- log.error(err)
573
- })
574
- }
575
-
576
- /**
577
- * If the `value` of `name` has exceeded its limit, maybe close a connection
578
- */
579
- async _checkMaxLimit (name: keyof ConnectionManagerInit, value: number, toPrune: number = 1): Promise<void> {
580
- const limit = this.opts[name]
581
-
582
- if (limit == null) {
583
- log.trace('limit %s was not set so it cannot be applied', name)
584
- return
585
- }
586
- if (limit === Infinity) {
587
- log.trace('limit %s is Infinity so it cannot be applied', name)
588
- return
589
- }
590
-
591
- log.trace('checking limit of %s. current value: %d of %d', name, value, limit)
592
- if (value > limit) {
593
- log('%s: limit exceeded: %p, %d/%d, pruning %d connection(s)', this.components.peerId, name, value, limit, toPrune)
594
- await this._pruneConnections(toPrune)
595
- }
596
- }
597
-
598
- /**
599
- * If we have more connections than our maximum, select some excess connections
600
- * to prune based on peer value
601
- */
602
- async _pruneConnections (toPrune: number): Promise<void> {
603
- const connections = this.getConnections()
604
- const peerValues = new PeerMap<number>()
605
-
606
- // work out peer values
607
- for (const connection of connections) {
608
- const remotePeer = connection.remotePeer
609
-
610
- if (peerValues.has(remotePeer)) {
611
- continue
612
- }
613
-
614
- const tags = await this.components.peerStore.getTags(remotePeer)
615
-
616
- // sum all tag values
617
- peerValues.set(remotePeer, tags.reduce((acc, curr) => {
618
- return acc + curr.value
619
- }, 0))
620
- }
621
-
622
- // sort by value, lowest to highest
623
- const sortedConnections = connections.sort((a, b) => {
624
- const peerAValue = peerValues.get(a.remotePeer) ?? 0
625
- const peerBValue = peerValues.get(b.remotePeer) ?? 0
626
-
627
- if (peerAValue > peerBValue) {
628
- return 1
629
- }
630
-
631
- if (peerAValue < peerBValue) {
632
- return -1
633
- }
634
-
635
- // if the peers have an equal tag value then we want to close short-lived connections first
636
- const connectionALifespan = a.stat.timeline.open
637
- const connectionBLifespan = b.stat.timeline.open
638
-
639
- if (connectionALifespan < connectionBLifespan) {
640
- return 1
641
- }
642
-
643
- if (connectionALifespan > connectionBLifespan) {
644
- return -1
645
- }
646
-
647
- return 0
648
- })
649
-
650
- // close some connections
651
- const toClose = []
652
-
653
- for (const connection of sortedConnections) {
654
- log('too many connections open - closing a connection to %p', connection.remotePeer)
655
- // check allow list
656
- const connectionInAllowList = this.allow.some((ma) => {
657
- return connection.remoteAddr.toString().startsWith(ma.toString())
658
- })
659
-
660
- // Connections in the allow list should be excluded from pruning
661
- if (!connectionInAllowList) {
662
- toClose.push(connection)
663
- }
664
-
665
- if (toClose.length === toPrune) {
666
- break
667
- }
668
- }
669
-
670
- // close connections
671
- await Promise.all(
672
- toClose.map(async connection => {
673
- try {
674
- await connection.close()
675
- } catch (err) {
676
- log.error(err)
677
- }
678
-
679
- // TODO: should not need to invoke this manually
680
- this.onDisconnect(new CustomEvent<Connection>('connectionEnd', {
681
- detail: connection
682
- }))
683
- })
684
- )
685
- }
686
-
687
534
  async acceptIncomingConnection (maConn: MultiaddrConnection): Promise<boolean> {
688
535
  // check deny list
689
536
  const denyConnection = this.deny.some(ma => {
@@ -707,7 +554,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
707
554
  }
708
555
 
709
556
  // check pending connections
710
- if (this.incomingPendingConnections === this.opts.maxIncomingPendingConnections) {
557
+ if (this.incomingPendingConnections === this.maxIncomingPendingConnections) {
711
558
  log('connection from %s refused - incomingPendingConnections exceeded by peer %s', maConn.remoteAddr)
712
559
  return false
713
560
  }
@@ -723,7 +570,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
723
570
  }
724
571
  }
725
572
 
726
- if (this.getConnections().length < this.opts.maxConnections) {
573
+ if (this.getConnections().length < this.maxConnections) {
727
574
  this.incomingPendingConnections++
728
575
 
729
576
  return true
@@ -736,4 +583,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
736
583
  afterUpgradeInbound (): void {
737
584
  this.incomingPendingConnections--
738
585
  }
586
+
587
+ getDialQueue (): PendingDial[] {
588
+ return this.dialQueue.pendingDials
589
+ }
739
590
  }