@@ -36,13 +36,15 @@ use crate::{
36
36
transport:: { Transport , TransportError } ,
37
37
Executor , Multiaddr , PeerId ,
38
38
} ;
39
+ use either:: Either ;
39
40
use std:: {
40
41
convert:: TryFrom as _,
41
42
error, fmt,
42
43
num:: { NonZeroU8 , NonZeroUsize } ,
43
44
pin:: Pin ,
44
45
task:: { Context , Poll } ,
45
46
} ;
47
+ use thiserror:: Error ;
46
48
47
49
/// Implementation of `Stream` that handles the nodes.
48
50
pub struct Network < TTrans , THandler >
@@ -185,16 +187,15 @@ where
185
187
& self . local_peer_id
186
188
}
187
189
188
- /// Dials a [`Multiaddr`] that may or may not encapsulate a
189
- /// specific expected remote peer ID.
190
+ /// Dial a known or unknown peer.
190
191
///
191
192
/// The given `handler` will be used to create the
192
193
/// [`Connection`](crate::connection::Connection) upon success and the
193
194
/// connection ID is returned.
194
195
pub fn dial (
195
196
& mut self ,
196
- address : & Multiaddr ,
197
197
handler : THandler ,
198
+ opts : impl Into < DialOpts > ,
198
199
) -> Result < ConnectionId , DialError < THandler > >
199
200
where
200
201
TTrans : Transport + Send ,
@@ -203,50 +204,54 @@ where
203
204
TTrans :: Error : Send + ' static ,
204
205
TTrans :: Dial : Send + ' static ,
205
206
{
206
- // If the address ultimately encapsulates an expected peer ID, dial that peer
207
- // such that any mismatch is detected. We do not "pop off" the `P2p` protocol
208
- // from the address, because it may be used by the `Transport`, i.e. `P2p`
209
- // is a protocol component that can influence any transport, like `libp2p-dns`.
210
- if let Some ( multiaddr:: Protocol :: P2p ( ma) ) = address. iter ( ) . last ( ) {
211
- if let Ok ( peer) = PeerId :: try_from ( ma) {
212
- return self . dial_peer ( DialingOpts {
213
- peer,
214
- addresses : std:: iter:: once ( address. clone ( ) ) ,
215
- handler,
216
- } ) ;
207
+ let opts = opts. into ( ) ;
208
+
209
+ let ( peer_id, addresses, dial_concurrency_factor_override) = match opts. 0 {
210
+ // Dial a known peer.
211
+ Opts :: WithPeerIdWithAddresses ( WithPeerIdWithAddresses {
212
+ peer_id,
213
+ addresses,
214
+ dial_concurrency_factor_override,
215
+ } ) => (
216
+ Some ( peer_id) ,
217
+ Either :: Left ( addresses. into_iter ( ) ) ,
218
+ dial_concurrency_factor_override,
219
+ ) ,
220
+ // Dial an unknown peer.
221
+ Opts :: WithoutPeerIdWithAddress ( WithoutPeerIdWithAddress { address } ) => {
222
+ // If the address ultimately encapsulates an expected peer ID, dial that peer
223
+ // such that any mismatch is detected. We do not "pop off" the `P2p` protocol
224
+ // from the address, because it may be used by the `Transport`, i.e. `P2p`
225
+ // is a protocol component that can influence any transport, like `libp2p-dns`.
226
+ let peer_id = match address
227
+ . iter ( )
228
+ . last ( )
229
+ . and_then ( |p| {
230
+ if let multiaddr:: Protocol :: P2p ( ma) = p {
231
+ Some ( PeerId :: try_from ( ma) )
232
+ } else {
233
+ None
234
+ }
235
+ } )
236
+ . transpose ( )
237
+ {
238
+ Ok ( peer_id) => peer_id,
239
+ Err ( _) => return Err ( DialError :: InvalidPeerId { handler } ) ,
240
+ } ;
241
+
242
+ ( peer_id, Either :: Right ( std:: iter:: once ( address) ) , None )
217
243
}
218
- }
244
+ } ;
219
245
220
246
self . pool . add_outgoing (
221
247
self . transport ( ) . clone ( ) ,
222
- std :: iter :: once ( address . clone ( ) ) ,
223
- None ,
248
+ addresses ,
249
+ peer_id ,
224
250
handler,
251
+ dial_concurrency_factor_override,
225
252
)
226
253
}
227
254
228
- /// Initiates a connection attempt to a known peer.
229
- fn dial_peer < I > (
230
- & mut self ,
231
- opts : DialingOpts < THandler , I > ,
232
- ) -> Result < ConnectionId , DialError < THandler > >
233
- where
234
- I : Iterator < Item = Multiaddr > + Send + ' static ,
235
- TTrans : Transport + Send ,
236
- TTrans :: Output : Send + ' static ,
237
- TTrans :: Dial : Send + ' static ,
238
- TTrans :: Error : Send + ' static ,
239
- {
240
- let id = self . pool . add_outgoing (
241
- self . transport ( ) . clone ( ) ,
242
- opts. addresses ,
243
- Some ( opts. peer ) ,
244
- opts. handler ,
245
- ) ?;
246
-
247
- Ok ( id)
248
- }
249
-
250
255
/// Returns information about the state of the `Network`.
251
256
pub fn info ( & self ) -> NetworkInfo {
252
257
let num_peers = self . pool . num_peers ( ) ;
@@ -463,14 +468,6 @@ where
463
468
}
464
469
}
465
470
466
- /// Options for a dialing attempt (i.e. repeated connection attempt
467
- /// via a list of address) to a peer.
468
- struct DialingOpts < THandler , I > {
469
- peer : PeerId ,
470
- handler : THandler ,
471
- addresses : I ,
472
- }
473
-
474
471
/// Information about the network obtained by [`Network::info()`].
475
472
#[ derive( Clone , Debug ) ]
476
473
pub struct NetworkInfo {
@@ -560,31 +557,122 @@ impl NetworkConfig {
560
557
}
561
558
562
559
/// Possible (synchronous) errors when dialing a peer.
563
- #[ derive( Clone ) ]
560
+ #[ derive( Debug , Clone , Error ) ]
564
561
pub enum DialError < THandler > {
565
562
/// The dialing attempt is rejected because of a connection limit.
566
563
ConnectionLimit {
567
564
limit : ConnectionLimit ,
568
565
handler : THandler ,
569
566
} ,
570
567
/// The dialing attempt is rejected because the peer being dialed is the local peer.
571
- LocalPeerId { handler : THandler } ,
568
+ LocalPeerId {
569
+ handler : THandler ,
570
+ } ,
571
+ InvalidPeerId {
572
+ handler : THandler ,
573
+ } ,
572
574
}
573
575
574
- impl < THandler > fmt:: Debug for DialError < THandler > {
575
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> Result < ( ) , fmt:: Error > {
576
- match self {
577
- DialError :: ConnectionLimit { limit, handler : _ } => f
578
- . debug_struct ( "DialError::ConnectionLimit" )
579
- . field ( "limit" , limit)
580
- . finish ( ) ,
581
- DialError :: LocalPeerId { handler : _ } => {
582
- f. debug_struct ( "DialError::LocalPeerId" ) . finish ( )
583
- }
576
+ /// Options to configure a dial to a known or unknown peer.
577
+ ///
578
+ /// Used in [`Network::dial`].
579
+ ///
580
+ /// To construct use either of:
581
+ ///
582
+ /// - [`DialOpts::peer_id`] dialing a known peer
583
+ ///
584
+ /// - [`DialOpts::unknown_peer_id`] dialing an unknown peer
585
+ #[ derive( Debug , Clone , PartialEq ) ]
586
+ pub struct DialOpts ( pub ( super ) Opts ) ;
587
+
588
+ impl DialOpts {
589
+ /// Dial a known peer.
590
+ pub fn peer_id ( peer_id : PeerId ) -> WithPeerId {
591
+ WithPeerId { peer_id }
592
+ }
593
+
594
+ /// Dial an unknown peer.
595
+ pub fn unknown_peer_id ( ) -> WithoutPeerId {
596
+ WithoutPeerId { }
597
+ }
598
+ }
599
+
600
+ impl From < Multiaddr > for DialOpts {
601
+ fn from ( address : Multiaddr ) -> Self {
602
+ DialOpts :: unknown_peer_id ( ) . address ( address) . build ( )
603
+ }
604
+ }
605
+
606
+ /// Internal options type.
607
+ ///
608
+ /// Not to be constructed manually. Use either of the below instead:
609
+ ///
610
+ /// - [`DialOpts::peer_id`] dialing a known peer
611
+ /// - [`DialOpts::unknown_peer_id`] dialing an unknown peer
612
+ #[ derive( Debug , Clone , PartialEq ) ]
613
+ pub ( super ) enum Opts {
614
+ WithPeerIdWithAddresses ( WithPeerIdWithAddresses ) ,
615
+ WithoutPeerIdWithAddress ( WithoutPeerIdWithAddress ) ,
616
+ }
617
+
618
+ #[ derive( Debug , Clone , PartialEq ) ]
619
+ pub struct WithPeerId {
620
+ pub ( crate ) peer_id : PeerId ,
621
+ }
622
+
623
+ impl WithPeerId {
624
+ /// Specify a set of addresses to be used to dial the known peer.
625
+ pub fn addresses ( self , addresses : Vec < Multiaddr > ) -> WithPeerIdWithAddresses {
626
+ WithPeerIdWithAddresses {
627
+ peer_id : self . peer_id ,
628
+ addresses,
629
+ dial_concurrency_factor_override : Default :: default ( ) ,
584
630
}
585
631
}
586
632
}
587
633
634
+ #[ derive( Debug , Clone , PartialEq ) ]
635
+ pub struct WithPeerIdWithAddresses {
636
+ pub ( crate ) peer_id : PeerId ,
637
+ pub ( crate ) addresses : Vec < Multiaddr > ,
638
+ pub ( crate ) dial_concurrency_factor_override : Option < NonZeroU8 > ,
639
+ }
640
+
641
+ impl WithPeerIdWithAddresses {
642
+ /// Override [`NetworkConfig::with_dial_concurrency_factor`].
643
+ pub fn override_dial_concurrency_factor ( mut self , factor : NonZeroU8 ) -> Self {
644
+ self . dial_concurrency_factor_override = Some ( factor) ;
645
+ self
646
+ }
647
+
648
+ /// Build the final [`DialOpts`].
649
+ pub fn build ( self ) -> DialOpts {
650
+ DialOpts ( Opts :: WithPeerIdWithAddresses ( self ) )
651
+ }
652
+ }
653
+
654
+ #[ derive( Debug , Clone , PartialEq ) ]
655
+ pub struct WithoutPeerId { }
656
+
657
+ impl WithoutPeerId {
658
+ /// Specify a single address to dial the unknown peer.
659
+ pub fn address ( self , address : Multiaddr ) -> WithoutPeerIdWithAddress {
660
+ WithoutPeerIdWithAddress { address }
661
+ }
662
+ }
663
+
664
+ #[ derive( Debug , Clone , PartialEq ) ]
665
+ pub struct WithoutPeerIdWithAddress {
666
+ pub ( crate ) address : Multiaddr ,
667
+ }
668
+
669
+ impl WithoutPeerIdWithAddress {
670
+ /// Build the final [`DialOpts`].
671
+ pub fn build ( self ) -> DialOpts {
672
+ DialOpts ( Opts :: WithoutPeerIdWithAddress ( self ) )
673
+ }
674
+ }
675
+
588
676
#[ cfg( test) ]
589
677
mod tests {
590
678
use super :: * ;
0 commit comments