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

            
13
use super::*;
14

            
15
ns_use_this_variety! {
16
    use [crate::doc::netstatus::rs]::?::{DocDigest, RouterStatus, RouterStatusIntroItem};
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)]
23
pub struct RouterStatusBuilder {
24
    /// See [`RouterStatus::nickname`].
25
    nickname: Option<String>,
26
    /// See [`RouterStatusIntroItem::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

            
42
impl RouterStatusBuilder {
43
    /// Construct a new RouterStatusBuilder.
44
426532
    pub(crate) fn new() -> Self {
45
426532
        RouterStatusBuilder {
46
426532
            nickname: None,
47
426532
            identity: None,
48
426532
            addrs: Vec::new(),
49
426532
            doc_digest: None,
50
426532
            flags: RelayFlags::empty(),
51
426532
            version: None,
52
426532
            protos: None,
53
426532
            weight: None,
54
426532
        }
55
426532
    }
56

            
57
    /// Set the nickname for this routerstatus.
58
    ///
59
    /// This value defaults to "Unnamed".
60
4
    pub fn nickname(&mut self, nickname: String) -> &mut Self {
61
4
        self.nickname = Some(nickname);
62
4
        self
63
4
    }
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
428452
    pub fn identity(&mut self, identity: RsaIdentity) -> &mut Self {
71
428452
        self.identity = Some(identity);
72
428452
        self
73
428452
    }
74
    /// Add an OrPort at `addr` to this routerstatus.
75
    ///
76
    /// At least one value here is required.
77
426872
    pub fn add_or_port(&mut self, addr: SocketAddr) -> &mut Self {
78
426872
        self.addrs.push(addr);
79
426872
        self
80
426872
    }
81
    /// Set the document digest for this routerstatus.
82
    ///
83
    /// This value is required.
84
409780
    pub fn doc_digest(&mut self, doc_digest: DocDigest) -> &mut Self {
85
409780
        self.doc_digest = Some(doc_digest);
86
409780
        self
87
409780
    }
88
    /// Replace the current flags in this routerstatus with `flags`.
89
395093
    pub fn set_flags(&mut self, flags: impl Into<RelayFlags>) -> &mut Self {
90
395093
        self.flags = flags.into();
91
395093
        self
92
395093
    }
93
    /// Make all the flags in `flags` become set on this routerstatus,
94
    /// in addition to the flags already set.
95
96
    pub fn add_flags(&mut self, flags: impl Into<RelayFlags>) -> &mut Self {
96
96
        self.flags |= flags.into();
97
96
        self
98
96
    }
99
    /// Make all the flags in `flags` become cleared on this routerstatus.
100
    #[cfg(feature = "testing")]
101
476
    pub fn clear_flags(&mut self, flags: impl Into<RelayFlags>) -> &mut Self {
102
476
        self.flags &= !flags.into();
103
476
        self
104
476
    }
105
    /// Set the version of the relay described in this routerstatus.
106
    ///
107
    /// This value is optional.
108
4
    pub fn version(&mut self, version: String) -> &mut Self {
109
4
        self.version = Some(version);
110
4
        self
111
4
    }
112
    /// Set the list of subprotocols supported by the relay described
113
    /// by this routerstatus.
114
    ///
115
    /// This value is required.
116
427972
    pub fn protos(&mut self, protos: Protocols) -> &mut Self {
117
427972
        self.protos = Some(protos);
118
427972
        self
119
427972
    }
120
    /// Set the weight of this routerstatus for random selection.
121
    ///
122
    /// This value is optional; it defaults to 0.
123
436704
    pub fn weight(&mut self, weight: RelayWeight) -> &mut Self {
124
436704
        self.weight = Some(weight);
125
436704
        self
126
436704
    }
127
    /// Try to build a GenericRouterStatus from this builder.
128
    // TODO this function is identical to `build`; decide which one to keep
129
409780
    pub(super) fn finish(&self) -> Result<RouterStatus> {
130
409780
        let nickname = self.nickname.as_deref().unwrap_or("Unnamed").parse()?;
131
409780
        let identity = self
132
409780
            .identity
133
409780
            .ok_or(Error::CannotBuild("Missing RSA identity"))?;
134
409780
        if self.addrs.is_empty() {
135
            return Err(Error::CannotBuild("No addresses"));
136
409780
        }
137
409780
        let doc_digest = *self
138
409780
            .doc_digest
139
409780
            .as_ref()
140
409780
            .ok_or(Error::CannotBuild("Missing document digest"))?;
141
409780
        let protos = self
142
409780
            .protos
143
409780
            .as_ref()
144
409780
            .ok_or(Error::CannotBuild("Missing protocols"))?
145
409780
            .clone();
146
409780
        let weight = self.weight.unwrap_or(RelayWeight::Unmeasured(0));
147
409780
        let version = self.version.as_deref().map(str::parse).transpose()?;
148

            
149
409780
        let mut ip = None;
150
409780
        let a = self
151
409780
            .addrs
152
409780
            .iter()
153
426856
            .filter_map(|a| match a {
154
418317
                SocketAddr::V4(a) if ip.is_none() => {
155
418317
                    ip = Some(a);
156
418317
                    None
157
                }
158
347
                other => Some(*other),
159
418664
            })
160
409780
            .collect::<Vec<_>>();
161
409780
        let ip = ip.ok_or_else(|| Error::CannotBuild("No IPv4 address"))?;
162

            
163
        ns_choose! { (
164
            let r_doc_digest = doc_digest;
165
            let m_doc_digest = NotPresent;
166
        ) (
167
409780
            let r_doc_digest = NotPresent;
168
409780
            let m_doc_digest = doc_digest;
169
        ) (
170
            compile_error!("no builder for votes");
171
        ) };
172

            
173
409780
        Ok(RouterStatus {
174
409780
            r: RouterStatusIntroItem {
175
409780
                nickname,
176
409780
                identity: Base64Fingerprint(identity),
177
409780
                doc_digest: r_doc_digest,
178
409780
                publication: IgnoredPublicationTimeSp,
179
409780
                ip: *ip.ip(),
180
409780
                or_port: ip.port(),
181
409780
            },
182
409780
            m: m_doc_digest,
183
409780
            a,
184
409780
            version,
185
409780
            protos,
186
409780
            flags: DocRelayFlags {
187
409780
                known: self.flags,
188
409780
                unknown: Unknown::new_discard(),
189
409780
            },
190
409780
            weight,
191
409780
        })
192
409780
    }
193

            
194
    /// Try to finish this builder and add its RouterStatus to a
195
    /// provided ConsensusBuilder.x
196
409492
    pub fn build_into(&self, builder: &mut ConsensusBuilder) -> Result<()> {
197
409492
        builder.add_rs(self.build()?);
198
409492
        Ok(())
199
409492
    }
200

            
201
    /// Return a router status built by this object.
202
    // TODO this function is identical to `build`; decide which one to keep
203
409780
    pub fn build(&self) -> Result<RouterStatus> {
204
409780
        self.finish()
205
409780
    }
206
}