use super::{
behaviour::{DerivedDiscoveryBehaviour, DiscoveryBehaviour},
new_kademlia,
};
use crate::error::Error;
use blueprint_core::warn;
use blueprint_crypto::KeyType;
use libp2p::{
Multiaddr, PeerId, StreamProtocol, autonat, identify, identity::PublicKey, mdns, relay, upnp,
};
use std::{
collections::{HashMap, HashSet, VecDeque},
time::Duration,
};
pub struct DiscoveryConfig<K: KeyType> {
local_peer_id: PeerId,
local_public_key: PublicKey,
bootstrap_peers: Vec<(PeerId, Multiaddr)>,
relay_nodes: Vec<(PeerId, Multiaddr)>,
target_peer_count: u32,
enable_mdns: bool,
enable_kademlia: bool,
enable_upnp: bool,
enable_relay: bool,
network_name: String,
protocol_version: String,
_marker: blueprint_std::marker::PhantomData<K>,
}
impl<K: KeyType> DiscoveryConfig<K> {
#[must_use]
pub fn new(local_public_key: PublicKey, network_name: impl Into<String>) -> Self {
Self {
local_peer_id: local_public_key.to_peer_id(),
local_public_key,
bootstrap_peers: Vec::new(),
relay_nodes: Vec::new(),
target_peer_count: 25, enable_mdns: true, enable_kademlia: true, enable_upnp: true, enable_relay: true, network_name: network_name.into(),
protocol_version: String::from("blueprint/1.0.0"), _marker: blueprint_std::marker::PhantomData,
}
}
#[must_use]
pub fn protocol_version(mut self, version: impl Into<String>) -> Self {
self.protocol_version = version.into();
self
}
#[must_use]
pub fn bootstrap_peers(mut self, peers: Vec<(PeerId, Multiaddr)>) -> Self {
self.bootstrap_peers = peers;
self
}
#[must_use]
pub fn relay_nodes(mut self, nodes: Vec<(PeerId, Multiaddr)>) -> Self {
self.relay_nodes = nodes;
self
}
#[must_use]
pub fn target_peer_count(mut self, count: u32) -> Self {
self.target_peer_count = count;
self
}
#[must_use]
pub fn mdns(mut self, enable: bool) -> Self {
self.enable_mdns = enable;
self
}
#[must_use]
pub fn kademlia(mut self, enable: bool) -> Self {
self.enable_kademlia = enable;
self
}
#[must_use]
pub fn upnp(mut self, enable: bool) -> Self {
self.enable_upnp = enable;
self
}
#[must_use]
pub fn relay(mut self, enable: bool) -> Self {
self.enable_relay = enable;
self
}
pub fn build(self) -> Result<DiscoveryBehaviour<K>, Error> {
let kademlia_opt = if self.enable_kademlia {
let protocol = StreamProtocol::try_from_owned(format!(
"/blueprint/kad/{}/kad/1.0.0",
self.network_name
))?;
let mut kademlia = new_kademlia(self.local_peer_id, protocol);
for (peer_id, addr) in &self.bootstrap_peers {
kademlia.add_address(peer_id, addr.clone());
}
if let Err(e) = kademlia.bootstrap() {
warn!("Kademlia bootstrap failed: {}", e);
}
Some(kademlia)
} else {
None
};
let mdns_opt = if self.enable_mdns {
Some(mdns::Behaviour::new(
mdns::Config::default(),
self.local_peer_id,
)?)
} else {
None
};
let upnp_opt = if self.enable_upnp {
Some(upnp::tokio::Behaviour::default())
} else {
None
};
let relay_opt = if self.enable_relay {
let relay = relay::Behaviour::new(self.local_peer_id, relay::Config::default());
Some(relay)
} else {
None
};
let behaviour = DerivedDiscoveryBehaviour {
kademlia: kademlia_opt.into(),
mdns: mdns_opt.into(),
identify: identify::Behaviour::new(
identify::Config::new(self.protocol_version, self.local_public_key)
.with_agent_version(format!("blueprint-{}", env!("CARGO_PKG_VERSION")))
.with_push_listen_addr_updates(true),
),
autonat: autonat::Behaviour::new(self.local_peer_id, autonat::Config::default()),
upnp: upnp_opt.into(),
relay: relay_opt.into(),
};
Ok(DiscoveryBehaviour::<K> {
discovery: behaviour,
peers: HashSet::new(),
peer_info: HashMap::new(),
target_peer_count: self.target_peer_count,
next_kad_random_query: tokio::time::interval(Duration::from_secs(1)),
duration_to_next_kad: Duration::from_secs(1),
pending_events: VecDeque::new(),
n_node_connected: 0,
pending_dial_opts: VecDeque::new(),
_marker: blueprint_std::marker::PhantomData,
})
}
}