use std::sync::Arc; use std::time::Duration; use tokio::sync::RwLock; use tokio::task::JoinHandle; use tracing::debug; use crate::action_callback::ActionCallback; #[derive(Debug, Default)] pub struct State { handle: Option>, } #[derive(Debug, Clone)] pub struct Timeout { state: Arc>, } impl mlua::UserData for Timeout { fn add_methods>(methods: &mut M) { methods.add_function("new", |_lua, ()| { let device = Self { state: Default::default(), }; Ok(device) }); methods.add_async_method( "start", |_lua, this, (timeout, callback): (u64, ActionCallback)| async move { if let Some(handle) = this.state.write().await.handle.take() { handle.abort(); } debug!("Running timeout callback after {timeout}s"); let timeout = Duration::from_secs(timeout); this.state.write().await.handle = Some(tokio::spawn({ async move { tokio::time::sleep(timeout).await; callback.call(false).await; } })); Ok(()) }, ); methods.add_async_method("cancel", |_lua, this, ()| async move { debug!("Canceling timeout callback"); if let Some(handle) = this.state.write().await.handle.take() { handle.abort(); } Ok(()) }); methods.add_async_method("is_waiting", |_lua, this, ()| async move { debug!("Canceling timeout callback"); if let Some(handle) = this.state.read().await.handle.as_ref() { debug!("Join handle: {}", handle.is_finished()); return Ok(!handle.is_finished()); } debug!("Join handle: None"); Ok(false) }); } }