Loading crates/arti-client/examples/lazy-init.rs +5 −7 Original line number Diff line number Diff line use anyhow::Result; use arti_client::{BootstrapBehavior, TorClient, TorClientConfig}; use arti_client::{TorClient, TorClientConfig}; use tokio_crate as tokio; use tor_rtcompat::tokio::TokioNativeTlsRuntime; Loading Loading @@ -29,12 +29,10 @@ pub fn get_tor_client() -> Result<TorClient<TokioNativeTlsRuntime>> { eprintln!("creating unbootstrapped Tor client"); // Create an unbootstrapped Tor client. Bootstrapping will happen when the client is used, // since we specified `BootstrapBehavior::Ondemand`. Ok(TorClient::create_unbootstrapped( rt, config, BootstrapBehavior::OnDemand, )?) // since `BootstrapBehavior::OnDemand` is the default. Ok(TorClient::builder(rt) .config(config) .create_unbootstrapped()?) })?; Ok(client.clone()) Loading crates/arti-client/src/builder.rs 0 → 100644 +78 −0 Original line number Diff line number Diff line //! Types for conveniently constructing TorClients. #![allow(missing_docs, clippy::missing_docs_in_private_items)] use crate::{err::ErrorDetail, BootstrapBehavior, Result, TorClient, TorClientConfig}; use tor_rtcompat::Runtime; /// An object for constructing a [`TorClient`]. /// /// Returned by [`TorClient::builder()`]. #[derive(Debug, Clone)] #[must_use] pub struct TorClientBuilder<R> { /// The runtime for the client to use runtime: R, /// The client's configuration. config: TorClientConfig, /// How the client should behave when it is asked to do something on the Tor /// network before `bootstrap()` is called. bootstrap_behavior: BootstrapBehavior, } impl<R> TorClientBuilder<R> { /// Construct a new TorClientBuilder with the given runtime. pub(crate) fn new(runtime: R) -> Self { Self { runtime, config: TorClientConfig::default(), bootstrap_behavior: BootstrapBehavior::default(), } } /// Set the configuration for the `TorClient` under construction. /// /// If not called, then a compiled-in default configuration will be used. pub fn config(mut self, config: TorClientConfig) -> Self { self.config = config; self } /// Set the bootstrap behavior for the `TorClient` under construction. /// /// If not called, then the default ([`BootstrapBehavior::OnDemand`]) will /// be used. pub fn bootstrap_behavior(mut self, bootstrap_behavior: BootstrapBehavior) -> Self { self.bootstrap_behavior = bootstrap_behavior; self } } impl<R: Runtime> TorClientBuilder<R> { /// Create a `TorClient` from this builder, without automatically launching /// the bootstrap process. /// /// If you have left the default [`BootstrapBehavior`] in place, the client /// will bootstrap itself as soon any attempt is made to use it. You can /// also bootstrap the client yourself by running its /// [`bootstrap()`](TorClient::bootstrap) method. /// /// If you have replaced the default behavior with [`BootstrapBehavior::Manual`], /// any attempts to use the client will fail with an error of kind /// [`ErrorKind::BootstrapRequired`](crate::ErrorKind::BootstrapRequired), /// until you have called [`TorClient::bootstrap`] yourself. /// This option is useful if you wish to have control over the bootstrap /// process (for example, you might wish to avoid initiating network /// connections until explicit user confirmation is given). pub fn create_unbootstrapped(self) -> Result<TorClient<R>> { TorClient::create_inner(self.runtime, self.config, self.bootstrap_behavior) .map_err(ErrorDetail::into) } /// Create a TorClient from this builder, and try to bootstrap it. pub async fn create_bootstrapped(self) -> Result<TorClient<R>> { let r = self.create_unbootstrapped()?; r.bootstrap().await?; Ok(r) } } crates/arti-client/src/client.rs +28 −43 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; use crate::err::ErrorDetail; use crate::status; use crate::{status, TorClientBuilder}; #[cfg(feature = "async-std")] use tor_rtcompat::async_std::PreferredRuntime as PreferredAsyncStdRuntime; #[cfg(feature = "tokio")] Loading Loading @@ -88,8 +88,6 @@ pub struct TorClient<R: Runtime> { } /// Preferences for whether a [`TorClient`] should bootstrap on its own or not. /// /// *[See the documentation for `create_unbootstrapped` for a full explanation.](TorClient::create_unbootstrapped)* #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum BootstrapBehavior { Loading @@ -105,6 +103,12 @@ pub enum BootstrapBehavior { Manual, } impl Default for BootstrapBehavior { fn default() -> Self { BootstrapBehavior::OnDemand } } /// Preferences for how to route a stream over the Tor network. #[derive(Debug, Clone, Default)] pub struct StreamPrefs { Loading Loading @@ -312,57 +316,31 @@ impl TorClient<PreferredAsyncStdRuntime> { } impl<R: Runtime> TorClient<R> { /// Return a new builder for creating TorClient objects. pub fn builder(runtime: R) -> TorClientBuilder<R> { TorClientBuilder::new(runtime) } /// Bootstrap a connection to the Tor network, using the provided `config` and `runtime` (a /// [`tor_rtcompat`] [`Runtime`](tor_rtcompat::Runtime)). /// /// Returns a client once there is enough directory material to /// connect safely over the Tor network. /// /// Consider using [`create_unbootstrapped`](TorClient::create_unbootstrapped) /// if you wish to create a client immediately, and defer bootstrapping until later. /// Consider using a [`TorClientBuilder`] for more fine-grained control. pub async fn create_bootstrapped( runtime: R, config: TorClientConfig, ) -> crate::Result<TorClient<R>> { let ret = TorClient::create_unbootstrapped(runtime, config, BootstrapBehavior::Manual)?; ret.bootstrap().await?; Ok(ret) } /// Create a `TorClient` without bootstrapping a connection to the network. /// /// The behaviour of this client depends on the value of `autobootstrap`. /// /// ## If `autobootstrap` is [`Manual`](BootstrapBehavior::Manual) /// /// If `autobootstrap` is set to `Manual`, the returned `TorClient` (and its clones) will never /// attempt to bootstrap themselves. You must manually call [`bootstrap`](TorClient::bootstrap) /// in order for the client(s) to become usable. /// /// Attempts to use the client (e.g. by creating connections or resolving hosts over the Tor /// network) before calling [`bootstrap`](TorClient::bootstrap) will fail, and /// return an error that has kind [`ErrorKind::BootstrapRequired`](crate::ErrorKind::BootstrapRequired). /// /// This option is useful if you wish to have control over the bootstrap process (for example, /// you might wish to avoid initiating network connections until explicit user confirmation /// is given). /// /// ## If `autobootstrap` is [`OnDemand`](BootstrapBehavior::OnDemand) /// /// If `autoboostrap` is set to `OnDemand`, the returned `TorClient` (and its clones) will /// automatically bootstrap before doing any operation that would require them to be /// bootstrapped. pub fn create_unbootstrapped( runtime: R, config: TorClientConfig, autobootstrap: BootstrapBehavior, ) -> crate::Result<Self> { TorClient::create_inner(runtime, config, autobootstrap).map_err(ErrorDetail::into) Self::builder(runtime) .config(config) .create_bootstrapped() .await } /// Implementation of `create_unbootstrapped`, split out in order to avoid manually specifying /// double error conversions. fn create_inner( pub(crate) fn create_inner( runtime: R, config: TorClientConfig, autobootstrap: BootstrapBehavior, Loading Loading @@ -1085,7 +1063,11 @@ mod test { let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir) .build() .unwrap(); let _ = TorClient::create_unbootstrapped(rt, cfg, BootstrapBehavior::Manual).unwrap(); let _ = TorClient::builder(rt) .config(cfg) .bootstrap_behavior(BootstrapBehavior::Manual) .create_unbootstrapped() .unwrap(); }); } Loading @@ -1097,8 +1079,11 @@ mod test { let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir) .build() .unwrap(); let client = TorClient::create_unbootstrapped(rt, cfg, BootstrapBehavior::Manual).unwrap(); let client = TorClient::builder(rt) .config(cfg) .bootstrap_behavior(BootstrapBehavior::Manual) .create_unbootstrapped() .unwrap(); let result = client.connect("example.com:80").await; assert!(result.is_err()); assert_eq!(result.err().unwrap().kind(), ErrorKind::BootstrapRequired); Loading crates/arti-client/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -190,12 +190,14 @@ #![deny(clippy::unwrap_used)] mod address; mod builder; mod client; pub mod config; pub mod status; pub use address::{DangerouslyIntoTorAddr, IntoTorAddr, TorAddr, TorAddrError}; pub use builder::TorClientBuilder; pub use client::{BootstrapBehavior, StreamPrefs, TorClient}; pub use config::TorClientConfig; Loading crates/arti/src/main.rs +4 −1 Original line number Diff line number Diff line Loading @@ -113,7 +113,10 @@ async fn run<R: Runtime>( // for bootstrap to complete, rather than getting errors. use arti_client::BootstrapBehavior::OnDemand; use futures::FutureExt; let client = TorClient::create_unbootstrapped(runtime.clone(), client_config, OnDemand)?; let client = TorClient::builder(runtime.clone()) .config(client_config) .bootstrap_behavior(OnDemand) .create_unbootstrapped()?; if arti_config.application().watch_configuration() { watch_cfg::watch_for_config_changes(config_sources, arti_config, client.clone())?; } Loading Loading
crates/arti-client/examples/lazy-init.rs +5 −7 Original line number Diff line number Diff line use anyhow::Result; use arti_client::{BootstrapBehavior, TorClient, TorClientConfig}; use arti_client::{TorClient, TorClientConfig}; use tokio_crate as tokio; use tor_rtcompat::tokio::TokioNativeTlsRuntime; Loading Loading @@ -29,12 +29,10 @@ pub fn get_tor_client() -> Result<TorClient<TokioNativeTlsRuntime>> { eprintln!("creating unbootstrapped Tor client"); // Create an unbootstrapped Tor client. Bootstrapping will happen when the client is used, // since we specified `BootstrapBehavior::Ondemand`. Ok(TorClient::create_unbootstrapped( rt, config, BootstrapBehavior::OnDemand, )?) // since `BootstrapBehavior::OnDemand` is the default. Ok(TorClient::builder(rt) .config(config) .create_unbootstrapped()?) })?; Ok(client.clone()) Loading
crates/arti-client/src/builder.rs 0 → 100644 +78 −0 Original line number Diff line number Diff line //! Types for conveniently constructing TorClients. #![allow(missing_docs, clippy::missing_docs_in_private_items)] use crate::{err::ErrorDetail, BootstrapBehavior, Result, TorClient, TorClientConfig}; use tor_rtcompat::Runtime; /// An object for constructing a [`TorClient`]. /// /// Returned by [`TorClient::builder()`]. #[derive(Debug, Clone)] #[must_use] pub struct TorClientBuilder<R> { /// The runtime for the client to use runtime: R, /// The client's configuration. config: TorClientConfig, /// How the client should behave when it is asked to do something on the Tor /// network before `bootstrap()` is called. bootstrap_behavior: BootstrapBehavior, } impl<R> TorClientBuilder<R> { /// Construct a new TorClientBuilder with the given runtime. pub(crate) fn new(runtime: R) -> Self { Self { runtime, config: TorClientConfig::default(), bootstrap_behavior: BootstrapBehavior::default(), } } /// Set the configuration for the `TorClient` under construction. /// /// If not called, then a compiled-in default configuration will be used. pub fn config(mut self, config: TorClientConfig) -> Self { self.config = config; self } /// Set the bootstrap behavior for the `TorClient` under construction. /// /// If not called, then the default ([`BootstrapBehavior::OnDemand`]) will /// be used. pub fn bootstrap_behavior(mut self, bootstrap_behavior: BootstrapBehavior) -> Self { self.bootstrap_behavior = bootstrap_behavior; self } } impl<R: Runtime> TorClientBuilder<R> { /// Create a `TorClient` from this builder, without automatically launching /// the bootstrap process. /// /// If you have left the default [`BootstrapBehavior`] in place, the client /// will bootstrap itself as soon any attempt is made to use it. You can /// also bootstrap the client yourself by running its /// [`bootstrap()`](TorClient::bootstrap) method. /// /// If you have replaced the default behavior with [`BootstrapBehavior::Manual`], /// any attempts to use the client will fail with an error of kind /// [`ErrorKind::BootstrapRequired`](crate::ErrorKind::BootstrapRequired), /// until you have called [`TorClient::bootstrap`] yourself. /// This option is useful if you wish to have control over the bootstrap /// process (for example, you might wish to avoid initiating network /// connections until explicit user confirmation is given). pub fn create_unbootstrapped(self) -> Result<TorClient<R>> { TorClient::create_inner(self.runtime, self.config, self.bootstrap_behavior) .map_err(ErrorDetail::into) } /// Create a TorClient from this builder, and try to bootstrap it. pub async fn create_bootstrapped(self) -> Result<TorClient<R>> { let r = self.create_unbootstrapped()?; r.bootstrap().await?; Ok(r) } }
crates/arti-client/src/client.rs +28 −43 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; use crate::err::ErrorDetail; use crate::status; use crate::{status, TorClientBuilder}; #[cfg(feature = "async-std")] use tor_rtcompat::async_std::PreferredRuntime as PreferredAsyncStdRuntime; #[cfg(feature = "tokio")] Loading Loading @@ -88,8 +88,6 @@ pub struct TorClient<R: Runtime> { } /// Preferences for whether a [`TorClient`] should bootstrap on its own or not. /// /// *[See the documentation for `create_unbootstrapped` for a full explanation.](TorClient::create_unbootstrapped)* #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum BootstrapBehavior { Loading @@ -105,6 +103,12 @@ pub enum BootstrapBehavior { Manual, } impl Default for BootstrapBehavior { fn default() -> Self { BootstrapBehavior::OnDemand } } /// Preferences for how to route a stream over the Tor network. #[derive(Debug, Clone, Default)] pub struct StreamPrefs { Loading Loading @@ -312,57 +316,31 @@ impl TorClient<PreferredAsyncStdRuntime> { } impl<R: Runtime> TorClient<R> { /// Return a new builder for creating TorClient objects. pub fn builder(runtime: R) -> TorClientBuilder<R> { TorClientBuilder::new(runtime) } /// Bootstrap a connection to the Tor network, using the provided `config` and `runtime` (a /// [`tor_rtcompat`] [`Runtime`](tor_rtcompat::Runtime)). /// /// Returns a client once there is enough directory material to /// connect safely over the Tor network. /// /// Consider using [`create_unbootstrapped`](TorClient::create_unbootstrapped) /// if you wish to create a client immediately, and defer bootstrapping until later. /// Consider using a [`TorClientBuilder`] for more fine-grained control. pub async fn create_bootstrapped( runtime: R, config: TorClientConfig, ) -> crate::Result<TorClient<R>> { let ret = TorClient::create_unbootstrapped(runtime, config, BootstrapBehavior::Manual)?; ret.bootstrap().await?; Ok(ret) } /// Create a `TorClient` without bootstrapping a connection to the network. /// /// The behaviour of this client depends on the value of `autobootstrap`. /// /// ## If `autobootstrap` is [`Manual`](BootstrapBehavior::Manual) /// /// If `autobootstrap` is set to `Manual`, the returned `TorClient` (and its clones) will never /// attempt to bootstrap themselves. You must manually call [`bootstrap`](TorClient::bootstrap) /// in order for the client(s) to become usable. /// /// Attempts to use the client (e.g. by creating connections or resolving hosts over the Tor /// network) before calling [`bootstrap`](TorClient::bootstrap) will fail, and /// return an error that has kind [`ErrorKind::BootstrapRequired`](crate::ErrorKind::BootstrapRequired). /// /// This option is useful if you wish to have control over the bootstrap process (for example, /// you might wish to avoid initiating network connections until explicit user confirmation /// is given). /// /// ## If `autobootstrap` is [`OnDemand`](BootstrapBehavior::OnDemand) /// /// If `autoboostrap` is set to `OnDemand`, the returned `TorClient` (and its clones) will /// automatically bootstrap before doing any operation that would require them to be /// bootstrapped. pub fn create_unbootstrapped( runtime: R, config: TorClientConfig, autobootstrap: BootstrapBehavior, ) -> crate::Result<Self> { TorClient::create_inner(runtime, config, autobootstrap).map_err(ErrorDetail::into) Self::builder(runtime) .config(config) .create_bootstrapped() .await } /// Implementation of `create_unbootstrapped`, split out in order to avoid manually specifying /// double error conversions. fn create_inner( pub(crate) fn create_inner( runtime: R, config: TorClientConfig, autobootstrap: BootstrapBehavior, Loading Loading @@ -1085,7 +1063,11 @@ mod test { let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir) .build() .unwrap(); let _ = TorClient::create_unbootstrapped(rt, cfg, BootstrapBehavior::Manual).unwrap(); let _ = TorClient::builder(rt) .config(cfg) .bootstrap_behavior(BootstrapBehavior::Manual) .create_unbootstrapped() .unwrap(); }); } Loading @@ -1097,8 +1079,11 @@ mod test { let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir) .build() .unwrap(); let client = TorClient::create_unbootstrapped(rt, cfg, BootstrapBehavior::Manual).unwrap(); let client = TorClient::builder(rt) .config(cfg) .bootstrap_behavior(BootstrapBehavior::Manual) .create_unbootstrapped() .unwrap(); let result = client.connect("example.com:80").await; assert!(result.is_err()); assert_eq!(result.err().unwrap().kind(), ErrorKind::BootstrapRequired); Loading
crates/arti-client/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -190,12 +190,14 @@ #![deny(clippy::unwrap_used)] mod address; mod builder; mod client; pub mod config; pub mod status; pub use address::{DangerouslyIntoTorAddr, IntoTorAddr, TorAddr, TorAddrError}; pub use builder::TorClientBuilder; pub use client::{BootstrapBehavior, StreamPrefs, TorClient}; pub use config::TorClientConfig; Loading
crates/arti/src/main.rs +4 −1 Original line number Diff line number Diff line Loading @@ -113,7 +113,10 @@ async fn run<R: Runtime>( // for bootstrap to complete, rather than getting errors. use arti_client::BootstrapBehavior::OnDemand; use futures::FutureExt; let client = TorClient::create_unbootstrapped(runtime.clone(), client_config, OnDemand)?; let client = TorClient::builder(runtime.clone()) .config(client_config) .bootstrap_behavior(OnDemand) .create_unbootstrapped()?; if arti_config.application().watch_configuration() { watch_cfg::watch_for_config_changes(config_sources, arti_config, client.clone())?; } Loading