tor_netdoc/doc/netstatus/rs/build/
each_flavor.rs

1//! router status entry builders - items that vary by consensus flavor
2//!
3//! **This file is reincluded multiple times**,
4//! by the macros in [`crate::doc::ns_variety_definition_macros`],
5//! once for votes, and once for each consensus flavour.
6//! It is *not* a module `crate::doc::netstatus::rs::each_flavor`.
7//!
8//! Each time this file is included by one of the macros mentioned above,
9//! the `ns_***` macros (such as `ns_const_name!`) may expand to different values.
10//!
11//! See [`crate::doc::ns_variety_definition_macros`].
12
13use super::*;
14
15ns_use_this_variety! {
16    use [crate::doc::netstatus::rs]::?::{DocDigest, RouterStatus};
17}
18
19/// A Builder object for creating a RouterStatus and adding it to a
20/// consensus.
21#[cfg_attr(docsrs, doc(cfg(feature = "build_docs")))]
22#[derive(Debug, Clone)]
23pub struct RouterStatusBuilder {
24    /// See [`RouterStatus::nickname`].
25    nickname: Option<String>,
26    /// See [`RouterStatus::identity`].
27    identity: Option<RsaIdentity>,
28    /// See [`RouterStatus::addrs`].
29    addrs: Vec<SocketAddr>,
30    /// See [`RouterStatus::doc_digest`].
31    doc_digest: Option<DocDigest>,
32    /// See [`RouterStatus::flags`].
33    flags: RelayFlags,
34    /// See [`RouterStatus::version`].
35    version: Option<String>,
36    /// See [`RouterStatus::protos`].
37    protos: Option<Protocols>,
38    /// See [`RouterStatus::weight`].
39    weight: Option<RelayWeight>,
40}
41
42impl RouterStatusBuilder {
43    /// Construct a new RouterStatusBuilder.
44    pub(crate) fn new() -> Self {
45        RouterStatusBuilder {
46            nickname: None,
47            identity: None,
48            addrs: Vec::new(),
49            doc_digest: None,
50            flags: RelayFlags::empty(),
51            version: None,
52            protos: None,
53            weight: None,
54        }
55    }
56
57    /// Set the nickname for this routerstatus.
58    ///
59    /// This value defaults to "Unnamed".
60    pub fn nickname(&mut self, nickname: String) -> &mut Self {
61        self.nickname = Some(nickname);
62        self
63    }
64
65    /// Set the RSA identity for this routerstatus.
66    ///
67    /// (The Ed25519 identity is in the microdescriptor).
68    ///
69    /// This value is required.
70    pub fn identity(&mut self, identity: RsaIdentity) -> &mut Self {
71        self.identity = Some(identity);
72        self
73    }
74    /// Add an OrPort at `addr` to this routerstatus.
75    ///
76    /// At least one value here is required.
77    pub fn add_or_port(&mut self, addr: SocketAddr) -> &mut Self {
78        self.addrs.push(addr);
79        self
80    }
81    /// Set the document digest for this routerstatus.
82    ///
83    /// This value is required.
84    pub fn doc_digest(&mut self, doc_digest: DocDigest) -> &mut Self {
85        self.doc_digest = Some(doc_digest);
86        self
87    }
88    /// Replace the current flags in this routerstatus with `flags`.
89    pub fn set_flags(&mut self, flags: RelayFlags) -> &mut Self {
90        self.flags = flags;
91        self
92    }
93    /// Make all the flags in `flags` become set on this routerstatus,
94    /// in addition to the flags already set.
95    pub fn add_flags(&mut self, flags: RelayFlags) -> &mut Self {
96        self.flags |= flags;
97        self
98    }
99    /// Make all the flags in `flags` become cleared on this routerstatus.
100    #[cfg(feature = "testing")]
101    pub fn clear_flags(&mut self, flags: RelayFlags) -> &mut Self {
102        self.flags &= !flags;
103        self
104    }
105    /// Set the version of the relay described in this routerstatus.
106    ///
107    /// This value is optional.
108    pub fn version(&mut self, version: String) -> &mut Self {
109        self.version = Some(version);
110        self
111    }
112    /// Set the list of subprotocols supported by the relay described
113    /// by this routerstatus.
114    ///
115    /// This value is required.
116    pub fn protos(&mut self, protos: Protocols) -> &mut Self {
117        self.protos = Some(protos);
118        self
119    }
120    /// Set the weight of this routerstatus for random selection.
121    ///
122    /// This value is optional; it defaults to 0.
123    pub fn weight(&mut self, weight: RelayWeight) -> &mut Self {
124        self.weight = Some(weight);
125        self
126    }
127    /// Try to build a GenericRouterStatus from this builder.
128    // TODO this function is identical to `build`; decide which one to keep
129    pub(super) fn finish(&self) -> Result<RouterStatus> {
130        let nickname = self.nickname.as_deref().unwrap_or("Unnamed").parse()?;
131        let identity = self
132            .identity
133            .ok_or(Error::CannotBuild("Missing RSA identity"))?;
134        if self.addrs.is_empty() {
135            return Err(Error::CannotBuild("No addresses"));
136        }
137        let doc_digest = *self
138            .doc_digest
139            .as_ref()
140            .ok_or(Error::CannotBuild("Missing document digest"))?;
141        let protos = self
142            .protos
143            .as_ref()
144            .ok_or(Error::CannotBuild("Missing protocols"))?
145            .clone();
146        let weight = self.weight.unwrap_or(RelayWeight::Unmeasured(0));
147        let version = self.version.as_deref().map(str::parse).transpose()?;
148
149        Ok(RouterStatus {
150            nickname,
151            identity,
152            addrs: self.addrs.clone(),
153            doc_digest,
154            version,
155            protos: doc::PROTOVERS_CACHE.intern(protos),
156            flags: self.flags,
157            weight,
158        })
159    }
160
161    /// Try to finish this builder and add its RouterStatus to a
162    /// provided ConsensusBuilder.x
163    pub fn build_into(
164        &self,
165        builder: &mut ConsensusBuilder,
166    ) -> Result<()> {
167        builder.add_rs(self.build()?);
168        Ok(())
169    }
170
171    /// Return a router status built by this object.
172    // TODO this function is identical to `build`; decide which one to keep
173    pub fn build(&self) -> Result<RouterStatus> {
174        self.finish()
175    }
176}