@@ -15,8 +15,8 @@ import {
1515 MAX_PEER_ADDRS_TO_DIAL ,
1616 LAST_DIAL_FAILURE_KEY
1717} from './constants.js'
18- import { combineSignals , resolveMultiaddrs } from './utils.js'
19- import type { AddressSorter , AbortOptions , PendingDial , ComponentLogger , Logger , Connection , ConnectionGater , Metric , Metrics , PeerId , Address , PeerStore } from '@libp2p/interface'
18+ import { resolveMultiaddrs } from './utils.js'
19+ import type { AddressSorter , AbortOptions , ComponentLogger , Logger , Connection , ConnectionGater , Metrics , PeerId , Address , PeerStore , PeerRouting } from '@libp2p/interface'
2020import type { TransportManager } from '@libp2p/interface-internal'
2121
2222export interface PendingDialTarget {
@@ -59,15 +59,11 @@ interface DialQueueComponents {
5959 transportManager : TransportManager
6060 connectionGater : ConnectionGater
6161 logger : ComponentLogger
62+ peerRouting : PeerRouting
6263}
6364
6465export class DialQueue {
65- public pendingDials : PendingDialInternal [ ]
66- public queue : PQueue
67- private readonly peerId : PeerId
68- private readonly peerStore : PeerStore
69- private readonly connectionGater : ConnectionGater
70- private readonly transportManager : TransportManager
66+ public queue : Queue < Connection , DialQueueJobOptions >
7167 private readonly addressSorter : AddressSorter
7268 private readonly maxPeerAddrsToDial : number
7369 private readonly dialTimeout : number
@@ -76,6 +72,7 @@ export class DialQueue {
7672 private shutDownController : AbortController
7773 private readonly connections : PeerMap < Connection [ ] >
7874 private readonly log : Logger
75+ private readonly components : DialQueueComponents
7976
8077 constructor ( components : DialQueueComponents , init : DialerInit = { } ) {
8178 this . addressSorter = init . addressSorter ?? defaultOptions . addressSorter
@@ -84,10 +81,7 @@ export class DialQueue {
8481 this . connections = init . connections ?? new PeerMap ( )
8582 this . log = components . logger . forComponent ( 'libp2p:connection-manager:dial-queue' )
8683
87- this . peerId = components . peerId
88- this . peerStore = components . peerStore
89- this . connectionGater = components . connectionGater
90- this . transportManager = components . transportManager
84+ this . components = components
9185 this . shutDownController = new AbortController ( )
9286
9387 setMaxListeners ( Infinity , this . shutDownController . signal )
@@ -242,6 +236,75 @@ export class DialQueue {
242236 // remove our pending dial entry
243237 this . pendingDials = this . pendingDials . filter ( p => p . id !== pendingDial . id )
244238
239+ try {
240+ // load addresses from address book, resolve and dnsaddrs, filter
241+ // undiallables, add peer IDs, etc
242+ addrsToDial = await this . calculateMultiaddrs ( peerId , options ?. multiaddrs , {
243+ ...options ,
244+ signal
245+ } )
246+
247+ addrsToDial . map ( ( { multiaddr } ) => multiaddr . toString ( ) ) . forEach ( addr => {
248+ options ?. multiaddrs . add ( addr )
249+ } )
250+ } catch ( err ) {
251+ signal . clear ( )
252+ throw err
253+ }
254+
255+ try {
256+ let dialed = 0
257+ const errors : Error [ ] = [ ]
258+
259+ for ( const address of addrsToDial ) {
260+ if ( dialed === this . maxPeerAddrsToDial ) {
261+ this . log ( 'dialed maxPeerAddrsToDial (%d) addresses for %p, not trying any others' , dialed , peerId )
262+
263+ throw new CodeError ( 'Peer had more than maxPeerAddrsToDial' , codes . ERR_TOO_MANY_ADDRESSES )
264+ }
265+
266+ dialed ++
267+
268+ try {
269+ const conn = await this . components . transportManager . dial ( address . multiaddr , {
270+ ...options ,
271+ signal
272+ } )
273+
274+ this . log ( 'dial to %a succeeded' , address . multiaddr )
275+
276+ return conn
277+ } catch ( err : any ) {
278+ this . log . error ( 'dial failed to %a' , address . multiaddr , err )
279+
280+ if ( peerId != null ) {
281+ // record the failed dial
282+ try {
283+ await this . components . peerStore . patch ( peerId , {
284+ metadata : {
285+ [ LAST_DIAL_FAILURE_KEY ] : uint8ArrayFromString ( Date . now ( ) . toString ( ) )
286+ }
287+ } )
288+ } catch ( err : any ) {
289+ this . log . error ( 'could not update last dial failure key for %p' , peerId , err )
290+ }
291+ }
292+
293+ // the user/dial timeout/shutdown controller signal aborted
294+ if ( signal . aborted ) {
295+ throw new CodeError ( err . message , ERR_TIMEOUT )
296+ }
297+
298+ errors . push ( err )
299+ }
300+ }
301+
302+ if ( errors . length === 1 ) {
303+ throw errors [ 0 ]
304+ }
305+
306+ throw new AggregateCodeError ( errors , 'All multiaddr dials failed' , codes . ERR_TRANSPORT_DIAL_FAILED )
307+ } finally {
245308 // clean up abort signals/controllers
246309 signal . clear ( )
247310 } )
@@ -315,19 +378,20 @@ export class DialQueue {
315378 private async calculateMultiaddrs ( peerId ?: PeerId , addrs : Address [ ] = [ ] , options : DialOptions = { } ) : Promise < Address [ ] > {
316379 // 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
317380 if ( peerId != null ) {
318- if ( this . peerId . equals ( peerId ) ) {
381+ if ( this . components . peerId . equals ( peerId ) ) {
319382 throw new CodeError ( 'Tried to dial self' , codes . ERR_DIALED_SELF )
320383 }
321384
322- if ( ( await this . connectionGater . denyDialPeer ?.( peerId ) ) === true ) {
385+ if ( ( await this . components . connectionGater . denyDialPeer ?.( peerId ) ) === true ) {
323386 throw new CodeError ( 'The dial request is blocked by gater.allowDialPeer' , codes . ERR_PEER_DIAL_INTERCEPTED )
324387 }
325388
326- // if just a peer id was passed, load available multiaddrs for this peer from the address book
389+ // if just a peer id was passed, load available multiaddrs for this peer
390+ // from the peer store
327391 if ( addrs . length === 0 ) {
328392 this . log ( 'loading multiaddrs for %p' , peerId )
329393 try {
330- const peer = await this . peerStore . get ( peerId )
394+ const peer = await this . components . peerStore . get ( peerId )
331395 addrs . push ( ...peer . addresses )
332396 this . log ( 'loaded multiaddrs for %p' , peerId , addrs . map ( ( { multiaddr } ) => multiaddr . toString ( ) ) )
333397 } catch ( err : any ) {
@@ -336,9 +400,23 @@ export class DialQueue {
336400 }
337401 }
338402 }
403+
404+ // if the peer store had no addresses for the peer, try to find them via
405+ // peer routing
406+ if ( addrs . length === 0 ) {
407+ const peer = await this . components . peerRouting . findPeer ( peerId , options )
408+
409+ peer . multiaddrs . forEach ( multiaddr => {
410+ addrs . push ( {
411+ multiaddr,
412+ isCertified : false
413+ } )
414+ } )
415+ }
339416 }
340417
341- // resolve addresses - this can result in a one-to-many translation when dnsaddrs are resolved
418+ // resolve addresses - this can result in a one-to-many translation when
419+ // dnsaddrs are resolved
342420 let resolvedAddresses = ( await Promise . all (
343421 addrs . map ( async addr => {
344422 const result = await resolveMultiaddrs ( addr . multiaddr , {
@@ -383,7 +461,7 @@ export class DialQueue {
383461
384462 const filteredAddrs = resolvedAddresses . filter ( addr => {
385463 // filter out any multiaddrs that we do not have transports for
386- if ( this . transportManager . transportForMultiaddr ( addr . multiaddr ) == null ) {
464+ if ( this . components . transportManager . transportForMultiaddr ( addr . multiaddr ) == null ) {
387465 return false
388466 }
389467
@@ -433,7 +511,7 @@ export class DialQueue {
433511 const gatedAdrs : Address [ ] = [ ]
434512
435513 for ( const addr of dedupedMultiaddrs ) {
436- if ( this . connectionGater . denyDialMultiaddr != null && await this . connectionGater . denyDialMultiaddr ( addr . multiaddr ) ) {
514+ if ( this . components . connectionGater . denyDialMultiaddr != null && await this . components . connectionGater . denyDialMultiaddr ( addr . multiaddr ) ) {
437515 continue
438516 }
439517
0 commit comments