use async_trait::async_trait;
use chrono::{DateTime, Utc};
use std::sync::Arc;
#[async_trait]
pub trait Clock: Send + Sync {
async fn now(&self) -> DateTime<Utc>;
async fn drift_ms(&self) -> Option<i64>;
}
pub type SharedClock = Arc<dyn Clock>;
#[derive(Default)]
pub struct SystemClock {
ntp_reference: Option<String>,
}
impl SystemClock {
#[must_use]
pub fn with_ntp(reference: impl Into<String>) -> Self {
Self {
ntp_reference: Some(reference.into()),
}
}
#[must_use]
pub fn reference(&self) -> Option<&str> {
self.ntp_reference.as_deref()
}
}
#[async_trait]
impl Clock for SystemClock {
async fn now(&self) -> DateTime<Utc> {
Utc::now()
}
async fn drift_ms(&self) -> Option<i64> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn system_clock_now_returns_recent_time() {
let c = SystemClock::default();
let now = c.now().await;
let recent = chrono::Utc::now().signed_duration_since(now);
assert!(recent.num_seconds().abs() < 5);
}
#[tokio::test]
async fn system_clock_drift_unknown_without_ntp() {
let c = SystemClock::default();
let d = c.drift_ms().await;
assert!(
d.is_none(),
"drift must be unknown when no NTP source configured"
);
}
}