Merge branch 'master' into rand-feature

This commit is contained in:
Ivan Boldyrev 2023-10-10 11:18:45 +04:00
commit 50ec01cc31
80 changed files with 3002 additions and 971 deletions

View File

@ -34,6 +34,6 @@ jobs:
with:
context: .
file: ./misc/server/Dockerfile
push: ${{ ! github.event.pull_request.head.repo.fork }} # Only push image if we have the required permissions, i.e. not running from a fork
push: ${{ ! github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }} # Only push image if we have the required permissions, i.e. not running from a fork
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

16
Cargo.lock generated
View File

@ -714,9 +714,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byteorder"
version = "1.4.3"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
@ -1236,6 +1236,7 @@ dependencies = [
"futures-timer",
"libp2p",
"log",
"tokio",
]
[[package]]
@ -2205,6 +2206,8 @@ dependencies = [
"instant",
"libp2p",
"libp2p-mplex",
"libp2p-noise",
"libp2p-tls",
"libp2p-webrtc",
"libp2p-webrtc-websys",
"log",
@ -2386,6 +2389,7 @@ dependencies = [
"libp2p-mdns",
"libp2p-memory-connection-limits",
"libp2p-metrics",
"libp2p-mplex",
"libp2p-noise",
"libp2p-ping",
"libp2p-plaintext",
@ -2406,6 +2410,8 @@ dependencies = [
"libp2p-yamux",
"multiaddr",
"pin-project",
"rw-stream-sink",
"thiserror",
"tokio",
]
@ -3045,7 +3051,7 @@ dependencies = [
[[package]]
name = "libp2p-swarm"
version = "0.43.5"
version = "0.43.6"
dependencies = [
"async-std",
"either",
@ -5559,9 +5565,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.32.0"
version = "1.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
dependencies = [
"backtrace",
"bytes",

View File

@ -101,7 +101,7 @@ libp2p-rendezvous = { version = "0.13.0", path = "protocols/rendezvous" }
libp2p-upnp = { version = "0.1.1", path = "protocols/upnp" }
libp2p-request-response = { version = "0.25.1", path = "protocols/request-response" }
libp2p-server = { version = "0.12.3", path = "misc/server" }
libp2p-swarm = { version = "0.43.5", path = "swarm" }
libp2p-swarm = { version = "0.43.6", path = "swarm" }
libp2p-swarm-derive = { version = "0.33.0", path = "swarm-derive" }
libp2p-swarm-test = { version = "0.2.0", path = "swarm-test" }
libp2p-tcp = { version = "0.40.0", path = "transports/tcp" }

View File

@ -6,7 +6,7 @@ publish = false
license = "MIT"
[dependencies]
tokio = { version = "1.32", features = ["full"] }
tokio = { version = "1.33", features = ["full"] }
clap = { version = "4.3.23", features = ["derive"] }
env_logger = "0.10.0"
futures = "0.3.28"

View File

@ -21,10 +21,10 @@
#![doc = include_str!("../../README.md")]
use clap::Parser;
use futures::prelude::*;
use futures::StreamExt;
use libp2p::core::multiaddr::Protocol;
use libp2p::core::{upgrade::Version, Multiaddr, Transport};
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent};
use libp2p::core::Multiaddr;
use libp2p::swarm::{NetworkBehaviour, SwarmEvent};
use libp2p::{autonat, identify, identity, noise, tcp, yamux, PeerId};
use std::error::Error;
use std::net::Ipv4Addr;
@ -49,18 +49,16 @@ async fn main() -> Result<(), Box<dyn Error>> {
let opt = Opt::parse();
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| Behaviour::new(key.public()))?
.build();
let transport = tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed();
let behaviour = Behaviour::new(local_key.public());
let mut swarm = SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build();
swarm.listen_on(
Multiaddr::empty()
.with(Protocol::Ip4(Ipv4Addr::UNSPECIFIED))

View File

@ -21,10 +21,10 @@
#![doc = include_str!("../../README.md")]
use clap::Parser;
use futures::prelude::*;
use libp2p::core::{multiaddr::Protocol, upgrade::Version, Multiaddr, Transport};
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent};
use libp2p::{autonat, identify, identity, noise, tcp, yamux, PeerId};
use futures::StreamExt;
use libp2p::core::{multiaddr::Protocol, Multiaddr};
use libp2p::swarm::{NetworkBehaviour, SwarmEvent};
use libp2p::{autonat, identify, identity, noise, tcp, yamux};
use std::error::Error;
use std::net::Ipv4Addr;
@ -41,18 +41,16 @@ async fn main() -> Result<(), Box<dyn Error>> {
let opt = Opt::parse();
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| Behaviour::new(key.public()))?
.build();
let transport = tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed();
let behaviour = Behaviour::new(local_key.public());
let mut swarm = SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build();
swarm.listen_on(
Multiaddr::empty()
.with(Protocol::Ip4(Ipv4Addr::UNSPECIFIED))

View File

@ -24,7 +24,7 @@ axum = "0.6.19"
libp2p = { path = "../../libp2p", features = [ "ed25519", "macros", "ping", "wasm-bindgen", "tokio"] }
libp2p-webrtc = { workspace = true, features = ["tokio"] }
rust-embed = { version = "8.0.0", features = ["include-exclude", "interpolate-folder-path"] }
tokio = { version = "1.29", features = ["macros", "net", "rt", "signal"] }
tokio = { version = "1.33", features = ["macros", "net", "rt", "signal"] }
tokio-util = { version = "0.7", features = ["compat"] }
tower = "0.4"
tower-http = { version = "0.4.0", features = ["cors"] }

View File

@ -6,6 +6,7 @@ use libp2p::core::Multiaddr;
use libp2p::identity::{Keypair, PeerId};
use libp2p::ping;
use libp2p::swarm::{keep_alive, NetworkBehaviour, SwarmBuilder, SwarmEvent};
use libp2p::webrtc_websys;
use std::convert::From;
use std::io;
use wasm_bindgen::prelude::*;
@ -18,19 +19,16 @@ pub async fn run(libp2p_endpoint: String) -> Result<(), JsError> {
let body = Body::from_current_window()?;
body.append_p("Let's ping the WebRTC Server!")?;
let local_key = Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let mut swarm = SwarmBuilder::with_wasm_executor(
libp2p_webrtc_websys::Transport::new(libp2p_webrtc_websys::Config::new(&local_key)).boxed(),
Behaviour {
let swarm = libp2p::SwarmBuilder::with_new_identity()
.with_wasm_bindgen()
.with_other_transport(|key| {
webrtc_websys::Transport::new(webrtc_websys::Config::new(&key))
})?
.with_behaviour(|_| Behaviour {
ping: ping::Behaviour::new(ping::Config::new()),
keep_alive: keep_alive::Behaviour,
},
local_peer_id,
)
.build();
log::info!("Initialize swarm with identity: {local_peer_id}");
})?
.build();
let addr = libp2p_endpoint.parse::<Multiaddr>()?;
log::info!("Dialing {addr}");

View File

@ -10,10 +10,9 @@ use futures::StreamExt;
use libp2p::{
core::muxing::StreamMuxerBox,
core::Transport,
identity,
multiaddr::{Multiaddr, Protocol},
ping,
swarm::{SwarmBuilder, SwarmEvent},
swarm::SwarmEvent,
};
use libp2p_webrtc as webrtc;
use rand::thread_rng;
@ -28,19 +27,22 @@ async fn main() -> anyhow::Result<()> {
.parse_default_env()
.init();
let id_keys = identity::Keypair::generate_ed25519();
let local_peer_id = id_keys.public().to_peer_id();
let transport = webrtc::tokio::Transport::new(
id_keys,
webrtc::tokio::Certificate::generate(&mut thread_rng())?,
)
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn)))
.boxed();
let mut swarm =
SwarmBuilder::with_tokio_executor(transport, ping::Behaviour::default(), local_peer_id)
.idle_connection_timeout(Duration::from_secs(30)) // Allows us to observe the pings.
.build();
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_other_transport(|id_keys| {
Ok(webrtc::tokio::Transport::new(
id_keys.clone(),
webrtc::tokio::Certificate::generate(&mut thread_rng())?,
)
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))))
})?
.with_behaviour(|_| ping::Behaviour::default())?
.with_swarm_config(|cfg| {
cfg.with_idle_connection_timeout(
Duration::from_secs(30), // Allows us to observe the pings.
)
})
.build();
let address_webrtc = Multiaddr::from(Ipv4Addr::UNSPECIFIED)
.with(Protocol::Udp(0))

View File

@ -6,7 +6,7 @@ publish = false
license = "MIT"
[dependencies]
tokio = { version = "1.32", features = ["full"] }
tokio = { version = "1.33", features = ["full"] }
async-trait = "0.1"
env_logger = "0.10.0"
futures = "0.3.28"

View File

@ -20,14 +20,8 @@
#![doc = include_str!("../README.md")]
use futures::{future::Either, stream::StreamExt};
use libp2p::{
core::{muxing::StreamMuxerBox, transport::OrTransport, upgrade},
gossipsub, identity, mdns, noise, quic,
swarm::NetworkBehaviour,
swarm::{SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
};
use futures::stream::StreamExt;
use libp2p::{gossipsub, mdns, noise, swarm::NetworkBehaviour, swarm::SwarmEvent, tcp, yamux};
use std::collections::hash_map::DefaultHasher;
use std::error::Error;
use std::hash::{Hash, Hasher};
@ -43,58 +37,46 @@ struct MyBehaviour {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Create a random PeerId
env_logger::init();
let id_keys = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(id_keys.public());
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_quic()
.with_behaviour(|key| {
// To content-address message, we can take the hash of message and use it as an ID.
let message_id_fn = |message: &gossipsub::Message| {
let mut s = DefaultHasher::new();
message.data.hash(&mut s);
gossipsub::MessageId::from(s.finish().to_string())
};
// Set up an encrypted DNS-enabled TCP Transport over the yamux protocol.
let tcp_transport = tcp::tokio::Transport::new(tcp::Config::default().nodelay(true))
.upgrade(upgrade::Version::V1Lazy)
.authenticate(noise::Config::new(&id_keys).expect("signing libp2p-noise static keypair"))
.multiplex(yamux::Config::default())
.timeout(std::time::Duration::from_secs(20))
.boxed();
let quic_transport = quic::tokio::Transport::new(quic::Config::new(&id_keys));
let transport = OrTransport::new(quic_transport, tcp_transport)
.map(|either_output, _| match either_output {
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
})
.boxed();
// Set a custom gossipsub configuration
let gossipsub_config = gossipsub::ConfigBuilder::default()
.heartbeat_interval(Duration::from_secs(10)) // This is set to aid debugging by not cluttering the log space
.validation_mode(gossipsub::ValidationMode::Strict) // This sets the kind of message validation. The default is Strict (enforce message signing)
.message_id_fn(message_id_fn) // content-address messages. No two messages of the same content will be propagated.
.build()
.map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; // Temporary hack because `build` does not return a proper `std::error::Error`.
// To content-address message, we can take the hash of message and use it as an ID.
let message_id_fn = |message: &gossipsub::Message| {
let mut s = DefaultHasher::new();
message.data.hash(&mut s);
gossipsub::MessageId::from(s.finish().to_string())
};
// build a gossipsub network behaviour
let gossipsub = gossipsub::Behaviour::new(
gossipsub::MessageAuthenticity::Signed(key.clone()),
gossipsub_config,
)?;
// Set a custom gossipsub configuration
let gossipsub_config = gossipsub::ConfigBuilder::default()
.heartbeat_interval(Duration::from_secs(10)) // This is set to aid debugging by not cluttering the log space
.validation_mode(gossipsub::ValidationMode::Strict) // This sets the kind of message validation. The default is Strict (enforce message signing)
.message_id_fn(message_id_fn) // content-address messages. No two messages of the same content will be propagated.
.build()
.expect("Valid config");
let mdns =
mdns::tokio::Behaviour::new(mdns::Config::default(), key.public().to_peer_id())?;
Ok(MyBehaviour { gossipsub, mdns })
})?
.build();
// build a gossipsub network behaviour
let mut gossipsub = gossipsub::Behaviour::new(
gossipsub::MessageAuthenticity::Signed(id_keys),
gossipsub_config,
)
.expect("Correct configuration");
// Create a Gossipsub topic
let topic = gossipsub::IdentTopic::new("test-net");
// subscribes to our topic
gossipsub.subscribe(&topic)?;
// Create a Swarm to manage peers and events
let mut swarm = {
let mdns = mdns::tokio::Behaviour::new(mdns::Config::default(), local_peer_id)?;
let behaviour = MyBehaviour { gossipsub, mdns };
SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build()
};
swarm.behaviour_mut().gossipsub.subscribe(&topic)?;
// Read full lines from stdin
let mut stdin = io::BufReader::new(io::stdin()).lines();

View File

@ -10,8 +10,9 @@ clap = { version = "4.3.23", features = ["derive"] }
env_logger = "0.10.0"
futures = "0.3.28"
futures-timer = "3.0"
libp2p = { path = "../../libp2p", features = [ "async-std", "dns", "dcutr", "identify", "macros", "noise", "ping", "quic", "relay", "rendezvous", "tcp", "tokio", "yamux"] }
libp2p = { path = "../../libp2p", features = [ "dns", "dcutr", "identify", "macros", "noise", "ping", "quic", "relay", "rendezvous", "tcp", "tokio", "yamux"] }
log = "0.4"
tokio = { version = "1.29", features = ["macros", "net", "rt", "signal"] }
[lints]
workspace = true

View File

@ -21,20 +21,11 @@
#![doc = include_str!("../README.md")]
use clap::Parser;
use futures::{
executor::{block_on, ThreadPool},
future::{Either, FutureExt},
stream::StreamExt,
};
use futures::{executor::block_on, future::FutureExt, stream::StreamExt};
use libp2p::{
core::{
multiaddr::{Multiaddr, Protocol},
muxing::StreamMuxerBox,
transport::Transport,
upgrade,
},
dcutr, dns, identify, identity, noise, ping, quic, relay,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
core::multiaddr::{Multiaddr, Protocol},
dcutr, identify, identity, noise, ping, relay,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux, PeerId,
};
use log::info;
@ -78,37 +69,12 @@ impl FromStr for Mode {
}
}
fn main() -> Result<(), Box<dyn Error>> {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let opts = Opts::parse();
let local_key = generate_ed25519(opts.secret_key_seed);
let local_peer_id = PeerId::from(local_key.public());
let (relay_transport, client) = relay::client::new(local_peer_id);
let transport = {
let relay_tcp_quic_transport = relay_transport
.or_transport(tcp::async_io::Transport::new(
tcp::Config::default().port_reuse(true),
))
.upgrade(upgrade::Version::V1)
.authenticate(noise::Config::new(&local_key).unwrap())
.multiplex(yamux::Config::default())
.or_transport(quic::async_std::Transport::new(quic::Config::new(
&local_key,
)));
block_on(dns::async_std::Transport::system(relay_tcp_quic_transport))
.unwrap()
.map(|either_output, _| match either_output {
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
})
.boxed()
};
#[derive(NetworkBehaviour)]
struct Behaviour {
relay_client: relay::client::Behaviour,
@ -117,21 +83,27 @@ fn main() -> Result<(), Box<dyn Error>> {
dcutr: dcutr::Behaviour,
}
let behaviour = Behaviour {
relay_client: client,
ping: ping::Behaviour::new(ping::Config::new()),
identify: identify::Behaviour::new(identify::Config::new(
"/TODO/0.0.1".to_string(),
local_key.public(),
)),
dcutr: dcutr::Behaviour::new(local_peer_id),
};
let mut swarm = match ThreadPool::new() {
Ok(tp) => SwarmBuilder::with_executor(transport, behaviour, local_peer_id, tp),
Err(_) => SwarmBuilder::without_executor(transport, behaviour, local_peer_id),
}
.build();
let mut swarm =
libp2p::SwarmBuilder::with_existing_identity(generate_ed25519(opts.secret_key_seed))
.with_tokio()
.with_tcp(
tcp::Config::default().port_reuse(true).nodelay(true),
noise::Config::new,
yamux::Config::default,
)?
.with_quic()
.with_dns()?
.with_relay_client(noise::Config::new, yamux::Config::default)?
.with_behaviour(|keypair, relay_behaviour| Behaviour {
relay_client: relay_behaviour,
ping: ping::Behaviour::new(ping::Config::new()),
identify: identify::Behaviour::new(identify::Config::new(
"/TODO/0.0.1".to_string(),
keypair.public(),
)),
dcutr: dcutr::Behaviour::new(keypair.public().to_peer_id()),
})?
.build();
swarm
.listen_on("/ip4/0.0.0.0/udp/0/quic-v1".parse().unwrap())

View File

@ -10,7 +10,7 @@ async-std = { version = "1.12", features = ["attributes"] }
async-trait = "0.1"
env_logger = "0.10"
futures = "0.3.28"
libp2p = { path = "../../libp2p", features = [ "async-std", "dns", "kad", "mdns", "noise", "macros", "tcp", "websocket", "yamux"] }
libp2p = { path = "../../libp2p", features = [ "async-std", "dns", "kad", "mdns", "noise", "macros", "tcp", "yamux"] }
[lints]
workspace = true

View File

@ -22,14 +22,13 @@
use async_std::io;
use futures::{prelude::*, select};
use libp2p::core::upgrade::Version;
use libp2p::kad;
use libp2p::kad::record::store::MemoryStore;
use libp2p::kad::Mode;
use libp2p::{
identity, mdns, noise,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
mdns, noise,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux,
};
use std::error::Error;
@ -37,16 +36,6 @@ use std::error::Error;
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
// Create a random key for ourselves.
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let transport = tcp::async_io::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed();
// We create a custom network behaviour that combines Kademlia and mDNS.
#[derive(NetworkBehaviour)]
struct Behaviour {
@ -54,15 +43,26 @@ async fn main() -> Result<(), Box<dyn Error>> {
mdns: mdns::async_io::Behaviour,
}
// Create a swarm to manage peers and events.
let mut swarm = {
// Create a Kademlia behaviour.
let store = MemoryStore::new(local_peer_id);
let kademlia = kad::Behaviour::new(local_peer_id, store);
let mdns = mdns::async_io::Behaviour::new(mdns::Config::default(), local_peer_id)?;
let behaviour = Behaviour { kademlia, mdns };
SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id).build()
};
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_async_std()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| {
Ok(Behaviour {
kademlia: kad::Behaviour::new(
key.public().to_peer_id(),
MemoryStore::new(key.public().to_peer_id()),
),
mdns: mdns::async_io::Behaviour::new(
mdns::Config::default(),
key.public().to_peer_id(),
)?,
})
})?
.build();
swarm.behaviour_mut().kademlia.set_mode(Some(Mode::Server));

View File

@ -9,11 +9,10 @@ use libp2p::{
multiaddr::Protocol,
noise,
request_response::{self, ProtocolSupport, RequestId, ResponseChannel},
swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
swarm::{NetworkBehaviour, Swarm, SwarmEvent},
tcp, yamux, PeerId,
};
use libp2p::core::upgrade::Version;
use libp2p::StreamProtocol;
use serde::{Deserialize, Serialize};
use std::collections::{hash_map, HashMap, HashSet};
@ -41,18 +40,18 @@ pub(crate) async fn new(
};
let peer_id = id_keys.public().to_peer_id();
let transport = tcp::async_io::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&id_keys)?)
.multiplex(yamux::Config::default())
.boxed();
// Build the Swarm, connecting the lower layer transport logic with the
// higher layer network behaviour logic.
let mut swarm = SwarmBuilder::with_async_std_executor(
transport,
Behaviour {
kademlia: kad::Behaviour::new(peer_id, kad::record::store::MemoryStore::new(peer_id)),
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(id_keys)
.with_async_std()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| Behaviour {
kademlia: kad::Behaviour::new(
peer_id,
kad::store::MemoryStore::new(key.public().to_peer_id()),
),
request_response: request_response::cbor::Behaviour::new(
[(
StreamProtocol::new("/file-exchange/1"),
@ -60,10 +59,8 @@ pub(crate) async fn new(
)],
request_response::Config::default(),
),
},
peer_id,
)
.build();
})?
.build();
swarm
.behaviour_mut()

View File

@ -20,35 +20,28 @@
#![doc = include_str!("../README.md")]
use futures::prelude::*;
use libp2p::{
core::{multiaddr::Multiaddr, upgrade::Version},
identify, identity, noise,
swarm::{SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
};
use futures::StreamExt;
use libp2p::{core::multiaddr::Multiaddr, identify, noise, swarm::SwarmEvent, tcp, yamux};
use std::error::Error;
#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let transport = tcp::async_io::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key).unwrap())
.multiplex(yamux::Config::default())
.boxed();
// Create a identify network behaviour.
let behaviour = identify::Behaviour::new(identify::Config::new(
"/ipfs/id/1.0.0".to_string(),
local_key.public(),
));
let mut swarm =
SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id).build();
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_async_std()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| {
identify::Behaviour::new(identify::Config::new(
"/ipfs/id/1.0.0".to_string(),
key.public(),
))
})?
.build();
// Tell the swarm to listen on all interfaces and a random, OS-assigned
// port.

