diff --git a/ant-bootstrap/src/initial_peers.rs b/ant-bootstrap/src/initial_peers.rs index 55b3f78e16..27e59d899c 100644 --- a/ant-bootstrap/src/initial_peers.rs +++ b/ant-bootstrap/src/initial_peers.rs @@ -107,14 +107,21 @@ impl PeersArgs { return Ok(vec![]); } + let mut bootstrap_addresses = vec![]; + + // Read from ANT_PEERS environment variable if present + bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env()); + + if !bootstrap_addresses.is_empty() { + return Ok(bootstrap_addresses); + } + // If local mode is enabled, return empty store (will use mDNS) if self.local || cfg!(feature = "local") { info!("Local mode enabled, using only local discovery."); return Ok(vec![]); } - let mut bootstrap_addresses = vec![]; - // Add addrs from arguments if present for addr in &self.addrs { if let Some(addr) = craft_valid_multiaddr(addr, false) { @@ -124,8 +131,6 @@ impl PeersArgs { warn!("Invalid multiaddress format from arguments: {addr}"); } } - // Read from ANT_PEERS environment variable if present - bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env()); if let Some(count) = count { if bootstrap_addresses.len() >= count { diff --git a/autonomi/src/client/mod.rs b/autonomi/src/client/mod.rs index fae0a87ba8..05ef75d789 100644 --- a/autonomi/src/client/mod.rs +++ b/autonomi/src/client/mod.rs @@ -34,7 +34,7 @@ pub mod wasm; mod rate_limiter; mod utils; -use ant_bootstrap::{BootstrapCacheConfig, BootstrapCacheStore}; +use ant_bootstrap::{BootstrapCacheConfig, BootstrapCacheStore, PeersArgs}; pub use ant_evm::Amount; use ant_evm::EvmNetwork; @@ -71,6 +71,17 @@ pub struct Client { pub(crate) evm_network: EvmNetwork, } +/// Configuration for [`Client::init_with_config`]. +#[derive(Debug, Clone, Default)] +pub struct ClientConfig { + /// Whether we're expected to connect to a local network. + pub local: bool, + /// List of peers to connect to. + /// + /// If not provided, the client will use the default bootstrap peers. + pub peers: Option>, +} + /// Error returned by [`Client::connect`]. #[derive(Debug, thiserror::Error)] pub enum ConnectError { @@ -80,9 +91,55 @@ pub enum ConnectError { /// Same as [`ConnectError::TimedOut`] but with a list of incompatible protocols. #[error("Could not connect to peers due to incompatible protocol: {0:?}")] TimedOutWithIncompatibleProtocol(HashSet, String), + + /// An error occurred while bootstrapping the client. + #[error("Failed to bootstrap the client")] + Bootstrap(#[from] ant_bootstrap::Error), } impl Client { + pub async fn init() -> Result { + Self::init_with_config(ClientConfig::default()).await + } + + pub async fn init_with_config(config: ClientConfig) -> Result { + let (network, event_receiver) = build_client_and_run_swarm(config.local); + + let peers_args = PeersArgs { + disable_mainnet_contacts: config.local, + addrs: config.peers.unwrap_or_default(), + ..Default::default() + }; + + let peers = match peers_args.get_addrs(None, None).await { + Ok(peers) => peers, + Err(e) => return Err(e.into()), + }; + + let network_clone = network.clone(); + let peers = peers.to_vec(); + let _handle = ant_networking::target_arch::spawn(async move { + for addr in peers { + if let Err(err) = network_clone.dial(addr.clone()).await { + error!("Failed to dial addr={addr} with err: {err:?}"); + eprintln!("addr={addr} Failed to dial: {err:?}"); + }; + } + }); + + // Wait until we have added a few peers to our routing table. + let (sender, receiver) = futures::channel::oneshot::channel(); + ant_networking::target_arch::spawn(handle_event_receiver(event_receiver, sender)); + receiver.await.expect("sender should not close")?; + debug!("Client is connected to the network"); + + Ok(Self { + network, + client_event_sender: Arc::new(None), + evm_network: Default::default(), + }) + } + /// Connect to the network. /// /// This will timeout after [`CONNECT_TIMEOUT_SECS`] secs. diff --git a/autonomi/tests/put.rs b/autonomi/tests/put.rs index f5d411e691..ca4a808c7e 100644 --- a/autonomi/tests/put.rs +++ b/autonomi/tests/put.rs @@ -7,24 +7,24 @@ // permissions and limitations relating to use of the SAFE Network Software. use ant_logging::LogBuilder; -use autonomi::Client; +use autonomi::{client::ClientConfig, Client}; use eyre::Result; -use std::time::Duration; -use test_utils::{evm::get_funded_wallet, gen_random_data, peers_from_env}; -use tokio::time::sleep; +use test_utils::{evm::get_funded_wallet, gen_random_data}; #[tokio::test] async fn put() -> Result<()> { let _log_appender_guard = LogBuilder::init_single_threaded_tokio_test("put", false); - let client = Client::connect(&peers_from_env()?).await?; + let client = Client::init_with_config(ClientConfig { + local: true, + ..Default::default() + }) + .await?; let wallet = get_funded_wallet(); let data = gen_random_data(1024 * 1024 * 10); let addr = client.data_put_public(data.clone(), wallet.into()).await?; - sleep(Duration::from_secs(10)).await; - let data_fetched = client.data_get_public(addr).await?; assert_eq!(data, data_fetched, "data fetched should match data put");