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