View File

@ -6,13 +6,13 @@ publish = false
license = "MIT"
[dependencies]
tokio = { version = "1.12", features = ["rt-multi-thread", "macros"] }
tokio = { version = "1.33", features = ["rt-multi-thread", "macros"] }
async-trait = "0.1"
clap = { version = "4.3.23", features = ["derive"] }
env_logger = "0.10"
futures = "0.3.28"
anyhow = "1.0.75"
libp2p = { path = "../../libp2p", features = [ "tokio", "dns", "kad", "noise", "tcp", "websocket", "yamux", "rsa"] }
libp2p = { path = "../../libp2p", features = [ "tokio", "dns", "kad", "noise", "tcp", "yamux", "rsa"] }
[lints]
workspace = true

View File

@ -27,12 +27,7 @@ use std::time::{Duration, Instant};
use anyhow::{bail, Result};
use clap::Parser;
use futures::StreamExt;
use libp2p::{
bytes::BufMut,
identity, kad,
swarm::{SwarmBuilder, SwarmEvent},
tokio_development_transport, PeerId,
};
use libp2p::{bytes::BufMut, identity, kad, noise, swarm::SwarmEvent, tcp, yamux, PeerId};
const BOOTNODES: [&str; 4] = [
"QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
@ -47,28 +42,32 @@ async fn main() -> Result<()> {
// Create a random key for ourselves.
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
// Set up a an encrypted DNS-enabled TCP Transport over the yamux protocol
let transport = tokio_development_transport(local_key.clone())?;
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(local_key.clone())
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_dns()?
.with_behaviour(|key| {
// Create a Kademlia behaviour.
let mut cfg = kad::Config::default();
cfg.set_query_timeout(Duration::from_secs(5 * 60));
let store = kad::store::MemoryStore::new(key.public().to_peer_id());
kad::Behaviour::with_config(key.public().to_peer_id(), store, cfg)
})?
.build();
// Create a swarm to manage peers and events.
let mut swarm = {
// Create a Kademlia behaviour.
let mut cfg = kad::Config::default();
cfg.set_query_timeout(Duration::from_secs(5 * 60));
let store = kad::store::MemoryStore::new(local_peer_id);
let mut behaviour = kad::Behaviour::with_config(local_peer_id, store, cfg);
// Add the bootnodes to the local routing table. `libp2p-dns` built
// into the `transport` resolves the `dnsaddr` when Kademlia tries
// to dial these nodes.
for peer in &BOOTNODES {
behaviour.add_address(&peer.parse()?, "/dnsaddr/bootstrap.libp2p.io".parse()?);
}
SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build()
};
// Add the bootnodes to the local routing table. `libp2p-dns` built
// into the `transport` resolves the `dnsaddr` when Kademlia tries
// to dial these nodes.
for peer in &BOOTNODES {
swarm
.behaviour_mut()
.add_address(&peer.parse()?, "/dnsaddr/bootstrap.libp2p.io".parse()?);
}
let cli_opt = Opt::parse();
@ -83,11 +82,11 @@ async fn main() -> Result<()> {
let mut pk_record_key = vec![];
pk_record_key.put_slice("/pk/".as_bytes());
pk_record_key.put_slice(local_peer_id.to_bytes().as_slice());
pk_record_key.put_slice(swarm.local_peer_id().to_bytes().as_slice());
let mut pk_record =
kad::Record::new(pk_record_key, local_key.public().encode_protobuf());
pk_record.publisher = Some(local_peer_id);
pk_record.publisher = Some(*swarm.local_peer_id());
pk_record.expires = Some(Instant::now().add(Duration::from_secs(60)));
swarm

View File

@ -6,7 +6,7 @@ publish = false
license = "MIT"
[dependencies]
tokio = { version = "1.32", features = ["rt-multi-thread", "macros", "io-std"] }
tokio = { version = "1.33", features = ["rt-multi-thread", "macros", "io-std"] }
async-trait = "0.1"
either = "1.9"
env_logger = "0.10"

View File

@ -23,40 +23,17 @@
use either::Either;
use futures::prelude::*;
use libp2p::{
core::{muxing::StreamMuxerBox, transport, transport::upgrade::Version},
gossipsub, identify, identity,
core::transport::upgrade::Version,
gossipsub, identify,
multiaddr::Protocol,
noise, ping,
pnet::{PnetConfig, PreSharedKey},
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, Multiaddr, PeerId, Transport,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux, Multiaddr, Transport,
};
use std::{env, error::Error, fs, path::Path, str::FromStr, time::Duration};
use std::{env, error::Error, fs, path::Path, str::FromStr};
use tokio::{io, io::AsyncBufReadExt, select};
/// Builds the transport that serves as a common ground for all connections.
pub fn build_transport(
key_pair: identity::Keypair,
psk: Option<PreSharedKey>,
) -> transport::Boxed<(PeerId, StreamMuxerBox)> {
let noise_config = noise::Config::new(&key_pair).unwrap();
let yamux_config = yamux::Config::default();
let base_transport = tcp::tokio::Transport::new(tcp::Config::default().nodelay(true));
let maybe_encrypted = match psk {
Some(psk) => Either::Left(
base_transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)),
),
None => Either::Right(base_transport),
};
maybe_encrypted
.upgrade(Version::V1Lazy)
.authenticate(noise_config)
.multiplex(yamux_config)
.timeout(Duration::from_secs(20))
.boxed()
}
/// Get the current ipfs repo path, either from the IPFS_PATH environment variable or
/// from the default $HOME/.ipfs
fn get_ipfs_path() -> Box<Path> {
@ -118,76 +95,67 @@ async fn main() -> Result<(), Box<dyn Error>> {
.map(|text| PreSharedKey::from_str(&text))
.transpose()?;
// Create a random PeerId
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
println!("using random peer id: {local_peer_id:?}");
if let Some(psk) = psk {
println!("using swarm key with fingerprint: {}", psk.fingerprint());
}
// Set up a an encrypted DNS-enabled TCP Transport over and Yamux protocol
let transport = build_transport(local_key.clone(), psk);
// Create a Gosspipsub topic
let gossipsub_topic = gossipsub::IdentTopic::new("chat");
// We create a custom network behaviour that combines gossipsub, ping and identify.
#[derive(NetworkBehaviour)]
#[behaviour(to_swarm = "MyBehaviourEvent")]
struct MyBehaviour {
gossipsub: gossipsub::Behaviour,
identify: identify::Behaviour,
ping: ping::Behaviour,
}
enum MyBehaviourEvent {
Gossipsub(gossipsub::Event),
Identify(identify::Event),
Ping(ping::Event),
}
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_other_transport(|key| {
let noise_config = noise::Config::new(key).unwrap();
let yamux_config = yamux::Config::default();
impl From<gossipsub::Event> for MyBehaviourEvent {
fn from(event: gossipsub::Event) -> Self {
MyBehaviourEvent::Gossipsub(event)
}
}
let base_transport = tcp::tokio::Transport::new(tcp::Config::default().nodelay(true));
let maybe_encrypted = match psk {
Some(psk) => Either::Left(
base_transport
.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)),
),
None => Either::Right(base_transport),
};
maybe_encrypted
.upgrade(Version::V1Lazy)
.authenticate(noise_config)
.multiplex(yamux_config)
})?
.with_dns()?
.with_behaviour(|key| {
let gossipsub_config = gossipsub::ConfigBuilder::default()
.max_transmit_size(262144)
.build()
.map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?; // Temporary hack because `build` does not return a proper `std::error::Error`.
Ok(MyBehaviour {
gossipsub: gossipsub::Behaviour::new(
gossipsub::MessageAuthenticity::Signed(key.clone()),
gossipsub_config,
)
.expect("Valid configuration"),
identify: identify::Behaviour::new(identify::Config::new(
"/ipfs/0.1.0".into(),
key.public(),
)),
ping: ping::Behaviour::new(ping::Config::new()),
})
})?
.build();
impl From<identify::Event> for MyBehaviourEvent {
fn from(event: identify::Event) -> Self {
MyBehaviourEvent::Identify(event)
}
}
impl From<ping::Event> for MyBehaviourEvent {
fn from(event: ping::Event) -> Self {
MyBehaviourEvent::Ping(event)
}
}
// Create a Swarm to manage peers and events
let mut swarm = {
let gossipsub_config = gossipsub::ConfigBuilder::default()
.max_transmit_size(262144)
.build()
.expect("valid config");
let mut behaviour = MyBehaviour {
gossipsub: gossipsub::Behaviour::new(
gossipsub::MessageAuthenticity::Signed(local_key.clone()),
gossipsub_config,
)
.expect("Valid configuration"),
identify: identify::Behaviour::new(identify::Config::new(
"/ipfs/0.1.0".into(),
local_key.public(),
)),
ping: ping::Behaviour::new(ping::Config::new()),
};
println!("Subscribing to {gossipsub_topic:?}");
behaviour.gossipsub.subscribe(&gossipsub_topic).unwrap();
SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build()
};
println!("Subscribing to {gossipsub_topic:?}");
swarm
.behaviour_mut()
.gossipsub
.subscribe(&gossipsub_topic)
.unwrap();
// Reach out to other nodes if specified
for to_dial in std::env::args().skip(1) {

View File

@ -21,12 +21,10 @@
#![doc = include_str!("../README.md")]
use env_logger::Env;
use futures::executor::block_on;
use futures::stream::StreamExt;
use libp2p::core::{upgrade::Version, Multiaddr, Transport};
use libp2p::identity::PeerId;
use futures::{executor::block_on, StreamExt};
use libp2p::core::Multiaddr;
use libp2p::metrics::{Metrics, Recorder};
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent};
use libp2p::swarm::{NetworkBehaviour, SwarmEvent};
use libp2p::{identify, identity, noise, ping, tcp, yamux};
use log::info;
use prometheus_client::registry::Registry;
@ -39,21 +37,16 @@ mod http_service;
fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let local_pub_key = local_key.public();
let mut swarm = SwarmBuilder::without_executor(
tcp::async_io::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed(),
Behaviour::new(local_pub_key),
local_peer_id,
)
.idle_connection_timeout(Duration::from_secs(60))
.build();
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_async_std()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| Behaviour::new(key.public()))?
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))
.build();
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;

View File

@ -9,7 +9,7 @@ license = "MIT"
env_logger = "0.10.0"
futures = "0.3.28"
libp2p = { path = "../../libp2p", features = ["noise", "ping", "tcp", "tokio", "yamux"] }
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.33.0", features = ["full"] }
[lints]
workspace = true

View File

@ -21,31 +21,21 @@
#![doc = include_str!("../README.md")]
use futures::prelude::*;
use libp2p::core::upgrade::Version;
use libp2p::{
identity, noise, ping,
swarm::{SwarmBuilder, SwarmEvent},
tcp, yamux, Multiaddr, PeerId, Transport,
};
use std::error::Error;
use std::time::Duration;
use libp2p::{noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr};
use std::{error::Error, time::Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let transport = tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed();
let mut swarm =
SwarmBuilder::with_tokio_executor(transport, ping::Behaviour::default(), local_peer_id)
.idle_connection_timeout(Duration::from_secs(60)) // For illustrative purposes, keep idle connections alive for a minute so we can observe a few pings.
.build();
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|_| ping::Behaviour::default())?
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))
.build();
// Tell the swarm to listen on all interfaces and a random, OS-assigned
// port.

View File

@ -22,18 +22,14 @@
#![doc = include_str!("../README.md")]
use clap::Parser;
use futures::executor::block_on;
use futures::stream::StreamExt;
use futures::{executor::block_on, future::Either};
use libp2p::{
core::multiaddr::Protocol,
core::muxing::StreamMuxerBox,
core::upgrade,
core::{Multiaddr, Transport},
identify, identity,
identity::PeerId,
noise, ping, quic, relay,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp,
core::Multiaddr,
identify, identity, noise, ping, relay,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux,
};
use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr};
@ -42,41 +38,27 @@ fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let opt = Opt::parse();
println!("opt: {opt:?}");
// Create a static known PeerId based on given secret
let local_key: identity::Keypair = generate_ed25519(opt.secret_key_seed);
let local_peer_id = PeerId::from(local_key.public());
let tcp_transport = tcp::async_io::Transport::default();
let tcp_transport = tcp_transport
.upgrade(upgrade::Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).expect("Signing libp2p-noise static DH keypair failed."),
)
.multiplex(libp2p::yamux::Config::default());
let quic_transport = quic::async_std::Transport::new(quic::Config::new(&local_key));
let transport = quic_transport
.or_transport(tcp_transport)
.map(|either_output, _| match either_output {
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
})
.boxed();
let behaviour = Behaviour {
relay: relay::Behaviour::new(local_peer_id, Default::default()),
ping: ping::Behaviour::new(ping::Config::new()),
identify: identify::Behaviour::new(identify::Config::new(
"/TODO/0.0.1".to_string(),
local_key.public(),
)),
};
let mut swarm = SwarmBuilder::without_executor(transport, behaviour, local_peer_id).build();
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(local_key)
.with_async_std()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_quic()
.with_behaviour(|key| Behaviour {
relay: relay::Behaviour::new(key.public().to_peer_id(), Default::default()),
ping: ping::Behaviour::new(ping::Config::new()),
identify: identify::Behaviour::new(identify::Config::new(
"/TODO/0.0.1".to_string(),
key.public(),
)),
})?
.build();
// Listen on all interfaces
let listen_addr_tcp = Multiaddr::empty()

View File

@ -12,7 +12,7 @@ env_logger = "0.10.0"
futures = "0.3.28"
libp2p = { path = "../../libp2p", features = [ "async-std", "identify", "macros", "noise", "ping", "rendezvous", "tcp", "tokio", "yamux"] }
log = "0.4"
tokio = { version = "1.32", features = ["rt-multi-thread", "macros", "time"] }
tokio = { version = "1.33", features = ["rt-multi-thread", "macros", "time"] }
[lints]
workspace = true

View File

@ -20,41 +20,38 @@
use futures::StreamExt;
use libp2p::{
core::transport::upgrade::Version,
identity,
multiaddr::Protocol,
noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, Multiaddr, PeerId, Transport,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux, Multiaddr,
};
use std::error::Error;
use std::time::Duration;
const NAMESPACE: &str = "rendezvous";
#[tokio::main]
async fn main() {
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let key_pair = identity::Keypair::generate_ed25519();
let rendezvous_point_address = "/ip4/127.0.0.1/tcp/62649".parse::<Multiaddr>().unwrap();
let rendezvous_point = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
.parse()
.unwrap();
let mut swarm = SwarmBuilder::with_tokio_executor(
tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&key_pair).unwrap())
.multiplex(yamux::Config::default())
.boxed(),
MyBehaviour {
rendezvous: rendezvous::client::Behaviour::new(key_pair.clone()),
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| MyBehaviour {
rendezvous: rendezvous::client::Behaviour::new(key.clone()),
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
},
PeerId::from(key_pair.public()),
)
.idle_connection_timeout(Duration::from_secs(5))
.build();
})?
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(5)))
.build();
swarm.dial(rendezvous_point_address.clone()).unwrap();

View File

@ -20,10 +20,9 @@
use futures::StreamExt;
use libp2p::{
core::transport::upgrade::Version,
identify, identity, noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, Multiaddr, PeerId, Transport,
identify, noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux, Multiaddr,
};
use std::time::Duration;
@ -31,30 +30,30 @@ use std::time::Duration;
async fn main() {
env_logger::init();
let key_pair = identity::Keypair::generate_ed25519();
let rendezvous_point_address = "/ip4/127.0.0.1/tcp/62649".parse::<Multiaddr>().unwrap();
let rendezvous_point = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
.parse()
.unwrap();
let mut swarm = SwarmBuilder::with_tokio_executor(
tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&key_pair).unwrap())
.multiplex(yamux::Config::default())
.boxed(),
MyBehaviour {
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)
.unwrap()
.with_behaviour(|key| MyBehaviour {
identify: identify::Behaviour::new(identify::Config::new(
"rendezvous-example/1.0.0".to_string(),
key_pair.public(),
key.public(),
)),
rendezvous: rendezvous::client::Behaviour::new(key_pair.clone()),
rendezvous: rendezvous::client::Behaviour::new(key.clone()),
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
},
PeerId::from(key_pair.public()),
)
.idle_connection_timeout(Duration::from_secs(5))
.build();
})
.unwrap()
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(5)))
.build();
let _ = swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());

View File

@ -20,10 +20,9 @@
use futures::StreamExt;
use libp2p::{
core::transport::upgrade::Version,
identity, noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, Multiaddr, PeerId, Transport,
noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux, Multiaddr,
};
use std::time::Duration;
@ -31,26 +30,26 @@ use std::time::Duration;
async fn main() {
env_logger::init();
let key_pair = identity::Keypair::generate_ed25519();
let rendezvous_point_address = "/ip4/127.0.0.1/tcp/62649".parse::<Multiaddr>().unwrap();
let rendezvous_point = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
.parse()
.unwrap();
let mut swarm = SwarmBuilder::with_tokio_executor(
tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&key_pair).unwrap())
.multiplex(yamux::Config::default())
.boxed(),
MyBehaviour {
rendezvous: rendezvous::client::Behaviour::new(key_pair.clone()),
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)
.unwrap()
.with_behaviour(|key| MyBehaviour {
rendezvous: rendezvous::client::Behaviour::new(key.clone()),
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
},
PeerId::from(key_pair.public()),
)
.idle_connection_timeout(Duration::from_secs(5))
.build();
})
.unwrap()
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(5)))
.build();
// In production the external address should be the publicly facing IP address of the rendezvous point.
// This address is recorded in the registration entry by the rendezvous point.

View File

