use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct StalenessRule {
pub warn_after_days: u32,
pub block_after_days: u32,
}
impl Default for StalenessRule {
fn default() -> Self {
Self { warn_after_days: 7, block_after_days: 30 }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Staleness {
Fresh,
Warn,
Block,
}
impl Staleness {
pub fn as_str(self) -> &'static str {
match self {
Staleness::Fresh => "fresh",
Staleness::Warn => "warn",
Staleness::Block => "block",
}
}
}
impl StalenessRule {
pub fn validate(&self) -> anyhow::Result<()> {
anyhow::ensure!(
self.block_after_days >= self.warn_after_days,
"intel staleness: block_after_days ({}) is before warn_after_days ({})",
self.block_after_days,
self.warn_after_days
);
Ok(())
}
pub fn age_days(snapshot: DateTime<Utc>, now: DateTime<Utc>) -> i64 {
(now - snapshot).num_days().max(0)
}
pub fn judge(&self, snapshot: DateTime<Utc>, now: DateTime<Utc>) -> Staleness {
let age = Self::age_days(snapshot, now);
if age >= i64::from(self.block_after_days) {
Staleness::Block
} else if age >= i64::from(self.warn_after_days) {
Staleness::Warn
} else {
Staleness::Fresh
}
}
}