1
//! Code to construct paths to a directory for non-anonymous downloads
2
use super::TorPath;
3
use crate::Result;
4
use tor_guardmgr::{GuardMgr, GuardMonitor, GuardUsable};
5
use tor_rtcompat::Runtime;
6

            
7
/// A PathBuilder that can connect to a directory.
8
#[non_exhaustive]
9
pub(crate) struct DirPathBuilder {}
10

            
11
impl Default for DirPathBuilder {
12
    fn default() -> Self {
13
        Self::new()
14
    }
15
}
16

            
17
impl DirPathBuilder {
18
    /// Create a new DirPathBuilder.
19
328
    pub(crate) fn new() -> Self {
20
328
        DirPathBuilder {}
21
328
    }
22

            
23
    /// Try to create and return a path corresponding to the requirements of
24
    /// this builder.
25
328
    pub(crate) fn pick_path<'a, RT: Runtime>(
26
328
        &self,
27
328
        guards: &GuardMgr<RT>,
28
328
    ) -> Result<(TorPath<'a>, GuardMonitor, GuardUsable)> {
29
328
        let guard_usage = tor_guardmgr::GuardUsageBuilder::default()
30
328
            .kind(tor_guardmgr::GuardUsageKind::OneHopDirectory)
31
328
            .build()
32
328
            .expect("Unable to build directory guard usage");
33
328
        let (guard, mon, usable) = guards.select_guard(guard_usage)?;
34
328
        Ok((TorPath::new_one_hop_owned(&guard), mon, usable))
35
328
    }
36
}
37

            
38
#[cfg(test)]
39
mod test {
40
    // @@ begin test lint list maintained by maint/add_warning @@
41
    #![allow(clippy::bool_assert_comparison)]
42
    #![allow(clippy::clone_on_copy)]
43
    #![allow(clippy::dbg_macro)]
44
    #![allow(clippy::mixed_attributes_style)]
45
    #![allow(clippy::print_stderr)]
46
    #![allow(clippy::print_stdout)]
47
    #![allow(clippy::single_char_pattern)]
48
    #![allow(clippy::unwrap_used)]
49
    #![allow(clippy::unchecked_duration_subtraction)]
50
    #![allow(clippy::useless_vec)]
51
    #![allow(clippy::needless_pass_by_value)]
52
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
53

            
54
    use super::*;
55
    use std::collections::HashSet;
56
    use tor_guardmgr::TestConfig;
57
    use tor_linkspec::RelayIds;
58
    use tor_netdir::testnet;
59
    use tor_persist::TestingStateMgr;
60

            
61
    #[test]
62
    fn dirpath() {
63
        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
64
            let netdir = testnet::construct_netdir().unwrap_if_sufficient().unwrap();
65
            let statemgr = TestingStateMgr::new();
66
            let guards =
67
                tor_guardmgr::GuardMgr::new(rt.clone(), statemgr, &TestConfig::default()).unwrap();
68
            guards.install_test_netdir(&netdir);
69

            
70
            let mut distinct_guards = HashSet::new();
71

            
72
            // This is a nice easy case, since we tested the harder cases
73
            // in guard-spec.  We'll just have every path succeed.
74
            for _ in 0..40 {
75
                let (path, mon, usable) = DirPathBuilder::new().pick_path(&guards).unwrap();
76
                if let crate::path::TorPathInner::OwnedOneHop(relay) = path.inner {
77
                    distinct_guards.insert(RelayIds::from_relay_ids(&relay));
78
                    mon.succeeded();
79
                    assert!(usable.await.unwrap());
80
                } else {
81
                    panic!("Generated the wrong kind of path.");
82
                }
83
            }
84
            assert_eq!(
85
                distinct_guards.len(),
86
                netdir.params().guard_dir_use_parallelism.get() as usize
87
            );
88
        });
89
    }
90
}