//! Implement traits from [`crate::mgr`] for the circuit types we use. use crate::mgr::{self}; use crate::usage::{SupportedCircUsage, TargetCircUsage}; use crate::{DirInfo, Result}; use async_trait::async_trait; use rand::{rngs::StdRng, SeedableRng}; use std::convert::TryInto; use std::sync::Arc; use std::time::Duration; use tor_chanmgr::ChanMgr; use tor_proto::circuit::ClientCirc; use tor_rtcompat::{Runtime, SleepProviderExt}; impl mgr::AbstractCirc for tor_proto::circuit::ClientCirc { type Id = tor_proto::circuit::UniqId; fn id(&self) -> Self::Id { self.unique_id() } fn usable(&self) -> bool { !self.is_closing() } } /// The information generated by circuit planning, and used to build a /// circuit. pub(crate) struct Plan { /// The supported usage that the circuit will have when complete final_spec: SupportedCircUsage, /// An owned copy of the path to build. // TODO: it would be nice if this weren't owned. path: crate::path::OwnedPath, /// The protocol parameters to use when constructing the circuit. params: tor_proto::circuit::CircParameters, } /// An object that knows how to build circuits. pub(crate) struct Builder { /// The runtime used by this circuit builder. runtime: R, /// A channel manager that this circuit builder uses to make chanels. chanmgr: Arc>, } impl Builder { /// Construct a new Builder pub(crate) fn new(runtime: R, chanmgr: Arc>) -> Self { Builder { runtime, chanmgr } } } #[async_trait] impl crate::mgr::AbstractCircBuilder for Builder { type Circ = ClientCirc; type Spec = SupportedCircUsage; type Plan = Plan; fn plan_circuit( &self, usage: &TargetCircUsage, dir: DirInfo<'_>, ) -> Result<(Plan, SupportedCircUsage)> { let mut rng = rand::thread_rng(); let (path, final_spec) = usage.build_path(&mut rng, dir)?; let plan = Plan { final_spec: final_spec.clone(), path: (&path).try_into()?, params: dir.circ_params(), }; Ok((plan, final_spec)) } async fn build_circuit(&self, plan: Plan) -> Result<(SupportedCircUsage, Arc)> { let delay = Duration::from_secs(5); // TODO: make this configurable and inferred. let Plan { final_spec, path, params, } = plan; let mut rng = StdRng::from_rng(rand::thread_rng()).expect("couldn't construct temporary rng"); let build_future = path.build_circuit(&mut rng, &self.runtime, &self.chanmgr, ¶ms); let circuit = self.runtime.timeout(delay, build_future).await??; Ok((final_spec, circuit)) } fn launch_parallelism(&self, spec: &TargetCircUsage) -> usize { match spec { TargetCircUsage::Dir => 3, _ => 1, } } fn select_parallelism(&self, spec: &TargetCircUsage) -> usize { self.launch_parallelism(spec) } }