use super::{GenericRouterStatus, MdConsensusRouterStatus};
use crate::doc::microdesc::MdDigest;
use crate::doc::netstatus::{ConsensusBuilder, RelayFlags, RelayWeight};
use crate::{Error, 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;
#[derive(Debug, Clone)]
pub struct RouterStatusBuilder<D> {
nickname: Option<String>,
identity: Option<RsaIdentity>,
addrs: Vec<SocketAddr>,
doc_digest: Option<D>,
flags: RelayFlags,
version: Option<String>,
protos: Option<Protocols>,
weight: Option<RelayWeight>,
}
impl<D: Clone> RouterStatusBuilder<D> {
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,
}
}
pub fn nickname(&mut self, nickname: String) -> &mut Self {
self.nickname = Some(nickname);
self
}
pub fn identity(&mut self, identity: RsaIdentity) -> &mut Self {
self.identity = Some(identity);
self
}
pub fn add_or_port(&mut self, addr: SocketAddr) -> &mut Self {
self.addrs.push(addr);
self
}
pub fn doc_digest(&mut self, doc_digest: D) -> &mut Self {
self.doc_digest = Some(doc_digest);
self
}
pub fn set_flags(&mut self, flags: RelayFlags) -> &mut Self {
self.flags = flags;
self
}
pub fn add_flags(&mut self, flags: RelayFlags) -> &mut Self {
self.flags |= flags;
self
}
pub fn version(&mut self, version: String) -> &mut Self {
self.version = Some(version);
self
}
pub fn protos(&mut self, protos: Protocols) -> &mut Self {
self.protos = Some(protos);
self
}
pub fn weight(&mut self, weight: RelayWeight) -> &mut Self {
self.weight = Some(weight);
self
}
fn finish(&self) -> Result<GenericRouterStatus<D>> {
let nickname = self.nickname.clone().unwrap_or_else(|| "Unnamed".into());
let identity = self
.identity
.ok_or(Error::CannotBuild("Missing RSA identity"))?;
if self.addrs.is_empty() {
return Err(Error::CannotBuild("No addresses"));
}
let or_port = self.addrs[0].port();
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));
Ok(GenericRouterStatus {
nickname,
identity,
addrs: self.addrs.clone(),
or_port,
doc_digest,
version: self.version.clone(),
protos,
flags: self.flags,
weight,
})
}
}
#[cfg(feature = "ns_consensus")]
impl RouterStatusBuilder<RdDigest> {
pub fn build_into(
&self,
builder: &mut ConsensusBuilder<NsConsensusRouterStatus>,
) -> Result<()> {
builder.add_rs(self.build()?);
Ok(())
}
pub fn build(&self) -> Result<NsConsensusRouterStatus> {
Ok(self.finish()?.into())
}
}
impl RouterStatusBuilder<MdDigest> {
pub fn build_into(
&self,
builder: &mut ConsensusBuilder<MdConsensusRouterStatus>,
) -> Result<()> {
builder.add_rs(self.build()?);
Ok(())
}
pub fn build(&self) -> Result<MdConsensusRouterStatus> {
Ok(self.finish()?.into())
}
}