tor_netdoc/doc/netstatus/rs/
build.rs

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