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}