use std::num::NonZeroUsize;
use std::time::Duration;
use libp2p::{Multiaddr, StreamProtocol};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttestationPolicy {
RequireVerified,
VerifyKnownRoots,
Unverified,
}
impl AttestationPolicy {
#[must_use]
pub const fn accepts_unknown_roots(self) -> bool {
matches!(self, Self::VerifyKnownRoots | Self::Unverified)
}
}
#[derive(Debug, Clone)]
pub struct Libp2pConfig {
pub listen_addresses: Vec<Multiaddr>,
pub protocol: StreamProtocol,
pub replication_factor: NonZeroUsize,
pub max_record_ttl: Duration,
pub republication_interval: Duration,
pub descriptor_cache_ttl: Duration,
pub page_high_water: usize,
pub attestation_policy: AttestationPolicy,
pub query_timeout: Duration,
}
impl Libp2pConfig {
pub const PROTOCOL: StreamProtocol = StreamProtocol::new("/agent-uri/kad/1.0.0");
const DEFAULT_REPLICATION_FACTOR: NonZeroUsize = NonZeroUsize::new(20).unwrap();
#[must_use]
pub const fn new() -> Self {
Self {
listen_addresses: Vec::new(),
protocol: Self::PROTOCOL,
replication_factor: Self::DEFAULT_REPLICATION_FACTOR,
max_record_ttl: Duration::from_hours(24),
republication_interval: Duration::from_mins(15),
descriptor_cache_ttl: Duration::from_mins(5),
page_high_water: 128,
attestation_policy: AttestationPolicy::VerifyKnownRoots,
query_timeout: Duration::from_mins(1),
}
}
#[must_use]
pub fn listening_on(mut self, address: Multiaddr) -> Self {
self.listen_addresses.push(address);
self
}
#[must_use]
pub const fn with_replication_factor(mut self, factor: NonZeroUsize) -> Self {
self.replication_factor = factor;
self
}
#[must_use]
pub const fn with_max_record_ttl(mut self, ttl: Duration) -> Self {
self.max_record_ttl = ttl;
self
}
#[must_use]
pub const fn with_republication_interval(mut self, interval: Duration) -> Self {
self.republication_interval = interval;
self
}
#[must_use]
pub const fn with_descriptor_cache_ttl(mut self, ttl: Duration) -> Self {
self.descriptor_cache_ttl = ttl;
self
}
#[must_use]
pub const fn with_page_high_water(mut self, pointers: usize) -> Self {
self.page_high_water = pointers;
self
}
#[must_use]
pub const fn with_attestation_policy(mut self, policy: AttestationPolicy) -> Self {
self.attestation_policy = policy;
self
}
#[must_use]
pub const fn with_query_timeout(mut self, timeout: Duration) -> Self {
self.query_timeout = timeout;
self
}
}
impl Default for Libp2pConfig {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_verify_what_they_can() {
let config = Libp2pConfig::default();
assert_eq!(
config.attestation_policy,
AttestationPolicy::VerifyKnownRoots
);
assert_eq!(config.replication_factor.get(), 20);
}
#[test]
fn the_protocol_is_not_the_ipfs_default() {
assert_eq!(Libp2pConfig::PROTOCOL.as_ref(), "/agent-uri/kad/1.0.0");
}
#[test]
fn only_the_strict_policy_refuses_unknown_trust_roots() {
assert!(!AttestationPolicy::RequireVerified.accepts_unknown_roots());
assert!(AttestationPolicy::VerifyKnownRoots.accepts_unknown_roots());
assert!(AttestationPolicy::Unverified.accepts_unknown_roots());
}
#[test]
fn builders_override_defaults() {
let config = Libp2pConfig::new()
.with_max_record_ttl(Duration::from_hours(1))
.with_page_high_water(8)
.with_attestation_policy(AttestationPolicy::RequireVerified)
.with_query_timeout(Duration::from_secs(5));
assert_eq!(config.max_record_ttl, Duration::from_hours(1));
assert_eq!(config.page_high_water, 8);
assert_eq!(
config.attestation_policy,
AttestationPolicy::RequireVerified
);
assert_eq!(config.query_timeout, Duration::from_secs(5));
}
}