@ -22,37 +22,34 @@
use futures::StreamExt;
use libp2p::{
core::transport::upgrade::Version,
identify, identity, noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
identify, noise, ping, rendezvous,
swarm::{NetworkBehaviour, SwarmEvent},
tcp, yamux,
};
use std::error::Error;
use std::time::Duration;
#[tokio::main]
async fn main() {
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let key_pair = identity::Keypair::generate_ed25519();
let mut swarm = SwarmBuilder::with_tokio_executor(
tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&key_pair).unwrap())
.multiplex(yamux::Config::default())
.boxed(),
MyBehaviour {
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|key| MyBehaviour {
identify: identify::Behaviour::new(identify::Config::new(
"rendezvous-example/1.0.0".to_string(),
key_pair.public(),
key.public(),
)),
rendezvous: rendezvous::server::Behaviour::new(rendezvous::server::Config::default()),
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
},
PeerId::from(key_pair.public()),
)
.idle_connection_timeout(Duration::from_secs(5))
.build();
})?
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(5)))
.build();
let _ = swarm.listen_on("/ip4/0.0.0.0/tcp/62649".parse().unwrap());
@ -90,6 +87,8 @@ async fn main() {
}
}
}
Ok(())
}
#[derive(NetworkBehaviour)]

View File

@ -8,7 +8,7 @@ license = "MIT"
[dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
futures = "0.3.28"
libp2p = { path = "../../libp2p", features = ["tokio", "dns", "macros", "noise", "ping", "tcp", "websocket", "yamux", "upnp"] }
libp2p = { path = "../../libp2p", features = ["tokio", "dns", "macros", "noise", "ping", "tcp", "yamux", "upnp"] }
[lints]
workspace = true

View File

@ -21,32 +21,20 @@
#![doc = include_str!("../README.md")]
use futures::prelude::*;
use libp2p::core::upgrade::Version;
use libp2p::{
identity, noise,
swarm::{SwarmBuilder, SwarmEvent},
tcp, upnp, yamux, Multiaddr, PeerId, Transport,
};
use libp2p::{noise, swarm::SwarmEvent, upnp, yamux, Multiaddr};
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
println!("Local peer id: {local_peer_id:?}");
let transport = tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&local_key)?)
.multiplex(yamux::Config::default())
.boxed();
let mut swarm = SwarmBuilder::with_tokio_executor(
transport,
upnp::tokio::Behaviour::default(),
local_peer_id,
)
.build();
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|_| upnp::tokio::Behaviour::default())?
.build();
// Tell the swarm to listen on all interfaces and a random, OS-assigned
// port.

View File

@ -20,8 +20,10 @@ rand = "0.8.5"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
axum = "0.6"
libp2p = { path = "../libp2p", features = [ "ping", "noise", "tls", "rsa", "macros", "websocket", "tokio", "yamux", "tcp", "dns", "identify", "quic"] }
libp2p-webrtc = { workspace = true, features = ["tokio"] }
libp2p-mplex = { path = "../muxers/mplex" }
libp2p-noise = { workspace = true }
libp2p-tls = { workspace = true }
libp2p-webrtc = { workspace = true, features = ["tokio"] }
mime_guess = "2.0"
redis = { version = "0.23.3", default-features = false, features = [
"tokio-comp",
@ -29,7 +31,7 @@ redis = { version = "0.23.3", default-features = false, features = [
rust-embed = "8.0"
serde_json = "1"
thirtyfour = "=0.32.0-rc.8" # https://github.com/stevepryde/thirtyfour/issues/169
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.33.0", features = ["full"] }
tower-http = { version = "0.4", features = ["cors", "fs", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View File

@ -1,16 +1,10 @@
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::Boxed;
use libp2p::PeerId;
// Native re-exports
#[cfg(not(target_arch = "wasm32"))]
pub(crate) use native::{build_transport, init_logger, sleep, swarm_builder, Instant, RedisClient};
pub(crate) use native::{build_swarm, init_logger, sleep, Instant, RedisClient};
// Wasm re-exports
#[cfg(target_arch = "wasm32")]
pub(crate) use wasm::{build_transport, init_logger, sleep, swarm_builder, Instant, RedisClient};
type BoxedTransport = Boxed<(PeerId, StreamMuxerBox)>;
pub(crate) use wasm::{build_swarm, init_logger, sleep, Instant, RedisClient};
#[cfg(not(target_arch = "wasm32"))]
pub(crate) mod native {
@ -20,20 +14,15 @@ pub(crate) mod native {
use env_logger::{Env, Target};
use futures::future::BoxFuture;
use futures::FutureExt;
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::upgrade::Version;
use libp2p::identity::Keypair;
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder};
use libp2p::websocket::WsConfig;
use libp2p::{noise, quic, tcp, tls, yamux, PeerId, Transport as _};
use libp2p::swarm::{NetworkBehaviour, Swarm};
use libp2p::{noise, tcp, tls, yamux};
use libp2p_mplex as mplex;
use libp2p_webrtc as webrtc;
use redis::AsyncCommands;
use crate::{Muxer, SecProtocol, Transport};
use super::BoxedTransport;
pub(crate) type Instant = std::time::Instant;
pub(crate) fn init_logger() {
@ -46,128 +35,132 @@ pub(crate) mod native {
tokio::time::sleep(duration).boxed()
}
pub(crate) fn build_transport(
local_key: Keypair,
pub(crate) async fn build_swarm<B: NetworkBehaviour>(
ip: &str,
transport: Transport,
sec_protocol: Option<SecProtocol>,
muxer: Option<Muxer>,
) -> Result<(BoxedTransport, String)> {
let (transport, addr) = match (transport, sec_protocol, muxer) {
(Transport::QuicV1, _, _) => (
quic::tokio::Transport::new(quic::Config::new(&local_key))
.map(|(p, c), _| (p, StreamMuxerBox::new(c)))
.boxed(),
behaviour_constructor: impl FnOnce(&Keypair) -> B,
) -> Result<(Swarm<B>, String)> {
let (swarm, addr) = match (transport, sec_protocol, muxer) {
(Transport::QuicV1, None, None) => (
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_quic()
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/udp/0/quic-v1"),
),
(Transport::Tcp, Some(SecProtocol::Tls), Some(Muxer::Mplex)) => (
tcp::tokio::Transport::new(tcp::Config::new())
.upgrade(Version::V1Lazy)
.authenticate(tls::Config::new(&local_key).context("failed to initialise tls")?)
.multiplex(mplex::MplexConfig::new())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
tls::Config::new,
mplex::MplexConfig::default,
)?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0"),
),
(Transport::Tcp, Some(SecProtocol::Tls), Some(Muxer::Yamux)) => (
tcp::tokio::Transport::new(tcp::Config::new())
.upgrade(Version::V1Lazy)
.authenticate(tls::Config::new(&local_key).context("failed to initialise tls")?)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
tls::Config::new,
yamux::Config::default,
)?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0"),
),
(Transport::Tcp, Some(SecProtocol::Noise), Some(Muxer::Mplex)) => (
tcp::tokio::Transport::new(tcp::Config::new())
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to intialise noise")?,
)
.multiplex(mplex::MplexConfig::new())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
mplex::MplexConfig::default,
)?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0"),
),
(Transport::Tcp, Some(SecProtocol::Noise), Some(Muxer::Yamux)) => (
tcp::tokio::Transport::new(tcp::Config::new())
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to intialise noise")?,
)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0"),
),
(Transport::Ws, Some(SecProtocol::Tls), Some(Muxer::Mplex)) => (
WsConfig::new(tcp::tokio::Transport::new(tcp::Config::new()))
.upgrade(Version::V1Lazy)
.authenticate(tls::Config::new(&local_key).context("failed to initialise tls")?)
.multiplex(mplex::MplexConfig::new())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_websocket(tls::Config::new, mplex::MplexConfig::default)
.await?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/ws"),
),
(Transport::Ws, Some(SecProtocol::Tls), Some(Muxer::Yamux)) => (
WsConfig::new(tcp::tokio::Transport::new(tcp::Config::new()))
.upgrade(Version::V1Lazy)
.authenticate(
tls::Config::new(&local_key).context("failed to intialise noise")?,
)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_websocket(tls::Config::new, yamux::Config::default)
.await?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/ws"),
),
(Transport::Ws, Some(SecProtocol::Noise), Some(Muxer::Mplex)) => (
WsConfig::new(tcp::tokio::Transport::new(tcp::Config::new()))
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to initialise tls")?,
)
.multiplex(mplex::MplexConfig::new())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_websocket(noise::Config::new, mplex::MplexConfig::default)
.await?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/ws"),
),
(Transport::Ws, Some(SecProtocol::Noise), Some(Muxer::Yamux)) => (
WsConfig::new(tcp::tokio::Transport::new(tcp::Config::new()))
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to intialise noise")?,
)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_websocket(noise::Config::new, yamux::Config::default)
.await?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/ws"),
),
(Transport::WebRtcDirect, _, _) => (
webrtc::tokio::Transport::new(
local_key,
webrtc::tokio::Certificate::generate(&mut rand::thread_rng())?,
)
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn)))
.boxed(),
(Transport::WebRtcDirect, None, None) => (
libp2p::SwarmBuilder::with_new_identity()
.with_tokio()
.with_other_transport(|key| {
Ok(webrtc::tokio::Transport::new(
key.clone(),
webrtc::tokio::Certificate::generate(&mut rand::thread_rng())?,
))
})?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/udp/0/webrtc-direct"),
),
(Transport::Webtransport, _, _) => bail!("Webtransport can only be used with wasm"),
(Transport::Tcp | Transport::Ws, None, _) => {
bail!("Missing security protocol for {transport:?}")
}
(Transport::Tcp | Transport::Ws, _, None) => {
bail!("Missing muxer protocol for {transport:?}")
}
(t, s, m) => bail!("Unsupported combination: {t:?} {s:?} {m:?}"),
};
Ok((transport, addr))
}
pub(crate) fn swarm_builder<TBehaviour: NetworkBehaviour>(
transport: BoxedTransport,
behaviour: TBehaviour,
peer_id: PeerId,
) -> SwarmBuilder<TBehaviour> {
SwarmBuilder::with_tokio_executor(transport, behaviour, peer_id)
Ok((swarm, addr))
}
pub(crate) struct RedisClient(redis::Client);
@ -198,16 +191,14 @@ pub(crate) mod wasm {
use futures::future::{BoxFuture, FutureExt};
use libp2p::core::upgrade::Version;
use libp2p::identity::Keypair;
use libp2p::swarm::{NetworkBehaviour, SwarmBuilder};
use libp2p::{noise, yamux, PeerId, Transport as _};
use libp2p::swarm::{NetworkBehaviour, Swarm};
use libp2p::{noise, websocket_websys, webtransport_websys, yamux, Transport as _};
use libp2p_mplex as mplex;
use libp2p_webrtc_websys as webrtc;
use libp2p_webrtc_websys as webrtc_websys;
use std::time::Duration;
use crate::{BlpopRequest, Muxer, SecProtocol, Transport};
use super::BoxedTransport;
pub(crate) type Instant = instant::Instant;
pub(crate) fn init_logger() {
@ -219,70 +210,76 @@ pub(crate) mod wasm {
futures_timer::Delay::new(duration).boxed()
}
pub(crate) fn build_transport(
local_key: Keypair,
pub(crate) async fn build_swarm<B: NetworkBehaviour>(
ip: &str,
transport: Transport,
sec_protocol: Option<SecProtocol>,
muxer: Option<Muxer>,
) -> Result<(BoxedTransport, String)> {
behaviour_constructor: impl FnOnce(&Keypair) -> B,
) -> Result<(Swarm<B>, String)> {
Ok(match (transport, sec_protocol, muxer) {
(Transport::Webtransport, _, _) => (
libp2p::webtransport_websys::Transport::new(
libp2p::webtransport_websys::Config::new(&local_key),
)
.boxed(),
(Transport::Webtransport, None, None) => (
libp2p::SwarmBuilder::with_new_identity()
.with_wasm_bindgen()
.with_other_transport(|local_key| {
webtransport_websys::Transport::new(webtransport_websys::Config::new(
&local_key,
))
})?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/udp/0/quic/webtransport"),
),
(Transport::Ws, Some(SecProtocol::Noise), Some(Muxer::Mplex)) => (
libp2p::websocket_websys::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to initialise noise")?,
)
.multiplex(mplex::MplexConfig::new())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_wasm_bindgen()
.with_other_transport(|local_key| {
Ok(websocket_websys::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key)
.context("failed to initialise noise")?,
)
.multiplex(mplex::MplexConfig::new()))
})?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/wss"),
),
(Transport::Ws, Some(SecProtocol::Noise), Some(Muxer::Yamux)) => (
libp2p::websocket_websys::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key).context("failed to initialise noise")?,
)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(5))
.boxed(),
libp2p::SwarmBuilder::with_new_identity()
.with_wasm_bindgen()
.with_other_transport(|local_key| {
Ok(websocket_websys::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(
noise::Config::new(&local_key)
.context("failed to initialise noise")?,
)
.multiplex(yamux::Config::default()))
})?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/tcp/0/wss"),
),
(Transport::Ws, None, _) => {
bail!("Missing security protocol for WS")
}
(Transport::Ws, Some(SecProtocol::Tls), _) => {
bail!("TLS not supported in WASM")
}
(Transport::Ws, _, None) => {
bail!("Missing muxer protocol for WS")
}
(Transport::WebRtcDirect, _, _) => (
webrtc::Transport::new(webrtc::Config::new(&local_key)).boxed(),
(Transport::WebRtcDirect, None, None) => (
libp2p::SwarmBuilder::with_new_identity()
.with_wasm_bindgen()
.with_other_transport(|local_key| {
webrtc_websys::Transport::new(webrtc_websys::Config::new(&local_key))
})?
.with_behaviour(behaviour_constructor)?
.with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(5)))
.build(),
format!("/ip4/{ip}/udp/0/webrtc-direct"),
),
(Transport::QuicV1 | Transport::Tcp, _, _) => {
bail!("{transport:?} is not supported in WASM")
}
(t, s, m) => bail!("Unsupported combination: {t:?} {s:?} {m:?}"),
})
}
pub(crate) fn swarm_builder<TBehaviour: NetworkBehaviour>(
transport: BoxedTransport,
behaviour: TBehaviour,
peer_id: PeerId,
) -> SwarmBuilder<TBehaviour> {
SwarmBuilder::with_wasm_executor(transport, behaviour, peer_id)
}
pub(crate) struct RedisClient(String);
impl RedisClient {

View File

@ -3,14 +3,15 @@ use std::time::Duration;
use anyhow::{bail, Context, Result};
use futures::{FutureExt, StreamExt};
use libp2p::identity::Keypair;
use libp2p::swarm::SwarmEvent;
use libp2p::{identify, identity, ping, swarm::NetworkBehaviour, Multiaddr, PeerId};
use libp2p::{identify, ping, swarm::NetworkBehaviour, Multiaddr};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
mod arch;
use arch::{build_transport, init_logger, swarm_builder, Instant, RedisClient};
use arch::{build_swarm, init_logger, Instant, RedisClient};
pub async fn run_test(
transport: &str,
@ -40,37 +41,23 @@ pub async fn run_test(
})
.transpose()?;
let local_key = identity::Keypair::generate_ed25519();
let local_peer_id = PeerId::from(local_key.public());
let redis_client = RedisClient::new(redis_addr).context("Could not connect to redis")?;
// Build the transport from the passed ENV var.
let (boxed_transport, local_addr) =
build_transport(local_key.clone(), ip, transport, sec_protocol, muxer)?;
let mut swarm = swarm_builder(
boxed_transport,
Behaviour {
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(10))),
// Need to include identify until https://github.com/status-im/nim-libp2p/issues/924 is resolved.
identify: identify::Behaviour::new(identify::Config::new(
"/interop-tests".to_owned(),
local_key.public(),
)),
},
local_peer_id,
)
.idle_connection_timeout(Duration::from_secs(5))
.build();
let (mut swarm, local_addr) =
build_swarm(ip, transport, sec_protocol, muxer, build_behaviour).await?;
log::info!("Running ping test: {}", swarm.local_peer_id());
let mut maybe_id = None;
// See https://github.com/libp2p/rust-libp2p/issues/4071.
#[cfg(not(target_arch = "wasm32"))]
if transport == Transport::WebRtcDirect {
maybe_id = Some(swarm.listen_on(local_addr.parse()?)?);
}
let maybe_id = if transport == Transport::WebRtcDirect {
Some(swarm.listen_on(local_addr.parse()?)?)
} else {
None
};
#[cfg(target_arch = "wasm32")]
let maybe_id = None;
// Run a ping interop test. Based on `is_dialer`, either dial the address
// retrieved via `listenAddr` key over the redis connection. Or wait to be pinged and have
@ -129,9 +116,8 @@ pub async fn run_test(
continue;
}
if listener_id == id {
let ma = format!("{address}/p2p/{local_peer_id}");
let ma = format!("{address}/p2p/{}", swarm.local_peer_id());
redis_client.rpush("listenerAddr", ma.clone()).await?;
break;
}
}
@ -271,7 +257,18 @@ impl FromStr for SecProtocol {
}
#[derive(NetworkBehaviour)]
struct Behaviour {
pub(crate) struct Behaviour {
ping: ping::Behaviour,
identify: identify::Behaviour,
}
pub(crate) fn build_behaviour(key: &Keypair) -> Behaviour {
Behaviour {
ping: ping::Behaviour::new(ping::Config::new().with_interval(Duration::from_secs(1))),
// Need to include identify until https://github.com/status-im/nim-libp2p/issues/924 is resolved.
identify: identify::Behaviour::new(identify::Config::new(
"/interop-tests".to_owned(),
key.public(),
)),
}
}

View File

@ -4,11 +4,17 @@
This supersedes the existing `libp2p::wasm_ext` module which is now deprecated.
See [PR 3679].
- Introduce a new `libp2p::SwarmBuilder` in favor of the now deprecated `libp2p::swarm::SwarmBuilder`.
See `libp2p::SwarmBuilder` docs on how to use the new builder.
Also see [PR 4120].
- Update `libp2p-identity` version to 0.2.6.
Under the hood, we feature-flagged `libp2p-identity`'s `rand` dependency but it is enabled by default when using `libp2p`.
See [PR 4349](https://github.com/libp2p/rust-libp2p/pull/4349).
See [PR 4349].
[PR 3679]: https://github.com/libp2p/rust-libp2p/pull/3679
[PR 4120]: https://github.com/libp2p/rust-libp2p/pull/4120
[PR 4349]: https://github.com/libp2p/rust-libp2p/pull/4349
## 0.52.3

View File

@ -97,10 +97,13 @@ upnp = ["dep:libp2p-upnp"]
[dependencies]
bytes = "1"
either = "1.9.0"
futures = "0.3.26"
futures-timer = "3.0.2" # Explicit dependency to be used in `wasm-bindgen` feature
getrandom = "0.2.3" # Explicit dependency to be used in `wasm-bindgen` feature
instant = "0.1.12" # Explicit dependency to be used in `wasm-bindgen` feature
# TODO feature flag?
rw-stream-sink = { workspace = true }
libp2p-allow-block-list = { workspace = true }
libp2p-autonat = { workspace = true, optional = true }
@ -127,6 +130,7 @@ libp2p-webtransport-websys = { workspace = true, optional = true }
libp2p-yamux = { workspace = true, optional = true }
multiaddr = { workspace = true }
pin-project = "1.0.0"
thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libp2p-deflate = { workspace = true, optional = true }
@ -148,6 +152,7 @@ env_logger = "0.10.0"
clap = { version = "4.1.6", features = ["derive"] }
tokio = { version = "1.15", features = [ "io-util", "io-std", "macros", "rt", "rt-multi-thread"] }
libp2p-mplex = { workspace = true }
libp2p-noise = { workspace = true }
libp2p-tcp = { workspace = true, features = ["tokio"] }

322
libp2p/src/builder.rs Normal file
View File

@ -0,0 +1,322 @@
use std::marker::PhantomData;
mod phase;
mod select_security;
/// Build a [`Swarm`](libp2p_swarm::Swarm) by combining an identity, a set of
/// [`Transport`](libp2p_core::Transport)s and a
/// [`NetworkBehaviour`](libp2p_swarm::NetworkBehaviour).
///
/// ```
/// # use libp2p::{swarm::NetworkBehaviour, SwarmBuilder};
/// # use libp2p::core::transport::dummy::DummyTransport;
/// # use libp2p::core::muxing::StreamMuxerBox;
/// # use libp2p::identity::PeerId;
/// # use std::error::Error;
/// #
/// # #[cfg(all(
/// # not(target_arch = "wasm32"),
/// # feature = "tokio",
/// # feature = "tcp",
/// # feature = "tls",
/// # feature = "noise",
/// # feature = "quic",
/// # feature = "dns",
/// # feature = "relay",
/// # feature = "websocket",
/// # ))]
/// # async fn build_swarm() -> Result<(), Box<dyn Error>> {
/// # #[derive(NetworkBehaviour)]
/// # #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
/// # struct MyBehaviour {
/// # relay: libp2p_relay::client::Behaviour,
/// # }
///
/// let swarm = SwarmBuilder::with_new_identity()
/// .with_tokio()
/// .with_tcp(
/// Default::default(),
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )?
/// .with_quic()
/// .with_other_transport(|_key| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
/// .with_dns()?
/// .with_relay_client(
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )?
/// .with_websocket(
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )
/// .await?
/// .with_behaviour(|_key, relay| MyBehaviour { relay })?
/// .build();
/// #
/// # Ok(())
/// # }
/// ```
pub struct SwarmBuilder<Provider, Phase> {
keypair: libp2p_identity::Keypair,
phantom: PhantomData<Provider>,
phase: Phase,
}
#[cfg(test)]
mod tests {
use crate::SwarmBuilder;
use libp2p_swarm::{NetworkBehaviour, Swarm};
#[test]
#[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "noise"))]
fn tcp() {
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
libp2p_tls::Config::new,
libp2p_yamux::Config::default,
)
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[test]
#[cfg(all(
feature = "async-std",
feature = "tcp",
feature = "tls",
feature = "noise"
))]
fn async_std_tcp() {
let _ = SwarmBuilder::with_new_identity()
.with_async_std()
.with_tcp(
Default::default(),
libp2p_tls::Config::new,
libp2p_yamux::Config::default,
)
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[test]
#[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "mplex"))]
fn tcp_yamux_mplex() {
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
libp2p_tls::Config::new,
(
libp2p_yamux::Config::default(),
libp2p_mplex::MplexConfig::default(),
),
)
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[test]
#[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "noise"))]
fn tcp_tls_noise() {
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
(libp2p_tls::Config::new, libp2p_noise::Config::new),
(
libp2p_yamux::Config::default,
libp2p_mplex::MplexConfig::default,
),
)
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[test]
#[cfg(all(
feature = "tokio",
feature = "tcp",
feature = "tls",
feature = "noise",
feature = "quic"
))]
fn tcp_quic() {
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
(libp2p_tls::Config::new, libp2p_noise::Config::new),
libp2p_yamux::Config::default,
)
.unwrap()
.with_quic()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[test]
#[cfg(all(
feature = "tokio",
feature = "tcp",
feature = "tls",
feature = "noise",
feature = "relay"
))]
fn tcp_relay() {
#[derive(libp2p_swarm::NetworkBehaviour)]
#[behaviour(prelude = "libp2p_swarm::derive_prelude")]
struct Behaviour {
dummy: libp2p_swarm::dummy::Behaviour,
relay: libp2p_relay::client::Behaviour,
}
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
libp2p_tls::Config::new,
libp2p_yamux::Config::default,
)
.unwrap()
.with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
.unwrap()
.with_behaviour(|_, relay| Behaviour {
dummy: libp2p_swarm::dummy::Behaviour,
relay,
})
.unwrap()
.build();
}
#[tokio::test]
#[cfg(all(
feature = "tokio",
feature = "tcp",
feature = "tls",
feature = "noise",
feature = "dns"
))]
async fn tcp_dns() {
SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
(libp2p_tls::Config::new, libp2p_noise::Config::new),
libp2p_yamux::Config::default,
)
.unwrap()
.with_dns()
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
/// Showcases how to provide custom transports unknown to the libp2p crate, e.g. WebRTC.
#[test]
#[cfg(feature = "tokio")]
fn other_transport() -> Result<(), Box<dyn std::error::Error>> {
use libp2p_core::{muxing::StreamMuxerBox, transport::dummy::DummyTransport};
use libp2p_identity::PeerId;
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
// Closure can either return a Transport directly.
.with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
// Or a Result containing a Transport.
.with_other_transport(|_| {
if true {
Ok(DummyTransport::<(PeerId, StreamMuxerBox)>::new())
} else {
Err(Box::from("test"))
}
})?
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
Ok(())
}
#[tokio::test]
#[cfg(all(
feature = "tokio",
feature = "tcp",
feature = "tls",
feature = "noise",
feature = "dns",
feature = "websocket",
))]
async fn tcp_websocket() {
let _ = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
(libp2p_tls::Config::new, libp2p_noise::Config::new),
libp2p_yamux::Config::default,
)
.unwrap()
.with_websocket(
(libp2p_tls::Config::new, libp2p_noise::Config::new),
libp2p_yamux::Config::default,
)
.await
.unwrap()
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
.unwrap()
.build();
}
#[tokio::test]
#[cfg(all(
feature = "tokio",
feature = "tcp",
feature = "tls",
feature = "noise",
feature = "quic",
feature = "dns",
feature = "relay",
feature = "websocket",
))]
async fn all() {
#[derive(NetworkBehaviour)]
#[behaviour(prelude = "libp2p_swarm::derive_prelude")]
struct MyBehaviour {
relay: libp2p_relay::client::Behaviour,
}
let (builder, _bandwidth_sinks) = SwarmBuilder::with_new_identity()
.with_tokio()
.with_tcp(
Default::default(),
libp2p_tls::Config::new,
libp2p_yamux::Config::default,
)
.unwrap()
.with_quic()
.with_dns()
.unwrap()
.with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
.unwrap()
.with_websocket(libp2p_tls::Config::new, libp2p_yamux::Config::default)
.await
.unwrap()
.with_bandwidth_logging();
let _: Swarm<MyBehaviour> = builder
.with_behaviour(|_key, relay| MyBehaviour { relay })
.unwrap()
.build();
}
}

