use std::path::PathBuf;
use std::time::Duration;
pub const DEFAULT_FULL_SWEEP_SECONDS: u64 = 24 * 60 * 60;
pub const DEFAULT_SEGMENT_SECONDS: u64 = 60;
pub const DEFAULT_TIME_BUCKETS: u32 = 24;
pub const DEFAULT_SEGMENTS: u32 = 1024;
pub const DEFAULT_TIME_WINDOW_SECONDS: u64 = 60 * 60;
pub const MAX_SEGMENTS: u32 = 1 << 20;
pub const MAX_TIME_BUCKETS: u32 = 1 << 12;
pub const DEFAULT_SNAPSHOT_INTERVAL_SECONDS: u64 = 5 * 60;
pub const DEFAULT_AAE_STATE_DIR: &str = "/var/lib/dynomite/aae";
pub const SNAPSHOT_FILE_NAME: &str = "tree.snapshot";
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ConfAae {
pub enabled: bool,
pub full_sweep_interval_seconds: u64,
pub segment_interval_seconds: u64,
pub n_time_buckets: u32,
pub n_segments: u32,
pub time_window_seconds: u64,
pub snapshot_interval_seconds: u64,
pub aae_state_dir: PathBuf,
pub per_token_exchange: bool,
}
impl Default for ConfAae {
fn default() -> Self {
Self {
enabled: false,
full_sweep_interval_seconds: DEFAULT_FULL_SWEEP_SECONDS,
segment_interval_seconds: DEFAULT_SEGMENT_SECONDS,
n_time_buckets: DEFAULT_TIME_BUCKETS,
n_segments: DEFAULT_SEGMENTS,
time_window_seconds: DEFAULT_TIME_WINDOW_SECONDS,
snapshot_interval_seconds: DEFAULT_SNAPSHOT_INTERVAL_SECONDS,
aae_state_dir: PathBuf::from(DEFAULT_AAE_STATE_DIR),
per_token_exchange: false,
}
}
}
impl ConfAae {
pub fn validate(&self) -> Result<(), String> {
if self.n_time_buckets == 0 || self.n_time_buckets > MAX_TIME_BUCKETS {
return Err(format!(
"n_time_buckets {} out of range (1..={MAX_TIME_BUCKETS})",
self.n_time_buckets
));
}
if self.n_segments == 0 || self.n_segments > MAX_SEGMENTS {
return Err(format!(
"n_segments {} out of range (1..={MAX_SEGMENTS})",
self.n_segments
));
}
if self.time_window_seconds == 0 {
return Err("time_window_seconds must be > 0".to_string());
}
if self.segment_interval_seconds == 0 {
return Err("segment_interval_seconds must be > 0".to_string());
}
if self.full_sweep_interval_seconds == 0 {
return Err("full_sweep_interval_seconds must be > 0".to_string());
}
if self.segment_interval_seconds > self.full_sweep_interval_seconds {
return Err(format!(
"segment_interval_seconds {} must be <= full_sweep_interval_seconds {}",
self.segment_interval_seconds, self.full_sweep_interval_seconds
));
}
if self.snapshot_interval_seconds == 0 {
return Err("snapshot_interval_seconds must be > 0".to_string());
}
Ok(())
}
#[must_use]
pub fn segment_interval(&self) -> Duration {
Duration::from_secs(self.segment_interval_seconds)
}
#[must_use]
pub fn full_sweep_interval(&self) -> Duration {
Duration::from_secs(self.full_sweep_interval_seconds)
}
#[must_use]
pub fn snapshot_interval(&self) -> Duration {
Duration::from_secs(self.snapshot_interval_seconds)
}
#[must_use]
pub fn snapshot_path(&self) -> PathBuf {
self.aae_state_dir.join(SNAPSHOT_FILE_NAME)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_config_validates() {
assert!(ConfAae::default().validate().is_ok());
}
#[test]
fn validate_rejects_zero_segments() {
let cfg = ConfAae {
n_segments: 0,
..ConfAae::default()
};
assert!(cfg.validate().is_err());
}
#[test]
fn validate_rejects_segment_interval_above_sweep() {
let cfg = ConfAae {
segment_interval_seconds: 10,
full_sweep_interval_seconds: 5,
..ConfAae::default()
};
assert!(cfg.validate().is_err());
}
}