use std::net::{IpAddr, SocketAddr};
use std::{path::PathBuf, time::Duration};
use bitcoin::Network;
use super::{client::Client, config::NodeConfig, node::Node};
#[cfg(feature = "rusqlite")]
use crate::db::error::SqlInitializationError;
#[cfg(feature = "rusqlite")]
use crate::db::sqlite::{headers::SqliteHeaderDb, peers::SqlitePeerDb};
use crate::network::dns::{DnsResolver, DNS_RESOLVER_PORT};
use crate::network::ConnectionType;
use crate::{
chain::checkpoints::HeaderCheckpoint,
db::traits::{HeaderStore, PeerStore},
};
use crate::{PeerStoreSizeConfig, TrustedPeer};
#[cfg(feature = "rusqlite")]
pub type NodeDefault = Node<SqliteHeaderDb, SqlitePeerDb>;
const MIN_PEERS: u8 = 1;
const MAX_PEERS: u8 = 15;
pub struct Builder {
config: NodeConfig,
network: Network,
}
impl Builder {
pub fn new(network: Network) -> Self {
Self {
config: NodeConfig::default(),
network,
}
}
pub fn network(&self) -> Network {
self.network
}
pub fn add_peers(mut self, whitelist: impl IntoIterator<Item = TrustedPeer>) -> Self {
self.config.white_list.extend(whitelist);
self
}
pub fn add_peer(mut self, trusted_peer: impl Into<TrustedPeer>) -> Self {
self.config.white_list.push(trusted_peer.into());
self
}
pub fn data_dir(mut self, path: impl Into<PathBuf>) -> Self {
self.config.data_path = Some(path.into());
self
}
pub fn required_peers(mut self, num_peers: u8) -> Self {
self.config.required_peers = num_peers.clamp(MIN_PEERS, MAX_PEERS);
self
}
pub fn peer_db_size(mut self, target: PeerStoreSizeConfig) -> Self {
self.config.target_peer_size = target;
self
}
pub fn after_checkpoint(mut self, checkpoint: impl Into<HeaderCheckpoint>) -> Self {
self.config.header_checkpoint = Some(checkpoint.into());
self
}
pub fn handshake_timeout(mut self, handshake_timeout: impl Into<Duration>) -> Self {
self.config.peer_timeout_config.handshake_timeout = handshake_timeout.into();
self
}
pub fn response_timeout(mut self, response_timeout: impl Into<Duration>) -> Self {
self.config.peer_timeout_config.response_timeout = response_timeout.into();
self
}
pub fn maximum_connection_time(mut self, max_connection_time: impl Into<Duration>) -> Self {
self.config.peer_timeout_config.max_connection_time = max_connection_time.into();
self
}
pub fn dns_resolver(mut self, resolver: impl Into<IpAddr>) -> Self {
let ip_addr = resolver.into();
let socket_addr = SocketAddr::new(ip_addr, DNS_RESOLVER_PORT);
self.config.dns_resolver = DnsResolver { socket_addr };
self
}
pub fn socks5_proxy(mut self, proxy: impl Into<SocketAddr>) -> Self {
let ip_addr = proxy.into();
let connection = ConnectionType::Socks5Proxy(ip_addr);
self.config.connection_type = connection;
self
}
#[cfg(feature = "rusqlite")]
pub fn build(&mut self) -> Result<(NodeDefault, Client), SqlInitializationError> {
let peer_store = SqlitePeerDb::new(self.network, self.config.data_path.clone())?;
let header_store = SqliteHeaderDb::new(self.network, self.config.data_path.clone())?;
Ok(Node::new(
self.network,
core::mem::take(&mut self.config),
peer_store,
header_store,
))
}
pub fn build_with_databases<H: HeaderStore + 'static, P: PeerStore + 'static>(
&mut self,
peer_store: P,
header_store: H,
) -> (Node<H, P>, Client) {
Node::new(
self.network,
core::mem::take(&mut self.config),
peer_store,
header_store,
)
}
}