134
libp2p/src/builder/phase.rs Normal file
View File

@ -0,0 +1,134 @@
#![allow(unused_imports)]
mod bandwidth_logging;
mod behaviour;
mod build;
mod dns;
mod identity;
mod other_transport;
mod provider;
mod quic;
mod relay;
mod swarm;
mod tcp;
mod websocket;
use bandwidth_logging::*;
use behaviour::*;
use build::*;
use dns::*;
use other_transport::*;
use provider::*;
use quic::*;
use relay::*;
use swarm::*;
use tcp::*;
use websocket::*;
use super::select_security::SelectSecurityUpgrade;
use super::SwarmBuilder;
use libp2p_core::{muxing::StreamMuxerBox, upgrade::SelectUpgrade, Transport};
use libp2p_identity::Keypair;
pub trait IntoSecurityUpgrade<C> {
type Upgrade;
type Error;
fn into_security_upgrade(self, keypair: &Keypair) -> Result<Self::Upgrade, Self::Error>;
}
impl<C, T, F, E> IntoSecurityUpgrade<C> for F
where
F: for<'a> FnOnce(&'a Keypair) -> Result<T, E>,
{
type Upgrade = T;
type Error = E;
fn into_security_upgrade(self, keypair: &Keypair) -> Result<Self::Upgrade, Self::Error> {
(self)(keypair)
}
}
impl<F1, F2, C> IntoSecurityUpgrade<C> for (F1, F2)
where
F1: IntoSecurityUpgrade<C>,
F2: IntoSecurityUpgrade<C>,
{
type Upgrade = SelectSecurityUpgrade<F1::Upgrade, F2::Upgrade>;
type Error = either::Either<F1::Error, F2::Error>;
fn into_security_upgrade(self, keypair: &Keypair) -> Result<Self::Upgrade, Self::Error> {
let (f1, f2) = self;
let u1 = f1
.into_security_upgrade(keypair)
.map_err(either::Either::Left)?;
let u2 = f2
.into_security_upgrade(keypair)
.map_err(either::Either::Right)?;
Ok(SelectSecurityUpgrade::new(u1, u2))
}
}
pub trait IntoMultiplexerUpgrade<C> {
type Upgrade;
fn into_multiplexer_upgrade(self) -> Self::Upgrade;
}
impl<C, U, F> IntoMultiplexerUpgrade<C> for F
where
F: FnOnce() -> U,
{
type Upgrade = U;
fn into_multiplexer_upgrade(self) -> Self::Upgrade {
(self)()
}
}
impl<C, U1, U2> IntoMultiplexerUpgrade<C> for (U1, U2)
where
U1: IntoMultiplexerUpgrade<C>,
U2: IntoMultiplexerUpgrade<C>,
{
type Upgrade = SelectUpgrade<U1::Upgrade, U2::Upgrade>;
fn into_multiplexer_upgrade(self) -> Self::Upgrade {
let (f1, f2) = self;
let u1 = f1.into_multiplexer_upgrade();
let u2 = f2.into_multiplexer_upgrade();
SelectUpgrade::new(u1, u2)
}
}
pub trait AuthenticatedMultiplexedTransport:
Transport<
Error = Self::E,
Dial = Self::D,
ListenerUpgrade = Self::U,
Output = (libp2p_identity::PeerId, StreamMuxerBox),
> + Send
+ Unpin
+ 'static
{
type E: Send + Sync + 'static;
type D: Send;
type U: Send;
}
impl<T> AuthenticatedMultiplexedTransport for T
where
T: Transport<Output = (libp2p_identity::PeerId, StreamMuxerBox)> + Send + Unpin + 'static,
<T as Transport>::Error: Send + Sync + 'static,
<T as Transport>::Dial: Send,
<T as Transport>::ListenerUpgrade: Send,
{
type E = T::Error;
type D = T::Dial;
type U = T::ListenerUpgrade;
}

View File

@ -0,0 +1,70 @@
use super::*;
use crate::bandwidth::BandwidthSinks;
use crate::transport_ext::TransportExt;
use crate::SwarmBuilder;
use std::marker::PhantomData;
use std::sync::Arc;
pub struct BandwidthLoggingPhase<T, R> {
pub(crate) relay_behaviour: R,
pub(crate) transport: T,
}
impl<T: AuthenticatedMultiplexedTransport, Provider, R>
SwarmBuilder<Provider, BandwidthLoggingPhase<T, R>>
{
pub fn with_bandwidth_logging(
self,
) -> (
SwarmBuilder<Provider, BehaviourPhase<impl AuthenticatedMultiplexedTransport, R>>,
Arc<BandwidthSinks>,
) {
let (transport, sinks) = self.phase.transport.with_bandwidth_logging();
(
SwarmBuilder {
phase: BehaviourPhase {
relay_behaviour: self.phase.relay_behaviour,
transport,
},
keypair: self.keypair,
phantom: PhantomData,
},
sinks,
)
}
pub fn without_bandwidth_logging(self) -> SwarmBuilder<Provider, BehaviourPhase<T, R>> {
SwarmBuilder {
phase: BehaviourPhase {
relay_behaviour: self.phase.relay_behaviour,
transport: self.phase.transport,
},
keypair: self.keypair,
phantom: PhantomData,
}
}
}
// Shortcuts
#[cfg(feature = "relay")]
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, BandwidthLoggingPhase<T, libp2p_relay::client::Behaviour>>
{
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair, libp2p_relay::client::Behaviour) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_bandwidth_logging().with_behaviour(constructor)
}
}
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, BandwidthLoggingPhase<T, NoRelayBehaviour>>
{
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_bandwidth_logging().with_behaviour(constructor)
}
}

View File

@ -0,0 +1,90 @@
use super::*;
use crate::SwarmBuilder;
use libp2p_swarm::NetworkBehaviour;
use std::convert::Infallible;
use std::marker::PhantomData;
pub struct BehaviourPhase<T, R> {
pub(crate) relay_behaviour: R,
pub(crate) transport: T,
}
#[cfg(feature = "relay")]
impl<T, Provider> SwarmBuilder<Provider, BehaviourPhase<T, libp2p_relay::client::Behaviour>> {
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair, libp2p_relay::client::Behaviour) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
Ok(SwarmBuilder {
phase: SwarmPhase {
behaviour: constructor(&self.keypair, self.phase.relay_behaviour)
.try_into_behaviour()?,
transport: self.phase.transport,
},
keypair: self.keypair,
phantom: PhantomData,
})
}
}
impl<T, Provider> SwarmBuilder<Provider, BehaviourPhase<T, NoRelayBehaviour>> {
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
// Discard `NoRelayBehaviour`.
let _ = self.phase.relay_behaviour;
Ok(SwarmBuilder {
phase: SwarmPhase {
behaviour: constructor(&self.keypair).try_into_behaviour()?,
transport: self.phase.transport,
},
keypair: self.keypair,
phantom: PhantomData,
})
}
}
pub trait TryIntoBehaviour<B>: private::Sealed<Self::Error> {
type Error;
fn try_into_behaviour(self) -> Result<B, Self::Error>;
}
impl<B> TryIntoBehaviour<B> for B
where
B: NetworkBehaviour,
{
type Error = Infallible;
fn try_into_behaviour(self) -> Result<B, Self::Error> {
Ok(self)
}
}
impl<B> TryIntoBehaviour<B> for Result<B, Box<dyn std::error::Error + Send + Sync>>
where
B: NetworkBehaviour,
{
type Error = BehaviourError;
fn try_into_behaviour(self) -> Result<B, Self::Error> {
self.map_err(BehaviourError)
}
}
mod private {
pub trait Sealed<Error> {}
}
impl<B: NetworkBehaviour> private::Sealed<Infallible> for B {}
impl<B: NetworkBehaviour> private::Sealed<BehaviourError>
for Result<B, Box<dyn std::error::Error + Send + Sync>>
{
}
#[derive(Debug, thiserror::Error)]
#[error("failed to build behaviour: {0}")]
pub struct BehaviourError(Box<dyn std::error::Error + Send + Sync + 'static>);

View File

@ -0,0 +1,31 @@
#[allow(unused_imports)]
use super::*;
use crate::SwarmBuilder;
use libp2p_core::Transport;
use libp2p_swarm::Swarm;
pub struct BuildPhase<T, B> {
pub(crate) behaviour: B,
pub(crate) transport: T,
pub(crate) swarm_config: libp2p_swarm::Config,
}
const CONNECTION_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
impl<Provider, T: AuthenticatedMultiplexedTransport, B: libp2p_swarm::NetworkBehaviour>
SwarmBuilder<Provider, BuildPhase<T, B>>
{
pub fn build(self) -> Swarm<B> {
Swarm::new(
libp2p_core::transport::timeout::TransportTimeout::new(
self.phase.transport,
CONNECTION_TIMEOUT,
)
.boxed(),
self.phase.behaviour,
self.keypair.public().to_peer_id(),
self.phase.swarm_config,
)
}
}

View File

@ -0,0 +1,68 @@
use super::*;
use crate::SwarmBuilder;
use std::marker::PhantomData;
pub struct DnsPhase<T> {
pub(crate) transport: T,
}
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<super::provider::AsyncStd, DnsPhase<T>> {
pub async fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::AsyncStd, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
Ok(SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: RelayPhase {
transport: libp2p_dns::async_std::Transport::system(self.phase.transport).await?,
},
})
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<super::provider::Tokio, DnsPhase<T>> {
pub fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::Tokio, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
Ok(SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: RelayPhase {
transport: libp2p_dns::tokio::Transport::system(self.phase.transport)?,
},
})
}
}
impl<Provider, T> SwarmBuilder<Provider, DnsPhase<T>> {
pub(crate) fn without_dns(self) -> SwarmBuilder<Provider, RelayPhase<T>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: RelayPhase {
transport: self.phase.transport,
},
}
}
}
// Shortcuts
impl<Provider, T: AuthenticatedMultiplexedTransport> SwarmBuilder<Provider, DnsPhase<T>> {
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_dns()
.without_relay()
.without_websocket()
.with_behaviour(constructor)
}
}

View File

@ -0,0 +1,21 @@
use super::*;
use crate::SwarmBuilder;
use std::marker::PhantomData;
pub struct IdentityPhase {}
impl SwarmBuilder<NoProviderSpecified, IdentityPhase> {
pub fn with_new_identity() -> SwarmBuilder<NoProviderSpecified, ProviderPhase> {
SwarmBuilder::with_existing_identity(libp2p_identity::Keypair::generate_ed25519())
}
pub fn with_existing_identity(
keypair: libp2p_identity::Keypair,
) -> SwarmBuilder<NoProviderSpecified, ProviderPhase> {
SwarmBuilder {
keypair,
phantom: PhantomData,
phase: ProviderPhase {},
}
}
}

View File

