use crate::actor::message::{Handler, Message};
use crate::actor::{Actor, LocalActorRef};
use log::trace;
use std::time::{Duration, Instant};
use uuid::Uuid;
pub trait TimerTick: Message {}
pub struct Timer {
stop: tokio::sync::oneshot::Sender<bool>,
}
impl Timer {
pub fn start<A: Actor, T: TimerTick>(actor: LocalActorRef<A>, tick: Duration, msg: T) -> Timer
where
A: 'static + Handler<T> + Sync + Send,
T: 'static + Clone + Sync + Send,
T::Result: 'static + Sync + Send,
{
let (stop, stop_rx) = tokio::sync::oneshot::channel();
tokio::spawn(timer_loop(tick, msg, actor, stop_rx));
Timer { stop }
}
pub fn stop(self) -> bool {
if self.stop.send(true).is_ok() {
true
} else {
false
}
}
}
pub async fn timer_loop<A: Actor, T: TimerTick>(
tick: Duration,
msg: T,
mut actor: LocalActorRef<A>,
mut stop_rx: tokio::sync::oneshot::Receiver<bool>,
) where
A: 'static + Handler<T> + Sync + Send,
T: 'static + Clone + Sync + Send,
T::Result: 'static + Sync + Send,
{
let mut interval = tokio::time::interval_at(tokio::time::Instant::now(), tick);
let timer_id = Uuid::new_v4();
interval.tick().await;
trace!(target: "Timer", "{} - timer starting", &timer_id);
loop {
if stop_rx.try_recv().is_ok() {
break;
}
trace!(target: "Timer", "{} - timer tick", &timer_id);
let now = Instant::now();
if actor.send(msg.clone()).await.is_err() {
break;
}
trace!(target: "Timer", "{} - tick res received in {}ms", &timer_id, now.elapsed().as_millis());
interval.tick().await;
}
trace!(target: "Timer", "{} - timer finished", timer_id);
}