use std::sync::{Arc, Mutex};
use arti_client::{DataStream, TorAddr, TorClient, TorClientConfig};
use tor_rtcompat::tokio::TokioRuntimeHandle;
use tower::Service;
use zebra_chain::parameters::Network;
use crate::{
connect_isolated, connect_isolated_with_inbound, peer::Client as ZebraClient, BoxError,
Request, Response,
};
#[cfg(test)]
mod tests;
lazy_static::lazy_static! {
pub static ref SHARED_TOR_CLIENT: Arc<Mutex<Option<TorClient<TokioRuntimeHandle>>>> =
Arc::new(Mutex::new(None));
}
pub async fn connect_isolated_tor(
network: Network,
hostname: String,
user_agent: String,
) -> Result<ZebraClient, BoxError> {
let tor_stream = new_tor_stream(hostname).await?;
connect_isolated(network, tor_stream, user_agent).await
}
pub async fn connect_isolated_tor_with_inbound<InboundService>(
network: Network,
hostname: String,
user_agent: String,
inbound_service: InboundService,
) -> Result<ZebraClient, BoxError>
where
InboundService:
Service<Request, Response = Response, Error = BoxError> + Clone + Send + 'static,
InboundService::Future: Send,
{
let tor_stream = new_tor_stream(hostname).await?;
connect_isolated_with_inbound(network, tor_stream, user_agent, inbound_service).await
}
async fn new_tor_stream(hostname: String) -> Result<DataStream, BoxError> {
let addr = TorAddr::from(hostname)?;
let tor_client = match cloned_tor_client() {
Some(tor_client) => tor_client,
None => new_tor_client().await?,
};
let tor_stream = tor_client.connect(addr, None).await?;
Ok(tor_stream)
}
async fn new_tor_client() -> Result<TorClient<TokioRuntimeHandle>, BoxError> {
let runtime = tokio::runtime::Handle::current();
let runtime = TokioRuntimeHandle::new(runtime);
let tor_client = TorClient::bootstrap(runtime, TorClientConfig::default()).await?;
let mut shared_tor_client = SHARED_TOR_CLIENT
.lock()
.expect("panic in shared tor client mutex guard");
*shared_tor_client = Some(tor_client.isolated_client());
Ok(tor_client)
}
fn cloned_tor_client() -> Option<TorClient<TokioRuntimeHandle>> {
SHARED_TOR_CLIENT
.lock()
.expect("panic in shared tor client mutex guard")
.as_ref()
.map(TorClient::isolated_client)
}