napi-rs/examples/napi/src/threadsafe_function.rs

167 lines
4.7 KiB
Rust

use std::{thread, time::Duration};
use napi::{
bindgen_prelude::*,
threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode},
JsBoolean, JsString,
};
#[napi]
pub fn call_threadsafe_function(callback: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> =
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value + 1]))?;
for n in 0..100 {
let tsfn = tsfn.clone();
thread::spawn(move || {
tsfn.call(Ok(n), ThreadsafeFunctionCallMode::NonBlocking);
});
}
Ok(())
}
#[napi]
pub fn call_long_threadsafe_function(callback: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> =
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value + 1]))?;
thread::spawn(move || {
for n in 0..10 {
thread::sleep(Duration::from_millis(100));
tsfn.call(Ok(n), ThreadsafeFunctionCallMode::NonBlocking);
}
});
Ok(())
}
#[napi]
pub fn threadsafe_function_throw_error(cb: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<bool, ErrorStrategy::CalleeHandled> =
cb.create_threadsafe_function(0, |ctx| ctx.env.get_boolean(ctx.value).map(|v| vec![v]))?;
thread::spawn(move || {
tsfn.call(
Err(Error::new(
Status::GenericFailure,
"ThrowFromNative".to_owned(),
)),
ThreadsafeFunctionCallMode::Blocking,
);
});
Ok(())
}
#[napi]
pub fn threadsafe_function_fatal_mode(cb: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<bool, ErrorStrategy::Fatal> =
cb.create_threadsafe_function(0, |ctx| ctx.env.get_boolean(ctx.value).map(|v| vec![v]))?;
thread::spawn(move || {
tsfn.call(true, ThreadsafeFunctionCallMode::Blocking);
});
Ok(())
}
#[napi]
pub fn threadsafe_function_fatal_mode_error(cb: JsFunction) -> Result<()> {
let tsfn: ThreadsafeFunction<bool, ErrorStrategy::Fatal> =
cb.create_threadsafe_function(0, |_ctx| {
Err::<Vec<JsBoolean>, Error>(Error::new(
Status::GenericFailure,
"Generic tsfn error".to_owned(),
))
})?;
thread::spawn(move || {
tsfn.call(true, ThreadsafeFunctionCallMode::Blocking);
});
Ok(())
}
#[napi]
fn threadsafe_function_closure_capture(func: JsFunction) -> napi::Result<()> {
let str = "test";
let tsfn: ThreadsafeFunction<()> = func
.create_threadsafe_function(0, move |_| {
println!("{}", str); // str is NULL at this point
Ok(Vec::<JsString>::new())
})
.unwrap();
tsfn.call(Ok(()), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[napi]
pub fn tsfn_call_with_callback(func: JsFunction) -> napi::Result<()> {
let tsfn: ThreadsafeFunction<()> =
func.create_threadsafe_function(0, move |_| Ok(Vec::<JsString>::new()))?;
tsfn.call_with_return_value(
Ok(()),
ThreadsafeFunctionCallMode::NonBlocking,
|value: String| {
println!("{}", value);
assert_eq!(value, "ReturnFromJavaScriptRawCallback".to_owned());
Ok(())
},
);
Ok(())
}
#[napi(ts_return_type = "Promise<void>")]
pub fn tsfn_async_call(env: Env, func: JsFunction) -> napi::Result<Object> {
let tsfn: ThreadsafeFunction<()> =
func.create_threadsafe_function(0, move |_| Ok(vec![0u32, 1u32, 2u32]))?;
env.spawn_future(async move {
let msg: String = tsfn.call_async(Ok(())).await?;
assert_eq!(msg, "ReturnFromJavaScriptRawCallback".to_owned());
Ok(())
})
}
#[napi]
pub fn accept_threadsafe_function(func: ThreadsafeFunction<u32>) {
thread::spawn(move || {
func.call(Ok(1), ThreadsafeFunctionCallMode::NonBlocking);
});
}
#[napi]
pub fn accept_threadsafe_function_fatal(func: ThreadsafeFunction<u32, ErrorStrategy::Fatal>) {
thread::spawn(move || {
func.call(1, ThreadsafeFunctionCallMode::NonBlocking);
});
}
#[napi]
pub fn accept_threadsafe_function_tuple_args(func: ThreadsafeFunction<(u32, bool, String)>) {
thread::spawn(move || {
func.call(
Ok((1, false, "NAPI-RS".into())),
ThreadsafeFunctionCallMode::NonBlocking,
);
});
}
#[napi]
pub async fn tsfn_return_promise(func: ThreadsafeFunction<u32>) -> Result<u32> {
let val = func.call_async::<Promise<u32>>(Ok(1)).await?.await?;
Ok(val + 2)
}
#[napi]
pub async fn tsfn_return_promise_timeout(func: ThreadsafeFunction<u32>) -> Result<u32> {
use tokio::time::{self, Duration};
let promise = func.call_async::<Promise<u32>>(Ok(1)).await?;
let sleep = time::sleep(Duration::from_nanos(1));
tokio::select! {
_ = sleep => {
Err(Error::new(Status::GenericFailure, "Timeout".to_owned()))
}
value = promise => {
Ok(value? + 2)
}
}
}
#[napi]
pub async fn tsfn_throw_from_js(tsfn: ThreadsafeFunction<u32>) -> napi::Result<u32> {
tsfn.call_async::<Promise<u32>>(Ok(42)).await?.await
}