//! Code to construct paths to a directory for non-anonymous downloads use super::TorPath; use crate::Result; use tor_guardmgr::{GuardMgr, GuardMonitor, GuardUsable}; use tor_rtcompat::Runtime; use tracing::instrument; /// A PathBuilder that can connect to a directory. #[non_exhaustive] pub(crate) struct DirPathBuilder {} impl Default for DirPathBuilder { fn default() -> Self { Self::new() } } impl DirPathBuilder { /// Create a new DirPathBuilder. pub(crate) fn new() -> Self { DirPathBuilder {} } /// Try to create and return a path corresponding to the requirements of /// this builder. #[instrument(skip_all, level = "trace")] pub(crate) fn pick_path<'a, RT: Runtime>( &self, guards: &GuardMgr, ) -> Result<(TorPath<'a>, GuardMonitor, GuardUsable)> { let guard_usage = tor_guardmgr::GuardUsageBuilder::default() .kind(tor_guardmgr::GuardUsageKind::OneHopDirectory) .build() .expect("Unable to build directory guard usage"); let (guard, mon, usable) = guards.select_guard(guard_usage)?; Ok((TorPath::new_one_hop_owned(&guard), mon, usable)) } } #[cfg(test)] mod test { // @@ begin test lint list maintained by maint/add_warning @@ #![allow(clippy::bool_assert_comparison)] #![allow(clippy::clone_on_copy)] #![allow(clippy::dbg_macro)] #![allow(clippy::mixed_attributes_style)] #![allow(clippy::print_stderr)] #![allow(clippy::print_stdout)] #![allow(clippy::single_char_pattern)] #![allow(clippy::unwrap_used)] #![allow(clippy::unchecked_time_subtraction)] #![allow(clippy::useless_vec)] #![allow(clippy::needless_pass_by_value)] //! use super::*; use std::collections::HashSet; use tor_guardmgr::TestConfig; use tor_linkspec::RelayIds; use tor_netdir::testnet; use tor_persist::TestingStateMgr; #[test] fn dirpath() { tor_rtcompat::test_with_all_runtimes!(|rt| async move { let netdir = testnet::construct_netdir().unwrap_if_sufficient().unwrap(); let statemgr = TestingStateMgr::new(); let guards = tor_guardmgr::GuardMgr::new(rt.clone(), statemgr, &TestConfig::default()).unwrap(); guards.install_test_netdir(&netdir); let mut distinct_guards = HashSet::new(); // This is a nice easy case, since we tested the harder cases // in guard-spec. We'll just have every path succeed. for _ in 0..40 { let (path, mon, usable) = DirPathBuilder::new().pick_path(&guards).unwrap(); if let crate::path::TorPathInner::OwnedOneHop(relay) = path.inner { distinct_guards.insert(RelayIds::from_relay_ids(&relay)); mon.succeeded(); assert!(usable.await.unwrap()); } else { panic!("Generated the wrong kind of path."); } } assert_eq!( distinct_guards.len(), netdir.params().guard_dir_use_parallelism.get() as usize ); }); } }