mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-26 16:21:39 +00:00
swarm/: Enable advanced dialing requests (#2317)
Enable advanced dialing requests both on `Swarm` and via `NetworkBehaviourAction`. Users can now trigger a dial with a specific set of addresses, optionally extended via `NetworkBehaviour::addresses_of_peer`. In addition the whole process is now modelled in a type safe way via the builder pattern. Example of a `NetworkBehaviour` requesting a dial to a specific peer with a set of addresses additionally extended through `NetworkBehaviour::addresses_of_peer`: ```rust NetworkBehaviourAction::Dial { opts: DialOpts::peer_id(peer_id) .condition(PeerCondition::Always) .addresses(addresses) .extend_addresses_through_behaviour() .build(), handler, } ``` Example of a user requesting a dial to an unknown peer with a single address via `Swarm`: ```rust swarm1.dial( DialOpts::unknown_peer_id() .address(addr2.clone()) .build() ) ```
This commit is contained in:
217
swarm/src/dial_opts.rs
Normal file
217
swarm/src/dial_opts.rs
Normal file
@ -0,0 +1,217 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2021 Protocol Labs.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use libp2p_core::{Multiaddr, PeerId};
|
||||
|
||||
/// Options to configure a dial to a known or unknown peer.
|
||||
///
|
||||
/// Used in [`Swarm::dial`](crate::Swarm::dial) and
|
||||
/// [`NetworkBehaviourAction::Dial`](crate::behaviour::NetworkBehaviourAction::Dial).
|
||||
///
|
||||
/// To construct use either of:
|
||||
///
|
||||
/// - [`DialOpts::peer_id`] dialing a known peer
|
||||
///
|
||||
/// - [`DialOpts::unknown_peer_id`] dialing an unknown peer
|
||||
#[derive(Debug)]
|
||||
pub struct DialOpts(pub(super) Opts);
|
||||
|
||||
impl DialOpts {
|
||||
/// Dial a known peer.
|
||||
///
|
||||
/// ```
|
||||
/// # use libp2p_swarm::dial_opts::{DialOpts, PeerCondition};
|
||||
/// # use libp2p_core::PeerId;
|
||||
/// DialOpts::peer_id(PeerId::random())
|
||||
/// .condition(PeerCondition::Disconnected)
|
||||
/// .addresses(vec!["/ip6/::1/tcp/12345".parse().unwrap()])
|
||||
/// .extend_addresses_through_behaviour()
|
||||
/// .build();
|
||||
/// ```
|
||||
pub fn peer_id(peer_id: PeerId) -> WithPeerId {
|
||||
WithPeerId {
|
||||
peer_id,
|
||||
condition: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Dial an unknown peer.
|
||||
///
|
||||
/// ```
|
||||
/// # use libp2p_swarm::dial_opts::DialOpts;
|
||||
/// DialOpts::unknown_peer_id()
|
||||
/// .address("/ip6/::1/tcp/12345".parse().unwrap())
|
||||
/// .build();
|
||||
/// ```
|
||||
pub fn unknown_peer_id() -> WithoutPeerId {
|
||||
WithoutPeerId {}
|
||||
}
|
||||
|
||||
/// Get the [`PeerId`] specified in a [`DialOpts`] if any.
|
||||
pub fn get_peer_id(&self) -> Option<PeerId> {
|
||||
match self {
|
||||
DialOpts(Opts::WithPeerId(WithPeerId { peer_id, .. })) => Some(*peer_id),
|
||||
DialOpts(Opts::WithPeerIdWithAddresses(WithPeerIdWithAddresses {
|
||||
peer_id, ..
|
||||
})) => Some(*peer_id),
|
||||
DialOpts(Opts::WithoutPeerIdWithAddress(_)) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Multiaddr> for DialOpts {
|
||||
fn from(address: Multiaddr) -> Self {
|
||||
DialOpts::unknown_peer_id().address(address).build()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PeerId> for DialOpts {
|
||||
fn from(peer_id: PeerId) -> Self {
|
||||
DialOpts::peer_id(peer_id).build()
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal options type.
|
||||
///
|
||||
/// Not to be constructed manually. Use either of the below instead:
|
||||
///
|
||||
/// - [`DialOpts::peer_id`] dialing a known peer
|
||||
/// - [`DialOpts::unknown_peer_id`] dialing an unknown peer
|
||||
#[derive(Debug)]
|
||||
pub(super) enum Opts {
|
||||
WithPeerId(WithPeerId),
|
||||
WithPeerIdWithAddresses(WithPeerIdWithAddresses),
|
||||
WithoutPeerIdWithAddress(WithoutPeerIdWithAddress),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithPeerId {
|
||||
pub(crate) peer_id: PeerId,
|
||||
pub(crate) condition: PeerCondition,
|
||||
}
|
||||
|
||||
impl WithPeerId {
|
||||
/// Specify a [`PeerCondition`] for the dial.
|
||||
pub fn condition(mut self, condition: PeerCondition) -> Self {
|
||||
self.condition = condition;
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify a set of addresses to be used to dial the known peer.
|
||||
pub fn addresses(self, addresses: Vec<Multiaddr>) -> WithPeerIdWithAddresses {
|
||||
WithPeerIdWithAddresses {
|
||||
peer_id: self.peer_id,
|
||||
condition: self.condition,
|
||||
addresses,
|
||||
extend_addresses_through_behaviour: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the final [`DialOpts`].
|
||||
///
|
||||
/// Addresses to dial the peer are retrieved via
|
||||
/// [`NetworkBehaviour::addresses_of_peer`](crate::behaviour::NetworkBehaviour::addresses_of_peer).
|
||||
pub fn build(self) -> DialOpts {
|
||||
DialOpts(Opts::WithPeerId(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithPeerIdWithAddresses {
|
||||
pub(crate) peer_id: PeerId,
|
||||
pub(crate) condition: PeerCondition,
|
||||
pub(crate) addresses: Vec<Multiaddr>,
|
||||
pub(crate) extend_addresses_through_behaviour: bool,
|
||||
}
|
||||
|
||||
impl WithPeerIdWithAddresses {
|
||||
/// Specify a [`PeerCondition`] for the dial.
|
||||
pub fn condition(mut self, condition: PeerCondition) -> Self {
|
||||
self.condition = condition;
|
||||
self
|
||||
}
|
||||
|
||||
/// In addition to the provided addresses, extend the set via
|
||||
/// [`NetworkBehaviour::addresses_of_peer`](crate::behaviour::NetworkBehaviour::addresses_of_peer).
|
||||
pub fn extend_addresses_through_behaviour(mut self) -> Self {
|
||||
self.extend_addresses_through_behaviour = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final [`DialOpts`].
|
||||
pub fn build(self) -> DialOpts {
|
||||
DialOpts(Opts::WithPeerIdWithAddresses(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithoutPeerId {}
|
||||
|
||||
impl WithoutPeerId {
|
||||
/// Specify a single address to dial the unknown peer.
|
||||
pub fn address(self, address: Multiaddr) -> WithoutPeerIdWithAddress {
|
||||
WithoutPeerIdWithAddress { address }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithoutPeerIdWithAddress {
|
||||
pub(crate) address: Multiaddr,
|
||||
}
|
||||
|
||||
impl WithoutPeerIdWithAddress {
|
||||
/// Build the final [`DialOpts`].
|
||||
pub fn build(self) -> DialOpts {
|
||||
DialOpts(Opts::WithoutPeerIdWithAddress(self))
|
||||
}
|
||||
}
|
||||
|
||||
/// The available conditions under which a new dialing attempt to
|
||||
/// a known peer is initiated.
|
||||
///
|
||||
/// ```
|
||||
/// # use libp2p_swarm::dial_opts::{DialOpts, PeerCondition};
|
||||
/// # use libp2p_core::PeerId;
|
||||
/// #
|
||||
/// DialOpts::peer_id(PeerId::random())
|
||||
/// .condition(PeerCondition::Disconnected)
|
||||
/// .build();
|
||||
/// ```
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PeerCondition {
|
||||
/// A new dialing attempt is initiated _only if_ the peer is currently
|
||||
/// considered disconnected, i.e. there is no established connection
|
||||
/// and no ongoing dialing attempt.
|
||||
Disconnected,
|
||||
/// A new dialing attempt is initiated _only if_ there is currently
|
||||
/// no ongoing dialing attempt, i.e. the peer is either considered
|
||||
/// disconnected or connected but without an ongoing dialing attempt.
|
||||
NotDialing,
|
||||
/// A new dialing attempt is always initiated, only subject to the
|
||||
/// configured connection limits.
|
||||
Always,
|
||||
}
|
||||
|
||||
impl Default for PeerCondition {
|
||||
fn default() -> Self {
|
||||
PeerCondition::Disconnected
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user