use chrono::{DateTime, TimeDelta, Utc};
use tokio::time::Instant;
use crate::wall_clock_timer::Clock;
#[derive(Clone, Debug)]
pub struct TokioSyncedClock {
inner: std::sync::Arc<std::sync::RwLock<TokioSyncedClockInner>>,
}
#[derive(Debug)]
struct TokioSyncedClockInner {
wall_anchor: DateTime<Utc>,
mono_anchor: Instant,
}
impl Default for TokioSyncedClock {
fn default() -> Self {
Self::new()
}
}
impl TokioSyncedClock {
pub fn new() -> Self {
Self::with_wall_anchor(Utc::now())
}
pub fn with_wall_anchor(wall_anchor: DateTime<Utc>) -> Self {
Self {
inner: std::sync::Arc::new(std::sync::RwLock::new(TokioSyncedClockInner {
wall_anchor,
mono_anchor: Instant::now(),
})),
}
}
pub fn inject_wall_jump(&self, offset: TimeDelta) {
let mut inner = self.inner.write().expect("clock poisoned");
inner.wall_anchor += offset;
}
}
impl Clock for TokioSyncedClock {
fn wall_now(&self) -> DateTime<Utc> {
let inner = self.inner.read().expect("clock poisoned");
let elapsed = Instant::now().duration_since(inner.mono_anchor);
inner.wall_anchor
+ TimeDelta::from_std(elapsed).expect("tokio elapsed fits in TimeDelta (~292 years)")
}
}