1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
use instant::Duration;
use libp2p::{identity::Keypair, swarm::NetworkBehaviour, Swarm, SwarmBuilder};
use crate::p2p::P2pError;
pub(crate) use self::imp::new_swarm;
#[cfg(not(target_arch = "wasm32"))]
mod imp {
use super::*;
use libp2p::{dns, noise, tcp, yamux};
pub(crate) fn new_swarm<B>(keypair: Keypair, behaviour: B) -> Result<Swarm<B>, P2pError>
where
B: NetworkBehaviour,
{
Ok(SwarmBuilder::with_existing_identity(keypair)
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_quic()
// We do not use system's DNS because libp2p loads DNS servers only when
// `Swarm` get constructed. This is not a problem for server machines, but
// it is for movable machines such as laptops and smart phones. Because of
// that, the following edge cases can happen:
//
// 1. Machine connects to WiFi A. Our node starts and uses DNS that
// WiFi A announced. Then machine moves to WiFi B, the old DNS servers
// become unreachable, but libp2p still uses the old ones.
// 2. Machine is not connected to the Internet. Our node starts and does not
// find any DNS servers defined. Then machine connects to the Internet, but
// libp2p still does not have any DNS nameservers defined.
//
// By having a pre-defined public servers, these edge cases solved.
.with_dns_config(
dns::ResolverConfig::cloudflare(),
dns::ResolverOpts::default(),
)
.with_behaviour(|_| behaviour)
.expect("Moving behaviour doesn't fail")
.with_swarm_config(|config| {
// TODO: Refactor code to avoid being idle. This can be done by preloading a
// handler. This is how they fixed Kademlia:
// https://github.com/libp2p/rust-libp2p/pull/4675/files
config.with_idle_connection_timeout(Duration::from_secs(15))
})
.build())
}
impl From<noise::Error> for P2pError {
fn from(e: noise::Error) -> Self {
P2pError::InitNoise(e.to_string())
}
}
}
#[cfg(target_arch = "wasm32")]
mod imp {
use super::*;
use libp2p::webtransport_websys;
pub(crate) fn new_swarm<B>(keypair: Keypair, behaviour: B) -> Result<Swarm<B>, P2pError>
where
B: NetworkBehaviour,
{
Ok(SwarmBuilder::with_existing_identity(keypair)
.with_wasm_bindgen()
.with_other_transport(|local_keypair| {
let config = webtransport_websys::Config::new(local_keypair);
webtransport_websys::Transport::new(config)
})
.expect("webtransport_websys::Transport is infallible")
.with_behaviour(|_| behaviour)
.expect("Moving behaviour doesn't fail")
.with_swarm_config(|config| {
// TODO: Refactor code to avoid being idle. This can be done by preloading a
// handler. This is how they fixed Kademlia:
// https://github.com/libp2p/rust-libp2p/pull/4675/files
config.with_idle_connection_timeout(Duration::from_secs(15))
})
.build())
}
}