{core,swarm}/: Don't require Transport: Clone and take &mut (#2529)

Previously `libp2p-swarm` required a `Transport` to be `Clone`. Methods
on `Transport`, e.g. `Transport::dial` would take ownership, requiring
e.g. a `Clone::clone` before calling `Transport::dial`.

The requirement of `Transport` to be `Clone` is no longer needed in
`libp2p-swarm`. E.g.  concurrent dialing can be done without a clone per
dial.

This commit removes the requirement of `Clone` for `Transport` in
`libp2p-swarm`. As a follow-up methods on `Transport` no longer take
ownership, but instead a mutable reference (`&mut self`).

On the one hand this simplifies `libp2p-swarm`, on the other it
simplifies implementations of `Transport`.
This commit is contained in:
Max Inden
2022-04-06 20:23:16 +02:00
committed by GitHub
parent 7a1147877a
commit 2ad905f35a
82 changed files with 751 additions and 449 deletions

View File

@ -91,7 +91,7 @@ use libp2p_core::{
muxing::StreamMuxerBox,
transport::{self, TransportError},
upgrade::ProtocolName,
Executor, Multiaddr, Negotiated, PeerId, Transport,
Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport,
};
use registry::{AddressIntoIter, Addresses};
use smallvec::SmallVec;
@ -502,9 +502,33 @@ where
}
};
let dials = addresses
.map(|a| match p2p_addr(peer_id, a) {
Ok(address) => {
let dial = match role_override {
Endpoint::Dialer => self.listeners.transport_mut().dial(address.clone()),
Endpoint::Listener => self
.listeners
.transport_mut()
.dial_as_listener(address.clone()),
};
match dial {
Ok(fut) => fut
.map(|r| (address, r.map_err(|e| TransportError::Other(e))))
.boxed(),
Err(err) => futures::future::ready((address, Err(err))).boxed(),
}
}
Err(address) => futures::future::ready((
address.clone(),
Err(TransportError::MultiaddrNotSupported(address)),
))
.boxed(),
})
.collect();
match self.pool.add_outgoing(
self.listeners.transport().clone(),
addresses,
dials,
peer_id,
handler,
role_override,
@ -1527,6 +1551,32 @@ impl NetworkInfo {
}
}
/// Ensures a given `Multiaddr` is a `/p2p/...` address for the given peer.
///
/// If the given address is already a `p2p` address for the given peer,
/// i.e. the last encapsulated protocol is `/p2p/<peer-id>`, this is a no-op.
///
/// If the given address is already a `p2p` address for a different peer
/// than the one given, the given `Multiaddr` is returned as an `Err`.
///
/// If the given address is not yet a `p2p` address for the given peer,
/// the `/p2p/<peer-id>` protocol is appended to the returned address.
fn p2p_addr(peer: Option<PeerId>, addr: Multiaddr) -> Result<Multiaddr, Multiaddr> {
let peer = match peer {
Some(p) => p,
None => return Ok(addr),
};
if let Some(Protocol::P2p(hash)) = addr.iter().last() {
if &hash != peer.as_ref() {
return Err(addr);
}
Ok(addr)
} else {
Ok(addr.with(Protocol::P2p(peer.into())))
}
}
#[cfg(test)]
mod tests {
use super::*;