use crate::AppError;
use crate::shutdown::SHUTDOWN_EVENTS;
use crate::traits::GuardRecovery;
use allo_isolate::ffi::DartPostCObjectFnType;
use allo_isolate::{
IntoDart, Isolate, ZeroCopyBuffer, store_dart_post_cobject,
};
use os_thread_local::ThreadLocal;
use std::sync::Mutex;
use std::sync::OnceLock;
use std::thread::spawn;
static DART_ISOLATE: Mutex<Option<Isolate>> = Mutex::new(None);
#[unsafe(no_mangle)]
extern "C" fn rinf_prepare_isolate_extern(
store_post_object: DartPostCObjectFnType,
port: i64,
) {
unsafe { store_dart_post_cobject(store_post_object) }
let dart_isolate = Isolate::new(port);
let mut guard = DART_ISOLATE.lock().recover();
guard.replace(dart_isolate);
}
type ShutdownDropperLock = OnceLock<ThreadLocal<ShutdownDropper>>;
static SHUTDOWN_DROPPER: ShutdownDropperLock = OnceLock::new();
pub struct ShutdownDropper;
impl Drop for ShutdownDropper {
fn drop(&mut self) {
SHUTDOWN_EVENTS.dart_stopped.set();
SHUTDOWN_EVENTS.rust_stopped.wait();
}
}
pub fn start_rust_logic_real<F, T>(main_fn: F) -> Result<(), AppError>
where
F: Fn() -> T + Send + 'static,
{
#[cfg(debug_assertions)]
{
use crate::debug_print;
use std::panic::set_hook;
#[cfg(not(feature = "backtrace"))]
{
set_hook(Box::new(|panic_info| {
debug_print!("A panic occurred in Rust.\n{}", panic_info);
}));
}
#[cfg(feature = "backtrace")]
{
use backtrace::Backtrace;
set_hook(Box::new(|panic_info| {
let backtrace = Backtrace::new();
debug_print!(
"A panic occurred in Rust.\n{}\n{:?}",
panic_info,
backtrace
);
}));
}
}
let thread_local = ThreadLocal::new(|| ShutdownDropper);
let _ = SHUTDOWN_DROPPER.set(thread_local);
spawn(move || {
SHUTDOWN_EVENTS.dart_stopped.set();
SHUTDOWN_EVENTS.dart_stopped.clear();
SHUTDOWN_EVENTS.rust_stopped.clear();
main_fn();
SHUTDOWN_EVENTS.rust_stopped.set();
});
Ok(())
}
#[unsafe(no_mangle)]
extern "C" fn rinf_stop_rust_logic_extern() {
SHUTDOWN_EVENTS.dart_stopped.set();
SHUTDOWN_EVENTS.rust_stopped.wait();
}
pub fn send_rust_signal_real(
endpoint: &str,
message_bytes: Vec<u8>,
binary: Vec<u8>,
) -> Result<(), AppError> {
let guard = DART_ISOLATE.lock().recover();
let dart_isolate = guard.as_ref().ok_or(AppError::NoDartIsolate)?;
let message_filled = !message_bytes.is_empty();
let binary_filled = !binary.is_empty();
dart_isolate.post(
vec![
endpoint.into_dart(),
if message_filled {
ZeroCopyBuffer(message_bytes).into_dart()
} else {
().into_dart()
},
if binary_filled {
ZeroCopyBuffer(binary).into_dart()
} else {
().into_dart()
},
]
.into_dart(),
);
Ok(())
}