use core::cell::RefCell;
use core::future::Future;
struct WoabRuntime {
actix_system_runner: actix::SystemRunner,
runtime_cranker_source_id: glib::SourceId,
}
thread_local! {
static WOAB_RUNTIME: RefCell<Option<WoabRuntime>> = const { RefCell::new(None) };
}
pub fn block_on<F: Future>(fut: F) -> <F as Future>::Output {
try_block_on(fut).map_err(|_| "Already inside Actix context").unwrap()
}
pub fn try_block_on<F: Future>(fut: F) -> Result<<F as Future>::Output, F> {
WOAB_RUNTIME.with(|woab_runtime| {
if let Ok(woab_runtime) = woab_runtime.try_borrow_mut() {
let woab_runtime = woab_runtime
.as_ref()
.expect("`try_block_on` called without `run_actix_inside_gtk_event_loop`");
let result = woab_runtime.actix_system_runner.block_on(fut);
Ok(result)
} else {
Err(fut)
}
})
}
pub fn run_actix_inside_gtk_event_loop() {
WOAB_RUNTIME.with(|woab_runtime| {
let mut woab_runtime = woab_runtime.borrow_mut();
if woab_runtime.is_some() {
panic!("WoAB is already running Actix inside the GTK event loop");
}
let runtime_cranker_source_id = glib::idle_add(|| {
try_block_on(async {
actix::clock::sleep(core::time::Duration::new(0, 10_000_000)).await;
})
.map_err(|_| "`idle_add` function called inside Actix context")
.unwrap();
glib::ControlFlow::Continue
});
*woab_runtime = Some(WoabRuntime {
actix_system_runner: actix::System::new(),
runtime_cranker_source_id,
});
});
}
#[derive(thiserror::Error, Debug)]
pub enum RuntimeStopError {
#[error("Cannot stop the WoAB runtime because it was not started")]
RuntimeNotStarted,
#[error("Cannot stop the WoAB runtime because it is currently in use. Try stopping it with `actix::System::current().stop();` instead")]
RuntimeInUse,
}
pub fn close_actix_runtime() -> Result<Result<(), std::io::Error>, RuntimeStopError> {
let woab_runtime = WOAB_RUNTIME.with(|woab_runtime| {
woab_runtime
.try_borrow_mut()
.map_err(|_| RuntimeStopError::RuntimeInUse)?
.take()
.ok_or(RuntimeStopError::RuntimeNotStarted)
})?;
woab_runtime.actix_system_runner.block_on(async {
actix::System::current().stop();
});
woab_runtime.runtime_cranker_source_id.remove();
Ok(woab_runtime.actix_system_runner.run())
}
pub fn is_runtime_running() -> bool {
WOAB_RUNTIME.with(|woab_runtime| {
if let Ok(woab_runtime) = woab_runtime.try_borrow() {
woab_runtime.is_some()
} else {
true
}
})
}