@ -0,0 +1,208 @@
use std::convert::Infallible;
use std::marker::PhantomData;
use std::sync::Arc;
use libp2p_core::Transport;
#[cfg(feature = "relay")]
use libp2p_core::{InboundUpgrade, Negotiated, OutboundUpgrade, UpgradeInfo};
#[cfg(feature = "relay")]
use libp2p_identity::PeerId;
use crate::bandwidth::BandwidthSinks;
use crate::SwarmBuilder;
use super::*;
pub struct OtherTransportPhase<T> {
pub(crate) transport: T,
}
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, OtherTransportPhase<T>>
{
pub fn with_other_transport<
Muxer: libp2p_core::muxing::StreamMuxer + Send + 'static,
OtherTransport: Transport<Output = (libp2p_identity::PeerId, Muxer)> + Send + Unpin + 'static,
R: TryIntoTransport<OtherTransport>,
>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<
SwarmBuilder<Provider, OtherTransportPhase<impl AuthenticatedMultiplexedTransport>>,
R::Error,
>
where
<OtherTransport as Transport>::Error: Send + Sync + 'static,
<OtherTransport as Transport>::Dial: Send,
<OtherTransport as Transport>::ListenerUpgrade: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Substream: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Error: Send + Sync,
{
Ok(SwarmBuilder {
phase: OtherTransportPhase {
transport: self
.phase
.transport
.or_transport(
constructor(&self.keypair)
.try_into_transport()?
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))),
)
.map(|either, _| either.into_inner()),
},
keypair: self.keypair,
phantom: PhantomData,
})
}
pub(crate) fn without_any_other_transports(self) -> SwarmBuilder<Provider, DnsPhase<T>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: DnsPhase {
transport: self.phase.transport,
},
}
}
}
// Shortcuts
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport>
SwarmBuilder<super::provider::AsyncStd, OtherTransportPhase<T>>
{
pub async fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::AsyncStd, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
self.without_any_other_transports().with_dns().await
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport>
SwarmBuilder<super::provider::Tokio, OtherTransportPhase<T>>
{
pub fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::Tokio, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
self.without_any_other_transports().with_dns()
}
}
#[cfg(feature = "relay")]
impl<T: AuthenticatedMultiplexedTransport, Provider>
SwarmBuilder<Provider, OtherTransportPhase<T>>
{
/// See [`SwarmBuilder::with_relay_client`].
pub fn with_relay_client<SecUpgrade, SecStream, SecError, MuxUpgrade, MuxStream, MuxError>(
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
Provider,
WebsocketPhase<impl AuthenticatedMultiplexedTransport, libp2p_relay::client::Behaviour>,
>,
SecUpgrade::Error,
> where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<libp2p_relay::client::Connection>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: libp2p_core::muxing::StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
self.without_any_other_transports()
.without_dns()
.with_relay_client(security_upgrade, multiplexer_upgrade)
}
}
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, OtherTransportPhase<T>>
{
pub fn with_bandwidth_logging(
self,
) -> (
SwarmBuilder<
Provider,
BehaviourPhase<impl AuthenticatedMultiplexedTransport, NoRelayBehaviour>,
>,
Arc<BandwidthSinks>,
) {
self.without_any_other_transports()
.without_dns()
.without_relay()
.without_websocket()
.with_bandwidth_logging()
}
}
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, OtherTransportPhase<T>>
{
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_any_other_transports()
.without_dns()
.without_relay()
.without_websocket()
.without_bandwidth_logging()
.with_behaviour(constructor)
}
}
pub trait TryIntoTransport<T>: private::Sealed<Self::Error> {
type Error;
fn try_into_transport(self) -> Result<T, Self::Error>;
}
impl<T: Transport> TryIntoTransport<T> for T {
type Error = Infallible;
fn try_into_transport(self) -> Result<T, Self::Error> {
Ok(self)
}
}
impl<T: Transport> TryIntoTransport<T> for Result<T, Box<dyn std::error::Error + Send + Sync>> {
type Error = TransportError;
fn try_into_transport(self) -> Result<T, Self::Error> {
self.map_err(TransportError)
}
}
mod private {
pub trait Sealed<Error> {}
}
impl<T: Transport> private::Sealed<Infallible> for T {}
impl<T: Transport> private::Sealed<TransportError>
for Result<T, Box<dyn std::error::Error + Send + Sync>>
{
}
#[derive(Debug, thiserror::Error)]
#[error("failed to build transport: {0}")]
pub struct TransportError(Box<dyn std::error::Error + Send + Sync + 'static>);

View File

@ -0,0 +1,46 @@
#[allow(unused_imports)]
use super::*;
use crate::SwarmBuilder;
pub struct ProviderPhase {}
impl SwarmBuilder<NoProviderSpecified, ProviderPhase> {
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))]
pub fn with_async_std(self) -> SwarmBuilder<AsyncStd, TcpPhase> {
SwarmBuilder {
keypair: self.keypair,
phantom: std::marker::PhantomData,
phase: TcpPhase {},
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
pub fn with_tokio(self) -> SwarmBuilder<Tokio, TcpPhase> {
SwarmBuilder {
keypair: self.keypair,
phantom: std::marker::PhantomData,
phase: TcpPhase {},
}
}
#[cfg(feature = "wasm-bindgen")]
pub fn with_wasm_bindgen(self) -> SwarmBuilder<WasmBindgen, TcpPhase> {
SwarmBuilder {
keypair: self.keypair,
phantom: std::marker::PhantomData,
phase: TcpPhase {},
}
}
}
pub enum NoProviderSpecified {}
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std"))]
pub enum AsyncStd {}
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
pub enum Tokio {}
#[cfg(feature = "wasm-bindgen")]
pub enum WasmBindgen {}

View File

@ -0,0 +1,239 @@
use super::*;
use crate::SwarmBuilder;
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
use libp2p_core::muxing::StreamMuxer;
#[cfg(any(
feature = "relay",
all(not(target_arch = "wasm32"), feature = "websocket")
))]
use libp2p_core::{InboundUpgrade, Negotiated, OutboundUpgrade, UpgradeInfo};
use std::marker::PhantomData;
pub struct QuicPhase<T> {
pub(crate) transport: T,
}
macro_rules! impl_quic_builder {
($providerKebabCase:literal, $providerPascalCase:ty, $quic:ident) => {
#[cfg(all(not(target_arch = "wasm32"), feature = "quic", feature = $providerKebabCase))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<$providerPascalCase, QuicPhase<T>> {
pub fn with_quic(
self,
) -> SwarmBuilder<
$providerPascalCase,
OtherTransportPhase<impl AuthenticatedMultiplexedTransport>,
> {
self.with_quic_config(std::convert::identity)
}
pub fn with_quic_config(
self,
constructor: impl FnOnce(libp2p_quic::Config) -> libp2p_quic::Config,
) -> SwarmBuilder<
$providerPascalCase,
OtherTransportPhase<impl AuthenticatedMultiplexedTransport>,
> {
SwarmBuilder {
phase: OtherTransportPhase {
transport: self
.phase
.transport
.or_transport(
libp2p_quic::$quic::Transport::new(constructor(
libp2p_quic::Config::new(&self.keypair),
))
.map(|(peer_id, muxer), _| {
(peer_id, libp2p_core::muxing::StreamMuxerBox::new(muxer))
}),
)
.map(|either, _| either.into_inner()),
},
keypair: self.keypair,
phantom: PhantomData,
}
}
}
};
}
impl_quic_builder!("async-std", AsyncStd, async_std);
impl_quic_builder!("tokio", super::provider::Tokio, tokio);
impl<Provider, T> SwarmBuilder<Provider, QuicPhase<T>> {
pub(crate) fn without_quic(self) -> SwarmBuilder<Provider, OtherTransportPhase<T>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: OtherTransportPhase {
transport: self.phase.transport,
},
}
}
}
// Shortcuts
impl<Provider, T: AuthenticatedMultiplexedTransport> SwarmBuilder<Provider, QuicPhase<T>> {
/// See [`SwarmBuilder::with_relay_client`].
#[cfg(feature = "relay")]
pub fn with_relay_client<SecUpgrade, SecStream, SecError, MuxUpgrade, MuxStream, MuxError>(
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
Provider,
super::websocket::WebsocketPhase<impl AuthenticatedMultiplexedTransport, libp2p_relay::client::Behaviour>,
>,
SecUpgrade::Error,
> where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<libp2p_relay::client::Connection>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: libp2p_core::muxing::StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
self.without_quic()
.with_relay_client(security_upgrade, multiplexer_upgrade)
}
pub fn with_other_transport<
Muxer: libp2p_core::muxing::StreamMuxer + Send + 'static,
OtherTransport: Transport<Output = (libp2p_identity::PeerId, Muxer)> + Send + Unpin + 'static,
R: TryIntoTransport<OtherTransport>,
>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<
SwarmBuilder<Provider, OtherTransportPhase<impl AuthenticatedMultiplexedTransport>>,
R::Error,
>
where
<OtherTransport as Transport>::Error: Send + Sync + 'static,
<OtherTransport as Transport>::Dial: Send,
<OtherTransport as Transport>::ListenerUpgrade: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Substream: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Error: Send + Sync,
{
self.without_quic().with_other_transport(constructor)
}
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_quic()
.without_any_other_transports()
.without_dns()
.without_relay()
.without_websocket()
.with_behaviour(constructor)
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "async-std", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<super::provider::AsyncStd, QuicPhase<T>> {
pub async fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::AsyncStd, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
self.without_quic()
.without_any_other_transports()
.with_dns()
.await
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio", feature = "dns"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<super::provider::Tokio, QuicPhase<T>> {
pub fn with_dns(
self,
) -> Result<
SwarmBuilder<super::provider::Tokio, RelayPhase<impl AuthenticatedMultiplexedTransport>>,
std::io::Error,
> {
self.without_quic()
.without_any_other_transports()
.with_dns()
}
}
macro_rules! impl_quic_phase_with_websocket {
($providerKebabCase:literal, $providerPascalCase:ty, $websocketStream:ty) => {
#[cfg(all(feature = $providerKebabCase, not(target_arch = "wasm32"), feature = "websocket"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<$providerPascalCase, QuicPhase<T>> {
/// See [`SwarmBuilder::with_websocket`].
pub async fn with_websocket <
SecUpgrade,
SecStream,
SecError,
MuxUpgrade,
MuxStream,
MuxError,
> (
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
$providerPascalCase,
BandwidthLoggingPhase<impl AuthenticatedMultiplexedTransport, NoRelayBehaviour>,
>,
super::websocket::WebsocketError<SecUpgrade::Error>,
>
where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<$websocketStream>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
self.without_quic()
.without_any_other_transports()
.without_dns()
.without_relay()
.with_websocket(security_upgrade, multiplexer_upgrade)
.await
}
}
}
}
impl_quic_phase_with_websocket!(
"async-std",
super::provider::AsyncStd,
rw_stream_sink::RwStreamSink<
libp2p_websocket::BytesConnection<libp2p_tcp::async_io::TcpStream>,
>
);
impl_quic_phase_with_websocket!(
"tokio",
super::provider::Tokio,
rw_stream_sink::RwStreamSink<libp2p_websocket::BytesConnection<libp2p_tcp::tokio::TcpStream>>
);

View File

@ -0,0 +1,192 @@
use std::marker::PhantomData;
#[cfg(feature = "relay")]
use libp2p_core::muxing::StreamMuxerBox;
#[cfg(feature = "relay")]
use libp2p_core::Transport;
#[cfg(any(feature = "relay", feature = "websocket"))]
use libp2p_core::{InboundUpgrade, Negotiated, OutboundUpgrade, StreamMuxer, UpgradeInfo};
#[cfg(feature = "relay")]
use libp2p_identity::PeerId;
use crate::SwarmBuilder;
use super::*;
pub struct RelayPhase<T> {
pub(crate) transport: T,
}
#[cfg(feature = "relay")]
impl<Provider, T: AuthenticatedMultiplexedTransport> SwarmBuilder<Provider, RelayPhase<T>> {
/// Adds a relay client transport.
///
/// Note that both `security_upgrade` and `multiplexer_upgrade` take function pointers,
/// i.e. they take the function themselves (without the invocation via `()`), not the
/// result of the function invocation. See example below.
///
/// ``` rust
/// # use libp2p::SwarmBuilder;
/// # use std::error::Error;
/// # async fn build_swarm() -> Result<(), Box<dyn Error>> {
/// let swarm = SwarmBuilder::with_new_identity()
/// .with_tokio()
/// .with_tcp(
/// Default::default(),
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )?
/// .with_relay_client(
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )?
/// # ;
/// # Ok(())
/// # }
/// ```
pub fn with_relay_client<SecUpgrade, SecStream, SecError, MuxUpgrade, MuxStream, MuxError>(
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
Provider,
WebsocketPhase<impl AuthenticatedMultiplexedTransport, libp2p_relay::client::Behaviour>,
>,
SecUpgrade::Error,
> where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<libp2p_relay::client::Connection>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
let (relay_transport, relay_behaviour) =
libp2p_relay::client::new(self.keypair.public().to_peer_id());
Ok(SwarmBuilder {
phase: WebsocketPhase {
relay_behaviour,
transport: self
.phase
.transport
.or_transport(
relay_transport
.upgrade(libp2p_core::upgrade::Version::V1Lazy)
.authenticate(security_upgrade.into_security_upgrade(&self.keypair)?)
.multiplex(multiplexer_upgrade.into_multiplexer_upgrade())
.map(|(p, c), _| (p, StreamMuxerBox::new(c))),
)
.map(|either, _| either.into_inner()),
},
keypair: self.keypair,
phantom: PhantomData,
})
}
}
pub struct NoRelayBehaviour;
impl<Provider, T> SwarmBuilder<Provider, RelayPhase<T>> {
pub(crate) fn without_relay(
self,
) -> SwarmBuilder<Provider, WebsocketPhase<T, NoRelayBehaviour>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: WebsocketPhase {
transport: self.phase.transport,
relay_behaviour: NoRelayBehaviour,
},
}
}
}
// Shortcuts
impl<Provider, T: AuthenticatedMultiplexedTransport> SwarmBuilder<Provider, RelayPhase<T>> {
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_relay()
.without_websocket()
.with_behaviour(constructor)
}
}
macro_rules! impl_relay_phase_with_websocket {
($providerKebabCase:literal, $providerPascalCase:ty, $websocketStream:ty) => {
#[cfg(all(feature = $providerKebabCase, not(target_arch = "wasm32"), feature = "websocket"))]
impl<T: AuthenticatedMultiplexedTransport> SwarmBuilder<$providerPascalCase, RelayPhase<T>> {
pub async fn with_websocket <
SecUpgrade,
SecStream,
SecError,
MuxUpgrade,
MuxStream,
MuxError,
> (
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
$providerPascalCase,
BandwidthLoggingPhase<impl AuthenticatedMultiplexedTransport, NoRelayBehaviour>,
>,
super::websocket::WebsocketError<SecUpgrade::Error>,
>
where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<$websocketStream>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
self.without_relay()
.with_websocket(security_upgrade, multiplexer_upgrade)
.await
}
}
}
}
impl_relay_phase_with_websocket!(
"async-std",
super::provider::AsyncStd,
rw_stream_sink::RwStreamSink<
libp2p_websocket::BytesConnection<libp2p_tcp::async_io::TcpStream>,
>
);
impl_relay_phase_with_websocket!(
"tokio",
super::provider::Tokio,
rw_stream_sink::RwStreamSink<libp2p_websocket::BytesConnection<libp2p_tcp::tokio::TcpStream>>
);

View File

@ -0,0 +1,60 @@
#[allow(unused_imports)]
use super::*;
#[allow(dead_code)]
pub struct SwarmPhase<T, B> {
pub(crate) behaviour: B,
pub(crate) transport: T,
}
macro_rules! impl_with_swarm_config {
($providerKebabCase:literal, $providerPascalCase:ty, $config:expr) => {
#[cfg(feature = $providerKebabCase)]
impl<T, B> SwarmBuilder<$providerPascalCase, SwarmPhase<T, B>> {
pub fn with_swarm_config(
self,
constructor: impl FnOnce(libp2p_swarm::Config) -> libp2p_swarm::Config,
) -> SwarmBuilder<$providerPascalCase, BuildPhase<T, B>> {
SwarmBuilder {
phase: BuildPhase {
behaviour: self.phase.behaviour,
transport: self.phase.transport,
swarm_config: constructor($config),
},
keypair: self.keypair,
phantom: std::marker::PhantomData,
}
}
// Shortcuts
pub fn build(self) -> libp2p_swarm::Swarm<B>
where
B: libp2p_swarm::NetworkBehaviour,
T: AuthenticatedMultiplexedTransport,
{
self.with_swarm_config(std::convert::identity).build()
}
}
};
}
#[cfg(not(target_arch = "wasm32"))]
impl_with_swarm_config!(
"async-std",
super::provider::AsyncStd,
libp2p_swarm::Config::with_async_std_executor()
);
#[cfg(not(target_arch = "wasm32"))]
impl_with_swarm_config!(
"tokio",
super::provider::Tokio,
libp2p_swarm::Config::with_tokio_executor()
);
#[cfg(target_arch = "wasm32")]
impl_with_swarm_config!(
"wasm-bindgen",
super::provider::WasmBindgen,
libp2p_swarm::Config::with_wasm_executor()
);

View File

