/// A watchdog timer with a timeout that needs to be regularly pinged /// to prevent it from firing. /// /// **Note**: the behavior of the watchdog is undefined (but will not /// result in a crash or put the watchdog in an invalid state) if it /// is pet at the last possible moment, for example, like this: /// /// ```no_compile /// let (watchdog, pet) = /* ... */ /// tokio::select! { /// tokio::time::sleep(watchdog.timeout).then(move |()| pet.pet()) = _ => { eprintln!("foo"); }, /// watchdog.wait() = _ => { eprintln!("bar"); } /// ``` pub struct Watchdog { rx: tokio::sync::mpsc::Receiver<()>, /// Timeout of this watchdog. pub timeout: std::time::Duration, } #[derive(Clone)] pub(crate) struct Pet(tokio::sync::mpsc::Sender<()>); pub(crate) fn watchdog(timeout: std::time::Duration) -> (Watchdog, Pet) { let (tx, rx) = tokio::sync::mpsc::channel::<()>(1); let pet = Pet(tx); let watchdog = Watchdog { rx, timeout }; (watchdog, pet) } impl Watchdog { /// Wait until the watchdog fires from not being pet in a while. /// /// The watchdog doesn't start waiting for pets and scritches /// until you await the future returned from this method. pub async fn wait(mut self) { while let Ok(Some(())) = tokio::time::timeout(self.timeout, self.rx.recv()).await {} } } impl Pet { pub(crate) async fn pet_owned(self) -> Result<(), tokio::sync::mpsc::error::SendError<()>> { let tx = self.0.clone(); tx.send(()).await } }