use std::path::Path; use std::thread; use napi::sys::{ napi_threadsafe_function_call_mode::napi_tsfn_blocking, napi_threadsafe_function_release_mode::napi_tsfn_release, }; use napi::threadsafe_function::{ThreadsafeFunction, ToJs}; use napi::{ CallContext, Env, Error, JsBuffer, JsFunction, JsNumber, JsString, JsUndefined, Result, Status, }; use tokio; #[derive(Clone, Copy)] struct HandleNumber; impl ToJs for HandleNumber { type Output = u8; type JsValue = JsNumber; fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<(u64, Self::JsValue)> { let argv: u64 = 1; let value = env.create_uint32(output as u32)?; Ok((argv, value)) } } #[js_function(1)] pub fn test_threadsafe_function(ctx: CallContext) -> Result { let func = ctx.get::(0)?; let to_js = HandleNumber; let tsfn = ThreadsafeFunction::create(ctx.env, func, to_js, 0)?; thread::spawn(move || { let output: u8 = 42; // It's okay to call a threadsafe function multiple times. tsfn.call(Ok(output), napi_tsfn_blocking).unwrap(); tsfn.call(Ok(output), napi_tsfn_blocking).unwrap(); tsfn.release(napi_tsfn_release).unwrap(); }); ctx.env.get_undefined() } #[js_function(1)] pub fn test_tsfn_error(ctx: CallContext) -> Result { let func = ctx.get::(0)?; let to_js = HandleNumber; let tsfn = ThreadsafeFunction::create(ctx.env, func, to_js, 0)?; thread::spawn(move || { tsfn .call( Err(Error::new(Status::Unknown, "invalid".to_owned())), napi_tsfn_blocking, ) .unwrap(); tsfn.release(napi_tsfn_release).unwrap(); }); ctx.env.get_undefined() } #[derive(Copy, Clone)] struct HandleBuffer; impl ToJs for HandleBuffer { type Output = Vec; type JsValue = JsBuffer; fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<(u64, JsBuffer)> { let value = env.create_buffer_with_data(output.to_vec())?; Ok((1u64, value)) } } async fn read_file_content(filepath: &Path) -> Result> { tokio::fs::read(filepath) .await .map_err(|_| Error::new(Status::Unknown, "failed to read file".to_owned())) } #[js_function(2)] pub fn test_tokio_readfile(ctx: CallContext) -> Result { let js_filepath = ctx.get::(0)?; let js_func = ctx.get::(1)?; let path_str = js_filepath.as_str()?; let to_js = HandleBuffer; let tsfn = ThreadsafeFunction::create(ctx.env, js_func, to_js, 0)?; let mut rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async move { let mut filepath = Path::new(path_str); let ret = read_file_content(&mut filepath).await; let _ = tsfn.call(ret, napi_tsfn_blocking); tsfn.release(napi_tsfn_release).unwrap(); }); ctx.env.get_undefined() }