@ -0,0 +1,226 @@
use super::*;
use crate::SwarmBuilder;
#[cfg(all(
not(target_arch = "wasm32"),
any(feature = "tcp", feature = "websocket")
))]
use libp2p_core::muxing::{StreamMuxer, StreamMuxerBox};
#[cfg(all(feature = "websocket", not(target_arch = "wasm32")))]
use libp2p_core::Transport;
#[cfg(all(
not(target_arch = "wasm32"),
any(feature = "tcp", feature = "websocket")
))]
use libp2p_core::{InboundUpgrade, Negotiated, OutboundUpgrade, UpgradeInfo};
use std::marker::PhantomData;
pub struct TcpPhase {}
macro_rules! impl_tcp_builder {
($providerKebabCase:literal, $providerPascalCase:ty, $path:ident) => {
#[cfg(all(
not(target_arch = "wasm32"),
feature = "tcp",
feature = $providerKebabCase,
))]
impl SwarmBuilder<$providerPascalCase, TcpPhase> {
/// Adds a TCP based transport.
///
/// Note that both `security_upgrade` and `multiplexer_upgrade` take function pointers,
/// i.e. they take the function themselves (without the invocation via `()`), not the
/// result of the function invocation. See example below.
///
/// ``` rust
/// # use libp2p::SwarmBuilder;
/// # use std::error::Error;
/// # async fn build_swarm() -> Result<(), Box<dyn Error>> {
/// let swarm = SwarmBuilder::with_new_identity()
/// .with_tokio()
/// .with_tcp(
/// Default::default(),
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )?
/// # ;
/// # Ok(())
/// # }
/// ```
pub fn with_tcp<SecUpgrade, SecStream, SecError, MuxUpgrade, MuxStream, MuxError>(
self,
tcp_config: libp2p_tcp::Config,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<$providerPascalCase, QuicPhase<impl AuthenticatedMultiplexedTransport>>,
SecUpgrade::Error,
>
where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<libp2p_tcp::$path::TcpStream>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<libp2p_tcp::$path::TcpStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<libp2p_tcp::$path::TcpStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<libp2p_tcp::$path::TcpStream>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<libp2p_tcp::$path::TcpStream>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<libp2p_tcp::$path::TcpStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<libp2p_tcp::$path::TcpStream>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
Ok(SwarmBuilder {
phase: QuicPhase {
transport: libp2p_tcp::$path::Transport::new(tcp_config)
.upgrade(libp2p_core::upgrade::Version::V1Lazy)
.authenticate(
security_upgrade.into_security_upgrade(&self.keypair)?,
)
.multiplex(multiplexer_upgrade.into_multiplexer_upgrade())
.map(|(p, c), _| (p, StreamMuxerBox::new(c))),
},
keypair: self.keypair,
phantom: PhantomData,
})
}
}
};
}
impl_tcp_builder!("async-std", super::provider::AsyncStd, async_io);
impl_tcp_builder!("tokio", super::provider::Tokio, tokio);
impl<Provider> SwarmBuilder<Provider, TcpPhase> {
pub(crate) fn without_tcp(
self,
) -> SwarmBuilder<Provider, QuicPhase<impl AuthenticatedMultiplexedTransport>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: QuicPhase {
transport: libp2p_core::transport::dummy::DummyTransport::new(),
},
}
}
}
// Shortcuts
#[cfg(all(not(target_arch = "wasm32"), feature = "quic", feature = "async-std"))]
impl SwarmBuilder<super::provider::AsyncStd, TcpPhase> {
pub fn with_quic(
self,
) -> SwarmBuilder<
super::provider::AsyncStd,
OtherTransportPhase<impl AuthenticatedMultiplexedTransport>,
> {
self.without_tcp().with_quic()
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "quic", feature = "tokio"))]
impl SwarmBuilder<super::provider::Tokio, TcpPhase> {
pub fn with_quic(
self,
) -> SwarmBuilder<
super::provider::Tokio,
OtherTransportPhase<impl AuthenticatedMultiplexedTransport>,
> {
self.without_tcp().with_quic()
}
}
impl<Provider> SwarmBuilder<Provider, TcpPhase> {
pub fn with_other_transport<
Muxer: libp2p_core::muxing::StreamMuxer + Send + 'static,
OtherTransport: Transport<Output = (libp2p_identity::PeerId, Muxer)> + Send + Unpin + 'static,
R: TryIntoTransport<OtherTransport>,
>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<
SwarmBuilder<Provider, OtherTransportPhase<impl AuthenticatedMultiplexedTransport>>,
R::Error,
>
where
<OtherTransport as Transport>::Error: Send + Sync + 'static,
<OtherTransport as Transport>::Dial: Send,
<OtherTransport as Transport>::ListenerUpgrade: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Substream: Send,
<Muxer as libp2p_core::muxing::StreamMuxer>::Error: Send + Sync,
{
self.without_tcp()
.without_quic()
.with_other_transport(constructor)
}
}
macro_rules! impl_tcp_phase_with_websocket {
($providerKebabCase:literal, $providerPascalCase:ty, $websocketStream:ty) => {
#[cfg(all(feature = $providerKebabCase, not(target_arch = "wasm32"), feature = "websocket"))]
impl SwarmBuilder<$providerPascalCase, TcpPhase> {
/// See [`SwarmBuilder::with_websocket`].
pub async fn with_websocket <
SecUpgrade,
SecStream,
SecError,
MuxUpgrade,
MuxStream,
MuxError,
> (
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
$providerPascalCase,
BandwidthLoggingPhase<impl AuthenticatedMultiplexedTransport, NoRelayBehaviour>,
>,
WebsocketError<SecUpgrade::Error>,
>
where
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<$websocketStream>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<$websocketStream>, Output = (libp2p_identity::PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
self.without_tcp()
.without_quic()
.without_any_other_transports()
.without_dns()
.without_relay()
.with_websocket(security_upgrade, multiplexer_upgrade)
.await
}
}
}
}
impl_tcp_phase_with_websocket!(
"async-std",
super::provider::AsyncStd,
rw_stream_sink::RwStreamSink<
libp2p_websocket::BytesConnection<libp2p_tcp::async_io::TcpStream>,
>
);
impl_tcp_phase_with_websocket!(
"tokio",
super::provider::Tokio,
rw_stream_sink::RwStreamSink<libp2p_websocket::BytesConnection<libp2p_tcp::tokio::TcpStream>>
);

View File

@ -0,0 +1,188 @@
use super::*;
use crate::SwarmBuilder;
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
use libp2p_core::muxing::{StreamMuxer, StreamMuxerBox};
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
use libp2p_core::Transport;
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
use libp2p_core::{InboundUpgrade, Negotiated, OutboundUpgrade, UpgradeInfo};
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
use libp2p_identity::PeerId;
use std::marker::PhantomData;
pub struct WebsocketPhase<T, R> {
pub(crate) transport: T,
pub(crate) relay_behaviour: R,
}
macro_rules! impl_websocket_builder {
($providerKebabCase:literal, $providerPascalCase:ty, $dnsTcp:expr, $websocketStream:ty) => {
/// Adds a websocket client transport.
///
/// Note that both `security_upgrade` and `multiplexer_upgrade` take function pointers,
/// i.e. they take the function themselves (without the invocation via `()`), not the
/// result of the function invocation. See example below.
///
/// ``` rust
/// # use libp2p::SwarmBuilder;
/// # use std::error::Error;
/// # async fn build_swarm() -> Result<(), Box<dyn Error>> {
/// let swarm = SwarmBuilder::with_new_identity()
/// .with_tokio()
/// .with_websocket(
/// (libp2p_tls::Config::new, libp2p_noise::Config::new),
/// libp2p_yamux::Config::default,
/// )
/// .await?
/// # ;
/// # Ok(())
/// # }
/// ```
#[cfg(all(not(target_arch = "wasm32"), feature = $providerKebabCase, feature = "websocket"))]
impl<T, R> SwarmBuilder<$providerPascalCase, WebsocketPhase<T, R>> {
pub async fn with_websocket<
SecUpgrade,
SecStream,
SecError,
MuxUpgrade,
MuxStream,
MuxError,
>(
self,
security_upgrade: SecUpgrade,
multiplexer_upgrade: MuxUpgrade,
) -> Result<
SwarmBuilder<
$providerPascalCase,
BandwidthLoggingPhase<impl AuthenticatedMultiplexedTransport, R>,
>,
WebsocketError<SecUpgrade::Error>,
>
where
T: AuthenticatedMultiplexedTransport,
SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
SecError: std::error::Error + Send + Sync + 'static,
SecUpgrade: IntoSecurityUpgrade<$websocketStream>,
SecUpgrade::Upgrade: InboundUpgrade<Negotiated<$websocketStream>, Output = (PeerId, SecStream), Error = SecError> + OutboundUpgrade<Negotiated<$websocketStream>, Output = (PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
<SecUpgrade::Upgrade as InboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<SecUpgrade::Upgrade as OutboundUpgrade<Negotiated<$websocketStream>>>::Future: Send,
<<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<SecUpgrade as IntoSecurityUpgrade<$websocketStream>>::Upgrade as UpgradeInfo>::Info: Send,
MuxStream: StreamMuxer + Send + 'static,
MuxStream::Substream: Send + 'static,
MuxStream::Error: Send + Sync + 'static,
MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
MuxUpgrade::Upgrade: InboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
<MuxUpgrade::Upgrade as InboundUpgrade<Negotiated<SecStream>>>::Future: Send,
<MuxUpgrade::Upgrade as OutboundUpgrade<Negotiated<SecStream>>>::Future: Send,
MuxError: std::error::Error + Send + Sync + 'static,
<<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
{
let security_upgrade = security_upgrade.into_security_upgrade(&self.keypair)
.map_err(WebsocketErrorInner::SecurityUpgrade)?;
let websocket_transport = libp2p_websocket::WsConfig::new(
$dnsTcp.await.map_err(WebsocketErrorInner::Dns)?,
)
.upgrade(libp2p_core::upgrade::Version::V1Lazy)
.authenticate(security_upgrade)
.multiplex(multiplexer_upgrade.into_multiplexer_upgrade())
.map(|(p, c), _| (p, StreamMuxerBox::new(c)));
Ok(SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: BandwidthLoggingPhase {
transport: websocket_transport
.or_transport(self.phase.transport)
.map(|either, _| either.into_inner()),
relay_behaviour: self.phase.relay_behaviour,
},
})
}
}
};
}
impl_websocket_builder!(
"async-std",
super::provider::AsyncStd,
libp2p_dns::async_std::Transport::system(libp2p_tcp::async_io::Transport::new(
libp2p_tcp::Config::default(),
)),
rw_stream_sink::RwStreamSink<
libp2p_websocket::BytesConnection<libp2p_tcp::async_io::TcpStream>,
>
);
impl_websocket_builder!(
"tokio",
super::provider::Tokio,
// Note this is an unnecessary await for Tokio Websocket (i.e. tokio dns) in order to be consistent
// with above AsyncStd construction.
futures::future::ready(libp2p_dns::tokio::Transport::system(
libp2p_tcp::tokio::Transport::new(libp2p_tcp::Config::default())
)),
rw_stream_sink::RwStreamSink<libp2p_websocket::BytesConnection<libp2p_tcp::tokio::TcpStream>>
);
impl<Provider, T: AuthenticatedMultiplexedTransport, R>
SwarmBuilder<Provider, WebsocketPhase<T, R>>
{
pub(crate) fn without_websocket(self) -> SwarmBuilder<Provider, BandwidthLoggingPhase<T, R>> {
SwarmBuilder {
keypair: self.keypair,
phantom: PhantomData,
phase: BandwidthLoggingPhase {
relay_behaviour: self.phase.relay_behaviour,
transport: self.phase.transport,
},
}
}
}
// Shortcuts
#[cfg(feature = "relay")]
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, WebsocketPhase<T, libp2p_relay::client::Behaviour>>
{
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair, libp2p_relay::client::Behaviour) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_websocket()
.without_bandwidth_logging()
.with_behaviour(constructor)
}
}
impl<Provider, T: AuthenticatedMultiplexedTransport>
SwarmBuilder<Provider, WebsocketPhase<T, NoRelayBehaviour>>
{
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
self,
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
self.without_websocket()
.without_bandwidth_logging()
.with_behaviour(constructor)
}
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
pub struct WebsocketError<Sec>(#[from] WebsocketErrorInner<Sec>);
#[derive(Debug, thiserror::Error)]
#[cfg(all(not(target_arch = "wasm32"), feature = "websocket"))]
enum WebsocketErrorInner<Sec> {
#[error("SecurityUpgrade")]
SecurityUpgrade(Sec),
#[cfg(feature = "dns")]
#[error("Dns")]
Dns(#[from] std::io::Error),
}

View File

@ -0,0 +1,113 @@
// Copyright 2023 Protocol Labs.
// Copyright 2018 Parity Technologies (UK) Ltd.
//
// 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 either::Either;
use futures::future::MapOk;
use futures::{future, TryFutureExt};
use libp2p_core::either::EitherFuture;
use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use libp2p_identity::PeerId;
use std::iter::{Chain, Map};
/// Upgrade that combines two upgrades into one. Supports all the protocols supported by either
/// sub-upgrade.
///
/// The protocols supported by the first element have a higher priority.
#[derive(Debug, Clone)]
pub struct SelectSecurityUpgrade<A, B>(A, B);
impl<A, B> SelectSecurityUpgrade<A, B> {
/// Combines two upgrades into an `SelectUpgrade`.
///
/// The protocols supported by the first element have a higher priority.
pub fn new(a: A, b: B) -> Self {
SelectSecurityUpgrade(a, b)
}
}
impl<A, B> UpgradeInfo for SelectSecurityUpgrade<A, B>
where
A: UpgradeInfo,
B: UpgradeInfo,
{
type Info = Either<A::Info, B::Info>;
type InfoIter = Chain<
Map<<A::InfoIter as IntoIterator>::IntoIter, fn(A::Info) -> Self::Info>,
Map<<B::InfoIter as IntoIterator>::IntoIter, fn(B::Info) -> Self::Info>,
>;
fn protocol_info(&self) -> Self::InfoIter {
let a = self
.0
.protocol_info()
.into_iter()
.map(Either::Left as fn(A::Info) -> _);
let b = self
.1
.protocol_info()
.into_iter()
.map(Either::Right as fn(B::Info) -> _);
a.chain(b)
}
}
impl<C, A, B, TA, TB, EA, EB> InboundUpgrade<C> for SelectSecurityUpgrade<A, B>
where
A: InboundUpgrade<C, Output = (PeerId, TA), Error = EA>,
B: InboundUpgrade<C, Output = (PeerId, TB), Error = EB>,
{
type Output = (PeerId, future::Either<TA, TB>);
type Error = Either<EA, EB>;
type Future = MapOk<
EitherFuture<A::Future, B::Future>,
fn(future::Either<(PeerId, TA), (PeerId, TB)>) -> (PeerId, future::Either<TA, TB>),
>;
fn upgrade_inbound(self, sock: C, info: Self::Info) -> Self::Future {
match info {
Either::Left(info) => EitherFuture::First(self.0.upgrade_inbound(sock, info)),
Either::Right(info) => EitherFuture::Second(self.1.upgrade_inbound(sock, info)),
}
.map_ok(future::Either::factor_first)
}
}
impl<C, A, B, TA, TB, EA, EB> OutboundUpgrade<C> for SelectSecurityUpgrade<A, B>
where
A: OutboundUpgrade<C, Output = (PeerId, TA), Error = EA>,
B: OutboundUpgrade<C, Output = (PeerId, TB), Error = EB>,
{
type Output = (PeerId, future::Either<TA, TB>);
type Error = Either<EA, EB>;
type Future = MapOk<
EitherFuture<A::Future, B::Future>,
fn(future::Either<(PeerId, TA), (PeerId, TB)>) -> (PeerId, future::Either<TA, TB>),
>;
fn upgrade_outbound(self, sock: C, info: Self::Info) -> Self::Future {
match info {
Either::Left(info) => EitherFuture::First(self.0.upgrade_outbound(sock, info)),
Either::Right(info) => EitherFuture::Second(self.1.upgrade_outbound(sock, info)),
}
.map_ok(future::Either::factor_first)
}
}

View File

@ -22,8 +22,9 @@
//!
//! To learn more about the general libp2p multi-language framework visit <https://libp2p.io>.
//!
//! To get started with this libp2p implementation in Rust, please take a look at the [`tutorials`].
//! Further examples can be found in the [examples] directory.
//! To get started with this libp2p implementation in Rust, please take a look
//! at the [`tutorials`]. Further examples can be found in the
//! [examples] directory.
//!
//! [examples]: https://github.com/libp2p/rust-libp2p/tree/master/examples
@ -157,6 +158,7 @@ pub use libp2p_webtransport_websys as webtransport_websys;
#[doc(inline)]
pub use libp2p_yamux as yamux;
mod builder;
mod transport_ext;
pub mod bandwidth;
@ -164,6 +166,7 @@ pub mod bandwidth;
#[cfg(doc)]
pub mod tutorials;
pub use self::builder::SwarmBuilder;
pub use self::core::{
transport::TransportError,
upgrade::{InboundUpgrade, OutboundUpgrade},
@ -187,6 +190,7 @@ pub use libp2p_swarm::{Stream, StreamProtocol};
///
/// > **Note**: This `Transport` is not suitable for production usage, as its implementation
/// > reserves the right to support additional protocols or remove deprecated protocols.
#[deprecated(note = "Use `libp2p::SwarmBuilder` instead.")]
#[cfg(all(
not(target_arch = "wasm32"),
feature = "tcp",
@ -232,6 +236,7 @@ pub async fn development_transport(
///
/// > **Note**: This `Transport` is not suitable for production usage, as its implementation
/// > reserves the right to support additional protocols or remove deprecated protocols.
#[deprecated(note = "Use `libp2p::SwarmBuilder` instead.")]
#[cfg(all(
not(target_arch = "wasm32"),
feature = "tcp",

View File

@ -55,10 +55,10 @@
//! edition = "2021"
//!
//! [dependencies]
//! libp2p = { version = "0.50", features = ["tcp", "dns", "async-std", "noise", "yamux", "websocket", "ping", "macros"] }
//! futures = "0.3.21"
//! libp2p = { version = "0.52", features = ["tcp", "dns", "async-std", "noise", "yamux", "websocket", "ping", "macros"] }
//! futures = "0.3"
//! env_logger = "0.10.0"
//! async-std = { version = "1.12.0", features = ["attributes"] }
//! async-std = { version = "1.12", features = ["attributes"] }
//! ```
//!
//! ## Network identity
@ -71,38 +71,27 @@
//! derived from their public key. Now, replace the contents of main.rs by:
//!
//! ```rust
//! use libp2p::{identity, PeerId};
//! use std::error::Error;
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//! println!("Local peer id: {local_peer_id:?}");
//! env_logger::init();
//!
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity();
//!
//! Ok(())
//! }
//! ```
//!
//! Go ahead and build and run the above code with: `cargo run`. A unique
//! [`PeerId`](crate::PeerId) should be displayed.
//! Go ahead and build and run the above code with: `cargo run`. Nothing happening thus far.
//!
//! ## Transport
//!
//! Next up we need to construct a transport. A transport in libp2p provides
//! connection-oriented communication channels (e.g. TCP) as well as upgrades
//! on top of those like authentication and encryption protocols. Technically,
//! a libp2p transport is anything that implements the [`Transport`] trait.
//!
//! Instead of constructing a transport ourselves for this tutorial, we use the
//! convenience function [`development_transport`](crate::development_transport)
//! that creates a TCP transport with [`noise`](crate::noise) for authenticated
//! encryption.
//!
//! Furthermore, [`development_transport`] builds a multiplexed transport,
//! whereby multiple logical substreams can coexist on the same underlying (TCP)
//! connection. For further details on substream multiplexing, take a look at
//! [`crate::core::muxing`] and [`yamux`](crate::yamux).
//! Next up we need to construct a transport. Each transport in libp2p provides encrypted streams.
//! E.g. combining TCP to establish connections, TLS to encrypt these connections and Yamux to run
//! one or more streams on a connection. Another libp2p transport is QUIC, providing encrypted
//! streams out-of-the-box. We will stick to TCP for now. Each of these implement the [`Transport`]
//! trait.
//!
//! ```rust
//! use libp2p::{identity, PeerId};
@ -110,11 +99,15 @@
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//! println!("Local peer id: {local_peer_id:?}");
//! env_logger::init();
//!
//! let transport = libp2p::development_transport(local_key).await?;
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?;
//!
//! Ok(())
//! }
@ -125,20 +118,20 @@
//! Now it is time to look at another core trait of rust-libp2p: the
//! [`NetworkBehaviour`]. While the previously introduced trait [`Transport`]
//! defines _how_ to send bytes on the network, a [`NetworkBehaviour`] defines
//! _what_ bytes to send on the network.
//! _what_ bytes and to _whom_ to send on the network.
//!
//! To make this more concrete, let's take a look at a simple implementation of
//! the [`NetworkBehaviour`] trait: the [`ping::Behaviour`](crate::ping::Behaviour).
//! As you might have guessed, similar to the good old `ping` network tool,
//! As you might have guessed, similar to the good old ICMP `ping` network tool,
//! libp2p [`ping::Behaviour`](crate::ping::Behaviour) sends a ping to a peer and expects
//! to receive a pong in turn. The [`ping::Behaviour`](crate::ping::Behaviour) does not care _how_
//! the ping and pong messages are sent on the network, whether they are sent via
//! TCP, whether they are encrypted via [noise](crate::noise) or just in
//! [plaintext](crate::plaintext). It only cares about _what_ messages are sent
//! on the network.
//! [plaintext](crate::plaintext). It only cares about _what_ messages and to _whom_ to sent on the
//! network.
//!
//! The two traits [`Transport`] and [`NetworkBehaviour`] allow us to cleanly
//! separate _how_ to send bytes from _what_ bytes to send.
//! separate _how_ to send bytes from _what_ bytes and to _whom_ to send.
//!
//! With the above in mind, let's extend our example, creating a [`ping::Behaviour`](crate::ping::Behaviour) at the end:
//!
@ -149,13 +142,16 @@
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//! println!("Local peer id: {local_peer_id:?}");
//! env_logger::init();
//!
//! let transport = libp2p::development_transport(local_key).await?;
//!
//! let behaviour = ping::Behaviour::default();
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?
//! .with_behaviour(|_| ping::Behaviour::default())?;
//!
//! Ok(())
//! }
@ -163,16 +159,10 @@
//!
//! ## Swarm
//!
//! Now that we have a [`Transport`] and a [`NetworkBehaviour`], we need
//! something that connects the two, allowing both to make progress. This job is
//! carried out by a [`Swarm`]. Put simply, a [`Swarm`] drives both a
//! [`Transport`] and a [`NetworkBehaviour`] forward, passing commands from the
//! [`NetworkBehaviour`] to the [`Transport`] as well as events from the
//! [`Transport`] to the [`NetworkBehaviour`]. As you can see, after [`Swarm`] initialization, we
//! removed the print of the local [`PeerId`](crate::PeerId) because every time a [`Swarm`] is
//! created, it prints the local [`PeerId`](crate::PeerId) in the logs at the INFO level. In order
//! to continue to see the local [`PeerId`](crate::PeerId) you must initialize the logger
//! (In our example, `env_logger` is used)
//! Now that we have a [`Transport`] and a [`NetworkBehaviour`], we can build the [`Swarm`]
//! which connects the two, allowing both to make progress. Put simply, a [`Swarm`] drives both a
//! [`Transport`] and a [`NetworkBehaviour`] forward, passing commands from the [`NetworkBehaviour`]
//! to the [`Transport`] as well as events from the [`Transport`] to the [`NetworkBehaviour`].
//!
//! ```rust
//! use libp2p::swarm::{NetworkBehaviour, SwarmBuilder};
@ -182,14 +172,16 @@
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! env_logger::init();
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//!
//! let transport = libp2p::development_transport(local_key).await?;
//!
//! let behaviour = ping::Behaviour::default();
//!
//! let mut swarm = SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id).build();
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?
//! .with_behaviour(|_| ping::Behaviour::default())?
//! .build();
//!
//! Ok(())
//! }
@ -213,17 +205,17 @@
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! use std::time::Duration;
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//! println!("Local peer id: {local_peer_id:?}");
//! env_logger::init();
//!
//! let transport = libp2p::development_transport(local_key).await?;
//!
//! let behaviour = ping::Behaviour::default();
//!
//! let mut swarm = SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id)
//! .idle_connection_timeout(Duration::from_secs(30)) // Allows us to observe pings for 30 seconds.
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?
//! .with_behaviour(|_| ping::Behaviour::default())?
//! .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(30))) // Allows us to observe pings for 30 seconds.
//! .build();
//!
//! Ok(())
@ -264,16 +256,15 @@
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! env_logger::init();
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//!
//! let transport = libp2p::development_transport(local_key).await?;
//!
//! let behaviour = ping::Behaviour::default();
//!
//! let mut swarm = SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id)
//! .idle_connection_timeout(Duration::from_secs(30)) // Allows us to observe pings for 30 seconds.
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?
//! .with_behaviour(|_| ping::Behaviour::default())?
//! .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(30))) // Allows us to observe pings for 30 seconds.
//! .build();
//!
//! // Tell the swarm to listen on all interfaces and a random, OS-assigned
@ -307,16 +298,15 @@
//!
//! #[async_std::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! env_logger::init();
//! let local_key = identity::Keypair::generate_ed25519();
//! let local_peer_id = PeerId::from(local_key.public());
//!
//! let transport = libp2p::development_transport(local_key).await?;
//!
//! let behaviour = ping::Behaviour::default();
//!
//! let mut swarm = SwarmBuilder::with_async_std_executor(transport, behaviour, local_peer_id)
//! .idle_connection_timeout(Duration::from_secs(30)) // Allows us to observe pings for 30 seconds.
//! let mut swarm = libp2p::SwarmBuilder::with_new_identity()
//! .with_async_std()
//! .with_tcp(
//! libp2p_tcp::Config::default(),
//! libp2p_tls::Config::new,
//! libp2p_yamux::Config::default,
//! )?
//! .with_behaviour(|_| ping::Behaviour::default())?
//! .with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(30))) // Allows us to observe pings for 30 seconds.
//! .build();
//!
//! // Tell the swarm to listen on all interfaces and a random, OS-assigned

View File

@ -17,7 +17,7 @@ futures-util = { version = "0.3.28" }
futures-timer = "3.0.2"
[dev-dependencies]
tokio = { version = "1.29.1", features = ["macros", "rt"] }
tokio = { version = "1.33.0", features = ["macros", "rt"] }
[lints]
workspace = true

View File

@ -1,27 +1,18 @@
use base64::Engine;
use clap::Parser;
use futures::future::Either;
use futures::stream::StreamExt;
use futures_timer::Delay;
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::upgrade;
use libp2p::dns;
use libp2p::identify;
use libp2p::identity;
use libp2p::identity::PeerId;
use libp2p::kad;
use libp2p::metrics::{Metrics, Recorder};
use libp2p::noise;
use libp2p::quic;
use libp2p::swarm::{SwarmBuilder, SwarmEvent};
use libp2p::swarm::SwarmEvent;
use libp2p::tcp;
use libp2p::yamux;
use libp2p::Transport;
use libp2p::{identify, noise, yamux};
use log::{debug, info, warn};
use prometheus_client::metrics::info::Info;
use prometheus_client::registry::Registry;
use std::error::Error;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;
use std::task::Poll;
@ -62,7 +53,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let config = Zeroizing::new(config::Config::from_file(opt.config.as_path())?);
let (local_peer_id, local_keypair) = {
let local_keypair = {
let keypair = identity::Keypair::from_protobuf_encoding(&Zeroizing::new(
base64::engine::general_purpose::STANDARD
.decode(config.identity.priv_key.as_bytes())?,
@ -75,37 +66,25 @@ async fn main() -> Result<(), Box<dyn Error>> {
"Expect peer id derived from private key and peer id retrieved from config to match."
);
(peer_id, keypair)
keypair
};
let transport = {
let tcp_transport =
tcp::tokio::Transport::new(tcp::Config::new().port_reuse(true).nodelay(true))
.upgrade(upgrade::Version::V1)
.authenticate(noise::Config::new(&local_keypair)?)
.multiplex(yamux::Config::default())
.timeout(Duration::from_secs(20));
let quic_transport = quic::tokio::Transport::new(quic::Config::new(&local_keypair));
dns::tokio::Transport::system(libp2p::core::transport::OrTransport::new(
quic_transport,
tcp_transport,
))?
.map(|either_output, _| match either_output {
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(local_keypair)
.with_tokio()
.with_tcp(
tcp::Config::default().port_reuse(true).nodelay(true),
noise::Config::new,
yamux::Config::default,
)?
.with_quic_config(|mut cfg| {
cfg.support_draft_29 = true;
cfg
})
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
.boxed()
};
let behaviour = behaviour::Behaviour::new(
local_keypair.public(),
opt.enable_kademlia,
opt.enable_autonat,
);
let mut swarm = SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id).build();
.with_dns()?
.with_behaviour(|key| {
behaviour::Behaviour::new(key.public(), opt.enable_kademlia, opt.enable_autonat)
})?
.build();
if config.addresses.swarm.is_empty() {
warn!("No listen addresses configured.");

View File

@ -26,7 +26,7 @@ use libp2p_identity as identity;
use libp2p_identity::PeerId;
use libp2p_plaintext as plaintext;
use libp2p_relay as relay;
use libp2p_swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{Config, NetworkBehaviour, Swarm, SwarmEvent};
use libp2p_swarm_test::SwarmExt as _;
use std::time::Duration;
@ -123,15 +123,15 @@ fn build_client() -> Swarm<Client> {
.multiplex(libp2p_yamux::Config::default())
.boxed();
SwarmBuilder::without_executor(
Swarm::new(
transport,
Client {
relay: behaviour,
dcutr: dcutr::Behaviour::new(local_peer_id),
},
local_peer_id,
Config::with_async_std_executor(),
)
.build()
}
#[derive(NetworkBehaviour)]

View File

@ -16,7 +16,7 @@ wasm-bindgen = ["getrandom/js", "instant/wasm-bindgen"]
[dependencies]
asynchronous-codec = "0.6"
base64 = "0.21.4"
byteorder = "1.3.4"
byteorder = "1.5.0"
bytes = "1.5"
either = "1.9"
fnv = "1.0.7"

View File

@ -37,7 +37,7 @@ use libp2p_core::{
use libp2p_identity as identity;
use libp2p_identity::PeerId;
use libp2p_noise as noise;
use libp2p_swarm::{ConnectionId, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{self as swarm, ConnectionId, Swarm, SwarmEvent};
use libp2p_yamux as yamux;
use quickcheck::*;
use rand::{random, rngs::StdRng, thread_rng, Rng, SeedableRng};
@ -67,7 +67,12 @@ fn build_node_with_config(cfg: Config) -> (Multiaddr, TestSwarm) {
let store = MemoryStore::new(local_id);
let behaviour = Behaviour::with_config(local_id, store, cfg);
let mut swarm = SwarmBuilder::without_executor(transport, behaviour, local_id).build();
let mut swarm = Swarm::new(
transport,
behaviour,
local_id,
swarm::Config::with_async_std_executor(),
);
let address: Multiaddr = Protocol::Memory(random::<u64>()).into();
swarm.listen_on(address.clone()).unwrap();

View File

@ -22,7 +22,7 @@ log = "0.4.20"
rand = "0.8.3"
smallvec = "1.11.1"
socket2 = { version = "0.5.4", features = ["all"] }
tokio = { version = "1.32", default-features = false, features = ["net", "time"], optional = true}
tokio = { version = "1.33", default-features = false, features = ["net", "time"], optional = true}
trust-dns-proto = { version = "0.23.0", default-features = false, features = ["mdns"] }
void = "1.0.2"
@ -37,7 +37,7 @@ libp2p-noise = { workspace = true }
libp2p-swarm = { workspace = true, features = ["tokio", "async-std"] }
libp2p-tcp = { workspace = true, features = ["tokio", "async-io"] }
libp2p-yamux = { workspace = true }
tokio = { version = "1.32", default-features = false, features = ["macros", "rt", "rt-multi-thread", "time"] }
tokio = { version = "1.33", default-features = false, features = ["macros", "rt", "rt-multi-thread", "time"] }
libp2p-swarm-test = { path = "../../swarm-test" }
[[test]]

View File

@ -30,7 +30,7 @@ log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.33.0", features = ["full"] }
void = "1"
[dev-dependencies]

View File

@ -31,7 +31,7 @@ use libp2p_core::{
};
use libp2p_identity::PeerId;
use libp2p_perf::{Run, RunDuration, RunParams};
use libp2p_swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{Config, NetworkBehaviour, Swarm, SwarmEvent};
use log::{error, info};
use serde::{Deserialize, Serialize};
@ -414,11 +414,15 @@ async fn swarm<B: NetworkBehaviour + Default>() -> Result<Swarm<B>> {
.boxed()
};
Ok(
SwarmBuilder::with_tokio_executor(transport, Default::default(), local_peer_id)
.substream_upgrade_protocol_override(upgrade::Version::V1Lazy)
.build(),
)
let swarm = Swarm::new(
transport,
Default::default(),
local_peer_id,
Config::with_tokio_executor()
.with_substream_upgrade_protocol_override(upgrade::Version::V1Lazy),
);
Ok(swarm)
}
async fn connect(

View File

@ -33,7 +33,7 @@ use libp2p_identity::PeerId;
use libp2p_ping as ping;
use libp2p_plaintext as plaintext;
use libp2p_relay as relay;
use libp2p_swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{Config, NetworkBehaviour, Swarm, SwarmEvent};
use std::time::Duration;
#[test]
@ -310,7 +310,7 @@ fn build_relay() -> Swarm<Relay> {
let transport = upgrade_transport(MemoryTransport::default().boxed(), &local_key);
SwarmBuilder::with_async_std_executor(
Swarm::new(
transport,
Relay {
ping: ping::Behaviour::new(ping::Config::new()),
@ -323,8 +323,8 @@ fn build_relay() -> Swarm<Relay> {
),
},
local_peer_id,
Config::with_async_std_executor(),
)
.build()
}
fn build_client() -> Swarm<Client> {
@ -337,15 +337,15 @@ fn build_client() -> Swarm<Client> {
&local_key,
);
SwarmBuilder::with_async_std_executor(
Swarm::new(
transport,
Client {
ping: ping::Behaviour::new(ping::Config::new()),
relay: behaviour,
},
local_peer_id,
Config::with_async_std_executor(),
)
.build()
}
fn upgrade_transport<StreamSink>(

View File

@ -37,7 +37,7 @@ libp2p-identify = { workspace = true }
libp2p-yamux = { workspace = true }
libp2p-tcp = { workspace = true, features = ["tokio"] }
rand = "0.8"
tokio = { version = "1.32", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] }
tokio = { version = "1.33", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] }
libp2p-swarm-test = { path = "../../swarm-test" }
# Passing arguments to the docsrs builder in order to properly document cfg's.

View File

@ -18,7 +18,7 @@ libp2p-core = { workspace = true }
libp2p-swarm = { workspace = true }
log = "0.4.19"
void = "1.0.2"
tokio = { version = "1.29", default-features = false, features = ["rt"], optional = true }
tokio = { version = "1.33", default-features = false, features = ["rt"], optional = true }
[features]
tokio = ["igd-next/aio_tokio", "dep:tokio"]

View File

@ -16,7 +16,7 @@ async-trait = "0.1.73"
libp2p-core = { workspace = true }
libp2p-identity = { workspace = true, features = ["rand"] }
libp2p-plaintext = { workspace = true }
libp2p-swarm = { workspace = true }
libp2p-swarm = { workspace = true, features = ["async-std"] }
libp2p-tcp = { workspace = true, features = ["async-io"] }
libp2p-yamux = { workspace = true }
futures = "0.3.28"

View File

@ -28,7 +28,7 @@ use libp2p_identity::{Keypair, PeerId};
use libp2p_plaintext as plaintext;
use libp2p_swarm::dial_opts::PeerCondition;
use libp2p_swarm::{
dial_opts::DialOpts, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent, THandlerErr,
self as swarm, dial_opts::DialOpts, NetworkBehaviour, Swarm, SwarmEvent, THandlerErr,
};
use libp2p_yamux as yamux;
use std::fmt::Debug;
@ -216,9 +216,13 @@ where
.timeout(Duration::from_secs(20))
.boxed();
SwarmBuilder::without_executor(transport, behaviour_fn(identity), peer_id)
.idle_connection_timeout(Duration::from_secs(5)) // Some tests need connections to be kept alive beyond what the individual behaviour configures.
.build()
Swarm::new(
transport,
behaviour_fn(identity),
peer_id,
swarm::Config::with_async_std_executor()
.with_idle_connection_timeout(Duration::from_secs(5)), // Some tests need connections to be kept alive beyond what the individual behaviour configures.,
)
}
async fn connect<T>(&mut self, other: &mut Swarm<T>)

View File

@ -1,3 +1,12 @@
## 0.43.6 - unreleased
- Deprecate `libp2p::swarm::SwarmBuilder`.
Most users should use `libp2p::SwarmBuilder`.
In some special cases, users may need to use `Swarm::new` and `Config` instead of the new `libp2p::SwarmBuilder`.
See [PR 4120].
[PR 4120]: https://github.com/libp2p/rust-libp2p/pull/4120
## 0.43.5
- Fix overflow in `KeepAlive` computation that could occur if `SwarmBuilder::idle_connection_timeout` is configured with `u64::MAX`.

View File

@ -3,7 +3,7 @@ name = "libp2p-swarm"
edition = "2021"
rust-version = { workspace = true }
description = "The libp2p swarm"
version = "0.43.5"
version = "0.43.6"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
@ -30,7 +30,7 @@ multistream-select = { workspace = true }
[target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies]
async-std = { version = "1.6.2", optional = true }
tokio = { version = "1.32", features = ["rt"], optional = true }
tokio = { version = "1.33", features = ["rt"], optional = true }
[features]
macros = ["dep:libp2p-swarm-derive"]
@ -55,7 +55,7 @@ quickcheck = { workspace = true }
void = "1"
once_cell = "1.18.0"
trybuild = "1.0.85"
tokio = { version = "1.29.1", features = ["time", "rt", "macros"] }
tokio = { version = "1.33.0", features = ["time", "rt", "macros", "rt-multi-thread"] }
[[test]]
name = "swarm_derive"

View File

@ -748,6 +748,8 @@ mod tests {
#[test]
fn max_negotiating_inbound_streams() {
let _ = env_logger::try_init();
fn prop(max_negotiating_inbound_streams: u8) {
let max_negotiating_inbound_streams: usize = max_negotiating_inbound_streams.into();
@ -756,7 +758,7 @@ mod tests {
StreamMuxerBox::new(DummyStreamMuxer {
counter: alive_substream_counter.clone(),
}),
MockConnectionHandler::new(Duration::ZERO),
MockConnectionHandler::new(Duration::from_secs(10)),
None,
max_negotiating_inbound_streams,
Duration::ZERO,

View File

@ -359,6 +359,26 @@ impl<TBehaviour> Swarm<TBehaviour>
where
TBehaviour: NetworkBehaviour,
{
/// Creates a new [`Swarm`] from the given [`Transport`], [`NetworkBehaviour`], [`PeerId`] and
/// [`Config`].
pub fn new(
transport: transport::Boxed<(PeerId, StreamMuxerBox)>,
behaviour: TBehaviour,
local_peer_id: PeerId,
config: Config,
) -> Self {
Swarm {
local_peer_id,
transport,
pool: Pool::new(local_peer_id, config.pool_config),
behaviour,
supported_protocols: Default::default(),
confirmed_external_addr: Default::default(),
listened_addrs: HashMap::new(),
pending_event: None,
}
}
/// Returns information about the connections underlying the [`Swarm`].
pub fn network_info(&self) -> NetworkInfo {
let num_peers = self.pool.num_peers();
@ -401,7 +421,9 @@ where
/// # use libp2p_swarm::dummy;
/// # use libp2p_identity::PeerId;
/// #
/// let mut swarm = SwarmBuilder::without_executor(
/// # #[tokio::main]
/// # async fn main() {
/// let mut swarm = SwarmBuilder::with_tokio_executor(
/// DummyTransport::new().boxed(),
/// dummy::Behaviour,
/// PeerId::random(),
@ -412,6 +434,7 @@ where
///
/// // Dial an unknown peer.
/// swarm.dial("/ip6/::1/tcp/12345".parse::<Multiaddr>().unwrap());
/// # }
/// ```
pub fn dial(&mut self, opts: impl Into<DialOpts>) -> Result<(), DialError> {
let dial_opts = opts.into();
@ -1346,7 +1369,132 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
}
}
pub struct Config {
pool_config: PoolConfig,
}
impl Config {
/// Creates a new [`Config`] from the given executor. The [`Swarm`] is obtained via
/// [`Swarm::new`].
pub fn with_executor(executor: impl Executor + Send + 'static) -> Self {
Self {
pool_config: PoolConfig::new(Some(Box::new(executor))),
}
}
/// Sets executor to the `wasm` executor.
/// Background tasks will be executed by the browser on the next micro-tick.
///
/// Spawning a task is similar too:
/// ```typescript
/// function spawn(task: () => Promise<void>) {
/// task()
/// }
/// ```
#[cfg(feature = "wasm-bindgen")]
pub fn with_wasm_executor() -> Self {
Self::with_executor(crate::executor::WasmBindgenExecutor)
}
/// Builds a new [`Config`] from the given `tokio` executor.
#[cfg(all(
feature = "tokio",
not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown"))
))]
pub fn with_tokio_executor() -> Self {
Self::with_executor(crate::executor::TokioExecutor)
}
/// Builds a new [`Config`] from the given `async-std` executor.
#[cfg(all(
feature = "async-std",
not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown"))
))]
pub fn with_async_std_executor() -> Self {
Self::with_executor(crate::executor::AsyncStdExecutor)
}
/// Configures the number of events from the [`NetworkBehaviour`] in
/// destination to the [`ConnectionHandler`] that can be buffered before
/// the [`Swarm`] has to wait. An individual buffer with this number of
/// events exists for each individual connection.
///
/// The ideal value depends on the executor used, the CPU speed, and the
/// volume of events. If this value is too low, then the [`Swarm`] will
/// be sleeping more often than necessary. Increasing this value increases
/// the overall memory usage.
pub fn with_notify_handler_buffer_size(mut self, n: NonZeroUsize) -> Self {
self.pool_config = self.pool_config.with_notify_handler_buffer_size(n);
self
}
/// Configures the size of the buffer for events sent by a [`ConnectionHandler`] to the
/// [`NetworkBehaviour`].
///
/// Each connection has its own buffer.
///
/// The ideal value depends on the executor used, the CPU speed and the volume of events.
/// If this value is too low, then the [`ConnectionHandler`]s will be sleeping more often
/// than necessary. Increasing this value increases the overall memory
/// usage, and more importantly the latency between the moment when an
/// event is emitted and the moment when it is received by the
/// [`NetworkBehaviour`].
pub fn with_per_connection_event_buffer_size(mut self, n: usize) -> Self {
self.pool_config = self.pool_config.with_per_connection_event_buffer_size(n);
self
}
/// Number of addresses concurrently dialed for a single outbound connection attempt.
pub fn with_dial_concurrency_factor(mut self, factor: NonZeroU8) -> Self {
self.pool_config = self.pool_config.with_dial_concurrency_factor(factor);
self
}
/// Configures an override for the substream upgrade protocol to use.
///
/// The subtream upgrade protocol is the multistream-select protocol
/// used for protocol negotiation on substreams. Since a listener
/// supports all existing versions, the choice of upgrade protocol
/// only effects the "dialer", i.e. the peer opening a substream.
///
/// > **Note**: If configured, specific upgrade protocols for
/// > individual [`SubstreamProtocol`]s emitted by the `NetworkBehaviour`
/// > are ignored.
pub fn with_substream_upgrade_protocol_override(
mut self,
v: libp2p_core::upgrade::Version,
) -> Self {
self.pool_config = self.pool_config.with_substream_upgrade_protocol_override(v);
self
}
/// The maximum number of inbound streams concurrently negotiating on a
/// connection. New inbound streams exceeding the limit are dropped and thus
/// reset.
///
/// Note: This only enforces a limit on the number of concurrently
/// negotiating inbound streams. The total number of inbound streams on a
/// connection is the sum of negotiating and negotiated streams. A limit on
/// the total number of streams can be enforced at the
/// [`StreamMuxerBox`] level.
pub fn with_max_negotiating_inbound_streams(mut self, v: usize) -> Self {
self.pool_config = self.pool_config.with_max_negotiating_inbound_streams(v);
self
}
/// How long to keep a connection alive once it is idling.
///
/// Defaults to 0.
pub fn with_idle_connection_timeout(mut self, timeout: Duration) -> Self {
self.pool_config.idle_connection_timeout = timeout;
self
}
}
/// A [`SwarmBuilder`] provides an API for configuring and constructing a [`Swarm`].
#[deprecated(
note = "Use the new `libp2p::SwarmBuilder` instead of `libp2p::swarm::SwarmBuilder` or create a `Swarm` directly via `Swarm::new`."
)]
pub struct SwarmBuilder<TBehaviour> {
local_peer_id: PeerId,
transport: transport::Boxed<(PeerId, StreamMuxerBox)>,
@ -1354,6 +1502,7 @@ pub struct SwarmBuilder<TBehaviour> {
pool_config: PoolConfig,
}
#[allow(deprecated)]
impl<TBehaviour> SwarmBuilder<TBehaviour>
where
TBehaviour: NetworkBehaviour,
@ -1820,9 +1969,7 @@ mod tests {
use super::*;
use crate::dummy;
use crate::test::{CallTraceBehaviour, MockBehaviour};
use futures::executor::block_on;
use futures::executor::ThreadPool;
use futures::{executor, future};
use futures::future;
use libp2p_core::multiaddr::multiaddr;
use libp2p_core::transport::memory::MemoryTransportError;
use libp2p_core::transport::TransportEvent;
@ -1841,7 +1988,8 @@ mod tests {
}
fn new_test_swarm(
) -> SwarmBuilder<CallTraceBehaviour<MockBehaviour<dummy::ConnectionHandler, ()>>> {
config: Config,
) -> Swarm<CallTraceBehaviour<MockBehaviour<dummy::ConnectionHandler, ()>>> {
let id_keys = identity::Keypair::generate_ed25519();
let local_public_key = id_keys.public();
let transport = transport::MemoryTransport::default()
@ -1850,14 +1998,13 @@ mod tests {
.multiplex(yamux::Config::default())
.boxed();
let behaviour = CallTraceBehaviour::new(MockBehaviour::new(dummy::ConnectionHandler));
let builder = match ThreadPool::new().ok() {
Some(tp) => {
SwarmBuilder::with_executor(transport, behaviour, local_public_key.into(), tp)
}
None => SwarmBuilder::without_executor(transport, behaviour, local_public_key.into()),
};
builder.idle_connection_timeout(Duration::from_secs(5))
Swarm::new(
transport,
behaviour,
local_public_key.into(),
config.with_idle_connection_timeout(Duration::from_secs(5)),
)
}
fn swarms_connected<TBehaviour>(
@ -1906,10 +2053,10 @@ mod tests {
///
/// The test expects both behaviours to be notified via calls to [`NetworkBehaviour::on_swarm_event`]
/// with pairs of [`FromSwarm::ConnectionEstablished`] / [`FromSwarm::ConnectionClosed`]
#[test]
fn test_swarm_disconnect() {
let mut swarm1 = new_test_swarm().build();
let mut swarm2 = new_test_swarm().build();
#[tokio::test]
async fn test_swarm_disconnect() {
let mut swarm1 = new_test_swarm(Config::with_tokio_executor());
let mut swarm2 = new_test_swarm(Config::with_tokio_executor());
let addr1: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
let addr2: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
@ -1927,7 +2074,7 @@ mod tests {
}
let mut state = State::Connecting;
executor::block_on(future::poll_fn(move |cx| loop {
future::poll_fn(move |cx| loop {
let poll1 = Swarm::poll_next_event(Pin::new(&mut swarm1), cx);
let poll2 = Swarm::poll_next_event(Pin::new(&mut swarm2), cx);
match state {
@ -1959,7 +2106,8 @@ mod tests {
if poll1.is_pending() && poll2.is_pending() {
return Poll::Pending;
}
}))
})
.await
}
/// Establishes multiple connections between two peers,
@ -1968,10 +2116,10 @@ mod tests {
///
/// The test expects both behaviours to be notified via calls to [`NetworkBehaviour::on_swarm_event`]
/// with pairs of [`FromSwarm::ConnectionEstablished`] / [`FromSwarm::ConnectionClosed`]
#[test]
fn test_behaviour_disconnect_all() {
let mut swarm1 = new_test_swarm().build();
let mut swarm2 = new_test_swarm().build();
#[tokio::test]
async fn test_behaviour_disconnect_all() {
let mut swarm1 = new_test_swarm(Config::with_tokio_executor());
let mut swarm2 = new_test_swarm(Config::with_tokio_executor());
let addr1: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
let addr2: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
@ -1989,7 +2137,7 @@ mod tests {
}
let mut state = State::Connecting;
executor::block_on(future::poll_fn(move |cx| loop {
future::poll_fn(move |cx| loop {
let poll1 = Swarm::poll_next_event(Pin::new(&mut swarm1), cx);
let poll2 = Swarm::poll_next_event(Pin::new(&mut swarm2), cx);
match state {
@ -2025,7 +2173,8 @@ mod tests {
if poll1.is_pending() && poll2.is_pending() {
return Poll::Pending;
}
}))
})
.await
}
/// Establishes multiple connections between two peers,
@ -2034,10 +2183,10 @@ mod tests {
///
/// The test expects both behaviours to be notified via calls to [`NetworkBehaviour::on_swarm_event`]
/// with pairs of [`FromSwarm::ConnectionEstablished`] / [`FromSwarm::ConnectionClosed`]
#[test]
fn test_behaviour_disconnect_one() {
let mut swarm1 = new_test_swarm().build();
let mut swarm2 = new_test_swarm().build();
#[tokio::test]
async fn test_behaviour_disconnect_one() {
let mut swarm1 = new_test_swarm(Config::with_tokio_executor());
let mut swarm2 = new_test_swarm(Config::with_tokio_executor());
let addr1: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
let addr2: Multiaddr = multiaddr::Protocol::Memory(rand::random::<u64>()).into();
@ -2055,7 +2204,7 @@ mod tests {
let mut state = State::Connecting;
let mut disconnected_conn_id = None;
executor::block_on(future::poll_fn(move |cx| loop {
future::poll_fn(move |cx| loop {
let poll1 = Swarm::poll_next_event(Pin::new(&mut swarm1), cx);
let poll2 = Swarm::poll_next_event(Pin::new(&mut swarm2), cx);
match state {
@ -2099,7 +2248,8 @@ mod tests {
if poll1.is_pending() && poll2.is_pending() {
return Poll::Pending;
}
}))
})
.await
}
#[test]
@ -2114,10 +2264,11 @@ mod tests {
}
fn prop(concurrency_factor: DialConcurrencyFactor) {
block_on(async {
let mut swarm = new_test_swarm()
.dial_concurrency_factor(concurrency_factor.0)
.build();
tokio::runtime::Runtime::new().unwrap().block_on(async {
let mut swarm = new_test_swarm(
Config::with_tokio_executor()
.with_dial_concurrency_factor(concurrency_factor.0),
);
// Listen on `concurrency_factor + 1` addresses.
//
@ -2173,31 +2324,29 @@ mod tests {
QuickCheck::new().tests(10).quickcheck(prop as fn(_) -> _);
}
#[test]
fn invalid_peer_id() {
#[tokio::test]
async fn invalid_peer_id() {
// Checks whether dialing an address containing the wrong peer id raises an error
// for the expected peer id instead of the obtained peer id.
let mut swarm1 = new_test_swarm().build();
let mut swarm2 = new_test_swarm().build();
let mut swarm1 = new_test_swarm(Config::with_tokio_executor());
let mut swarm2 = new_test_swarm(Config::with_tokio_executor());
swarm1.listen_on("/memory/0".parse().unwrap()).unwrap();
let address =
futures::executor::block_on(future::poll_fn(|cx| match swarm1.poll_next_unpin(cx) {
Poll::Ready(Some(SwarmEvent::NewListenAddr { address, .. })) => {
Poll::Ready(address)
}
Poll::Pending => Poll::Pending,
_ => panic!("Was expecting the listen address to be reported"),
}));
let address = future::poll_fn(|cx| match swarm1.poll_next_unpin(cx) {
Poll::Ready(Some(SwarmEvent::NewListenAddr { address, .. })) => Poll::Ready(address),
Poll::Pending => Poll::Pending,
_ => panic!("Was expecting the listen address to be reported"),
})
.await;
let other_id = PeerId::random();
let other_addr = address.with(multiaddr::Protocol::P2p(other_id));
swarm2.dial(other_addr.clone()).unwrap();
let (peer_id, error) = futures::executor::block_on(future::poll_fn(|cx| {
let (peer_id, error) = future::poll_fn(|cx| {
if let Poll::Ready(Some(SwarmEvent::IncomingConnection { .. })) =
swarm1.poll_next_unpin(cx)
{}
@ -2209,7 +2358,8 @@ mod tests {
Poll::Ready(x) => panic!("unexpected {x:?}"),
Poll::Pending => Poll::Pending,
}
}));
})
.await;
assert_eq!(peer_id.unwrap(), other_id);
match error {
DialError::WrongPeerId { obtained, endpoint } => {
@ -2226,8 +2376,8 @@ mod tests {
}
}
#[test]
fn dial_self() {
#[tokio::test]
async fn dial_self() {
// Check whether dialing ourselves correctly fails.
//
// Dialing the same address we're listening should result in three events:
@ -2238,17 +2388,15 @@ mod tests {
//
// The last two can happen in any order.
let mut swarm = new_test_swarm().build();
let mut swarm = new_test_swarm(Config::with_tokio_executor());
swarm.listen_on("/memory/0".parse().unwrap()).unwrap();
let local_address =
futures::executor::block_on(future::poll_fn(|cx| match swarm.poll_next_unpin(cx) {
Poll::Ready(Some(SwarmEvent::NewListenAddr { address, .. })) => {
Poll::Ready(address)
}
Poll::Pending => Poll::Pending,
_ => panic!("Was expecting the listen address to be reported"),
}));
let local_address = future::poll_fn(|cx| match swarm.poll_next_unpin(cx) {
Poll::Ready(Some(SwarmEvent::NewListenAddr { address, .. })) => Poll::Ready(address),
Poll::Pending => Poll::Pending,
_ => panic!("Was expecting the listen address to be reported"),
})
.await;
swarm.listened_addrs.clear(); // This is a hack to actually execute the dial to ourselves which would otherwise be filtered.
@ -2256,7 +2404,7 @@ mod tests {
let mut got_dial_err = false;
let mut got_inc_err = false;
futures::executor::block_on(future::poll_fn(|cx| -> Poll<Result<(), io::Error>> {
future::poll_fn(|cx| -> Poll<Result<(), io::Error>> {
loop {
match swarm.poll_next_unpin(cx) {
Poll::Ready(Some(SwarmEvent::OutgoingConnectionError {
@ -2290,26 +2438,27 @@ mod tests {
Poll::Pending => break Poll::Pending,
}
}
}))
})
.await
.unwrap();
}
#[test]
fn dial_self_by_id() {
#[tokio::test]
async fn dial_self_by_id() {
// Trying to dial self by passing the same `PeerId` shouldn't even be possible in the first
// place.
let swarm = new_test_swarm().build();
let swarm = new_test_swarm(Config::with_tokio_executor());
let peer_id = *swarm.local_peer_id();
assert!(!swarm.is_connected(&peer_id));
}
#[async_std::test]
#[tokio::test]
async fn multiple_addresses_err() {
// Tries dialing multiple addresses, and makes sure there's one dialing error per address.
let target = PeerId::random();
let mut swarm = new_test_swarm().build();
let mut swarm = new_test_swarm(Config::with_tokio_executor());
let addresses = HashSet::from([
multiaddr![Ip4([0, 0, 0, 0]), Tcp(rand::random::<u16>())],
@ -2351,16 +2500,16 @@ mod tests {
}
}
#[test]
fn aborting_pending_connection_surfaces_error() {
#[tokio::test]
async fn aborting_pending_connection_surfaces_error() {
let _ = env_logger::try_init();
let mut dialer = new_test_swarm().build();
let mut listener = new_test_swarm().build();
let mut dialer = new_test_swarm(Config::with_tokio_executor());
let mut listener = new_test_swarm(Config::with_tokio_executor());
let listener_peer_id = *listener.local_peer_id();
listener.listen_on(multiaddr![Memory(0u64)]).unwrap();
let listener_address = match block_on(listener.next()).unwrap() {
let listener_address = match listener.next().await.unwrap() {
SwarmEvent::NewListenAddr { address, .. } => address,
e => panic!("Unexpected network event: {e:?}"),
};
@ -2377,7 +2526,7 @@ mod tests {
.disconnect_peer_id(listener_peer_id)
.expect_err("Expect peer to not yet be connected.");
match block_on(dialer.next()).unwrap() {
match dialer.next().await.unwrap() {
SwarmEvent::OutgoingConnectionError {
error: DialError::Aborted,
..

View File

@ -27,7 +27,7 @@ libp2p-tcp = { workspace = true, features = ["tokio"] }
libp2p-websocket = { workspace = true }
libp2p-yamux = { workspace = true }
quickcheck = { workspace = true }
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.33.0", features = ["full"] }
# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling

View File

@ -6,7 +6,7 @@ use libp2p_core::upgrade::Version;
use libp2p_core::Transport;
use libp2p_core::{multiaddr::Protocol, Multiaddr};
use libp2p_pnet::{PnetConfig, PreSharedKey};
use libp2p_swarm::{dummy, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{dummy, Config, NetworkBehaviour, Swarm, SwarmEvent};
const TIMEOUT: Duration = Duration::from_secs(5);
@ -113,9 +113,12 @@ where
.authenticate(libp2p_noise::Config::new(&identity).unwrap())
.multiplex(libp2p_yamux::Config::default())
.boxed();
SwarmBuilder::with_tokio_executor(transport, dummy::Behaviour, identity.public().to_peer_id())
.idle_connection_timeout(Duration::from_secs(5))
.build()
Swarm::new(
transport,
dummy::Behaviour,
identity.public().to_peer_id(),
Config::with_tokio_executor(),
)
}
async fn listen_on<B: NetworkBehaviour>(swarm: &mut Swarm<B>, addr: Multiaddr) -> Multiaddr {

View File

@ -23,7 +23,7 @@ quinn = { version = "0.10.2", default-features = false, features = ["tls-rustls"
rand = "0.8.5"
rustls = { version = "0.21.7", default-features = false }
thiserror = "1.0.49"
tokio = { version = "1.32.0", default-features = false, features = ["net", "rt", "time"], optional = true }
tokio = { version = "1.33.0", default-features = false, features = ["net", "rt", "time"], optional = true }
socket2 = "0.5.4"
ring = "0.16.20"
@ -46,7 +46,7 @@ libp2p-noise = { workspace = true }
libp2p-tcp = { workspace = true, features = ["async-io"] }
libp2p-yamux = { workspace = true }
quickcheck = "1"
tokio = { version = "1.32.0", features = ["macros", "rt-multi-thread", "time"] }
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread", "time"] }
[[test]]
name = "stream_compliance"

View File

@ -20,7 +20,7 @@ libp2p-core = { workspace = true }
libp2p-identity = { workspace = true }
log = "0.4.20"
socket2 = { version = "0.5.4", features = ["all"] }
tokio = { version = "1.32.0", default-features = false, features = ["net"], optional = true }
tokio = { version = "1.33.0", default-features = false, features = ["net"], optional = true }
[features]
tokio = ["dep:tokio", "if-watch/tokio"]
@ -28,7 +28,7 @@ async-io = ["dep:async-io", "if-watch/smol"]
[dev-dependencies]
async-std = { version = "1.6.5", features = ["attributes"] }
tokio = { version = "1.32.0", default-features = false, features = ["full"] }
tokio = { version = "1.33.0", default-features = false, features = ["full"] }
env_logger = "0.10.0"
# Passing arguments to the docsrs builder in order to properly document cfg's.

View File

@ -54,7 +54,7 @@ pub type Transport = crate::Transport<Tcp>;
pub enum Tcp {}
impl Provider for Tcp {
type Stream = Async<net::TcpStream>;
type Stream = TcpStream;
type Listener = Async<net::TcpListener>;
type IfWatcher = if_watch::smol::IfWatcher;
@ -116,3 +116,5 @@ impl Provider for Tcp {
}))
}
}
pub type TcpStream = Async<net::TcpStream>;

View File

@ -31,9 +31,9 @@ hex = "0.4.3"
hex-literal = "0.4.1"
libp2p-core = { workspace = true }
libp2p-identity = { workspace = true, features = ["ed25519", "rsa", "secp256k1", "ecdsa"] }
libp2p-swarm = { workspace = true }
libp2p-swarm = { workspace = true, features = ["tokio"] }
libp2p-yamux = { workspace = true }
tokio = { version = "1.32.0", features = ["full"] }
tokio = { version = "1.33.0", features = ["full"] }
# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling

View File

@ -3,7 +3,7 @@ use libp2p_core::multiaddr::Protocol;
use libp2p_core::transport::MemoryTransport;
use libp2p_core::upgrade::Version;
use libp2p_core::Transport;
use libp2p_swarm::{dummy, Swarm, SwarmBuilder, SwarmEvent};
use libp2p_swarm::{dummy, Config, Swarm, SwarmEvent};
use std::time::Duration;
#[tokio::test]
@ -65,7 +65,10 @@ fn make_swarm() -> Swarm<dummy::Behaviour> {
.multiplex(libp2p_yamux::Config::default())
.boxed();
SwarmBuilder::without_executor(transport, dummy::Behaviour, identity.public().to_peer_id())
.idle_connection_timeout(Duration::from_secs(5))
.build()
Swarm::new(
transport,
dummy::Behaviour,
identity.public().to_peer_id(),
Config::with_tokio_executor().with_idle_connection_timeout(Duration::from_secs(60)),
)
}

View File

@ -15,7 +15,7 @@ async-std = { version = "1.6.2", optional = true }
libp2p-core = { workspace = true }
log = "0.4.20"
futures = "0.3.28"
tokio = { version = "1.32", default-features = false, features = ["net"], optional = true }
tokio = { version = "1.33", default-features = false, features = ["net"], optional = true }
[dev-dependencies]
tempfile = "3.8"

View File

@ -29,7 +29,7 @@ serde = { version = "1.0", features = ["derive"] }
stun = "0.5"
thiserror = "1"
tinytemplate = "1.2"
tokio = { version = "1.32", features = ["net"], optional = true }
tokio = { version = "1.33", features = ["net"], optional = true }
tokio-util = { version = "0.7", features = ["compat"], optional = true }
webrtc = { version = "0.9.0", optional = true }
@ -39,7 +39,7 @@ pem = ["webrtc?/pem"]
[dev-dependencies]
env_logger = "0.10"
tokio = { version = "1.32", features = ["full"] }
tokio = { version = "1.33", features = ["full"] }
quickcheck = "1.0.3"
[[test]]