use std::sync::Arc;
#[derive(Clone, Debug, Default)]
pub struct TtlConfig {
pub enabled: bool,
pub default_ttl_seconds: Option<u32>,
}
#[derive(Clone)]
pub struct TTLProvider {
enabled: bool,
default_ttl: Option<u32>,
time_provider: Arc<dyn crate::time::TimeProvider>,
}
impl TTLProvider {
pub fn new(config: &TtlConfig, time_provider: Arc<dyn crate::time::TimeProvider>) -> Self {
Self {
enabled: config.enabled,
default_ttl: config.default_ttl_seconds,
time_provider,
}
}
pub fn disabled() -> Self {
Self {
enabled: false,
default_ttl: None,
time_provider: Arc::new(crate::time::SystemTimeProvider),
}
}
pub(crate) fn get_expiration_timestamp(&self, ttl_seconds: Option<u32>) -> Option<u32> {
if !self.enabled {
return None;
}
let ttl = ttl_seconds.or(self.default_ttl);
ttl.map(|t| self.time_provider.now_seconds() + t)
}
pub(crate) fn expired(&self, expired_at: &Option<u32>) -> bool {
if !self.enabled {
return false;
}
match expired_at {
Some(ts) => self.time_provider.now_seconds() >= *ts,
None => false,
}
}
pub(crate) fn now_seconds(&self) -> u32 {
self.time_provider.now_seconds()
}
pub(crate) fn time_provider(&self) -> &dyn crate::time::TimeProvider {
self.time_provider.as_ref()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::time::ManualTimeProvider;
#[test]
fn test_ttl_provider() {
let time_provider = Arc::new(ManualTimeProvider::new(1000));
let ttl_provider = TTLProvider::new(
&TtlConfig {
enabled: true,
default_ttl_seconds: Some(500),
},
time_provider.clone(),
);
let expiration = ttl_provider.get_expiration_timestamp(None);
assert_eq!(expiration, Some(1500));
let expiration = ttl_provider.get_expiration_timestamp(Some(300));
assert_eq!(expiration, Some(1300));
assert!(!ttl_provider.expired(&Some(1500)));
time_provider.set_time(1600);
assert!(ttl_provider.expired(&Some(1500)));
}
}