feat: allow connecting using /Multiaddr/p2p/PeerId addresses

Signed-off-by: ljedrz <ljedrz@gmail.com>
This commit is contained in:
ljedrz 2020-08-11 16:59:37 +02:00
parent 47322befb7
commit cc12650d17
2 changed files with 69 additions and 3 deletions

View File

@ -1,5 +1,5 @@
use super::support::{with_ipfs, StringError};
use ipfs::{Ipfs, IpfsTypes, Multiaddr};
use ipfs::{p2p::ConnectionTarget, Ipfs, IpfsTypes, Multiaddr};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::BTreeMap;
@ -7,14 +7,18 @@ use warp::{query, Filter};
#[derive(Debug, Deserialize)]
struct ConnectQuery {
arg: Multiaddr,
arg: String,
}
async fn connect_query<T: IpfsTypes>(
ipfs: Ipfs<T>,
query: ConnectQuery,
) -> Result<impl warp::Reply, warp::Rejection> {
ipfs.connect(query.arg)
let target = query
.arg
.parse::<ConnectionTarget>()
.map_err(|e| warp::reject::custom(StringError::from(e)))?;
ipfs.connect(target)
.await
.map_err(|e| warp::reject::custom(StringError::from(e)))?;
let response: &[&str] = &[];

View File

@ -1,4 +1,5 @@
use crate::subscription::{SubscriptionFuture, SubscriptionRegistry};
use anyhow::anyhow;
use core::task::{Context, Poll};
use libp2p::core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId};
use libp2p::swarm::protocols_handler::{
@ -6,6 +7,7 @@ use libp2p::swarm::protocols_handler::{
};
use libp2p::swarm::{self, DialPeerCondition, NetworkBehaviour, PollParameters, Swarm};
use std::collections::{HashMap, HashSet, VecDeque};
use std::str::FromStr;
use std::time::Duration;
/// A description of currently active connection.
@ -23,6 +25,7 @@ pub struct Connection {
pub enum ConnectionTarget {
Addr(Multiaddr),
PeerId(PeerId),
PeerIdWithAddr(PeerId, Multiaddr),
}
impl From<Multiaddr> for ConnectionTarget {
@ -37,6 +40,33 @@ impl From<PeerId> for ConnectionTarget {
}
}
impl FromStr for ConnectionTarget {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains("/p2p/") {
let mut iter = s.split("/p2p/");
let addr = iter
.next()
.ok_or_else(|| anyhow!("missing Multiaddr part of the address"))?
.parse::<Multiaddr>()?;
let peer_id = iter
.next()
.ok_or_else(|| anyhow!("missing PeerId part of the address"))?
.parse::<PeerId>()?;
Ok(ConnectionTarget::PeerIdWithAddr(peer_id, addr))
} else if s.contains('/') {
let addr = s.parse::<Multiaddr>()?;
Ok(ConnectionTarget::Addr(addr))
} else {
let peer_id = s.parse::<PeerId>()?;
Ok(ConnectionTarget::PeerId(peer_id))
}
}
}
/// Disconnected will use banning to disconnect a node. Disconnecting a single peer connection is
/// not supported at the moment.
pub struct Disconnector {
@ -105,6 +135,9 @@ impl SwarmApi {
let will_attempt_connection = match target {
ConnectionTarget::PeerId(ref id) => self.connected_peers.get(id).is_none(),
ConnectionTarget::Addr(ref addr) => !self.connections.contains_key(addr),
ConnectionTarget::PeerIdWithAddr(ref id, ref addr) => {
self.connected_peers.get(id).is_none() || !self.connections.contains_key(addr)
}
};
if !will_attempt_connection {
@ -113,6 +146,14 @@ impl SwarmApi {
trace!("Connecting to {:?}", target);
// convert the ConnectionTarget to the actual dial method so that it's easier
// to handle the subscription we'll be creating.
let target = if let ConnectionTarget::PeerIdWithAddr(_id, addr) = target {
ConnectionTarget::Addr(addr)
} else {
target
};
let subscription = self
.connect_registry
.create_subscription(target.clone().into(), None);
@ -123,6 +164,7 @@ impl SwarmApi {
peer_id,
condition: DialPeerCondition::Disconnected,
},
_ => unreachable!(),
});
Some(subscription)
@ -277,6 +319,26 @@ mod tests {
use libp2p::identity::Keypair;
use libp2p::swarm::Swarm;
#[test]
fn connection_targets() {
let peer_id = "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ";
let multiaddr = "/ip4/104.131.131.82/tcp/4001";
let both = format!("{}/p2p/{}", multiaddr, peer_id);
assert!(matches!(
peer_id.parse().unwrap(),
ConnectionTarget::PeerId(_)
));
assert!(matches!(
multiaddr.parse().unwrap(),
ConnectionTarget::Addr(_)
));
assert!(matches!(
both.parse().unwrap(),
ConnectionTarget::PeerIdWithAddr(..)
));
}
#[async_std::test]
async fn swarm_api() {
let (peer1_id, trans) = mk_transport();