mod running_cheat_clock;
mod stable_cheat_clock;
mod true_clock;
use chrono::{DateTime, TimeDelta, Utc};
use std::{fmt, future::Future, time::Duration};
use tokio::{select, sync::Notify, time::sleep};
use crate::core::CoreResult;
pub use {
running_cheat_clock::{RunningCheatClock, RunningCheatClockFactory, RunningCheatClockRemote},
stable_cheat_clock::{StableCheatClock, StableCheatClockFactory, StableCheatClockRemote},
true_clock::{TrueClock, TrueClockFactory},
};
pub trait ClockBase: Send + Sync + fmt::Debug + 'static {
const NAME: &'static str;
fn now(&self) -> DateTime<Utc>;
}
pub trait Clock: Send + Sync + fmt::Debug + ClockBase + Clone + 'static {
type Remote: ClockRemote;
fn sleep(&self, delay: TimeDelta) -> impl Future<Output = ()> + Send;
fn sleep_until(&self, deadline: DateTime<Utc>) -> impl Future<Output = ()> + Send;
fn synchronize(&self);
}
#[cfg(test)]
pub const REMOTE_REFRESH_RATE: Duration = Duration::from_millis(10);
#[cfg(not(test))]
pub const REMOTE_REFRESH_RATE: Duration = Duration::from_secs(1);
pub const SAFETY_REFRESH_DELAY: Duration = Duration::from_secs(120);
pub trait ClockRemote: ClockBase {
#[cfg(test)]
fn not_blocking(&self);
fn remote_now(&self) -> DateTime<Utc>;
fn advance_toward(&self, date: DateTime<Utc>);
fn notify(&self) -> &Notify;
fn is_sync(&self) -> bool;
fn wait_for_the_clock(&self) -> impl std::future::Future<Output = ()> + Send {
async {
loop {
if self.is_sync() {
break;
}
select! {
_ = sleep(REMOTE_REFRESH_RATE) => {},
_ = self.notify().notified() => {}
}
}
}
}
}
type ClockPackage<C> = (Option<<C as Clock>::Remote>, C);
pub trait ClockFactory {
type _Clock: Clock;
fn build(self) -> CoreResult<ClockPackage<Self::_Clock>>;
}
#[derive(Debug)]
pub struct NoRemote {
_private: (),
}
impl ClockBase for NoRemote {
fn now(&self) -> DateTime<Utc> {
unreachable!()
}
const NAME: &'static str = "NoRemote";
}
impl ClockRemote for NoRemote {
#[cfg(test)]
fn not_blocking(&self) {
unreachable!()
}
fn remote_now(&self) -> DateTime<Utc> {
unreachable!()
}
fn advance_toward(&self, _: DateTime<Utc>) {
unreachable!()
}
fn notify(&self) -> &Notify {
unreachable!()
}
fn is_sync(&self) -> bool {
unreachable!()
}
}