From 9df9f890f72b5471ed5158efda2c604258e35499 Mon Sep 17 00:00:00 2001 From: richerfu <32590310+richerfu@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:14:32 +0800 Subject: [PATCH] feat(napi): add on_abort for AbortSignal (#2942) * feat(napi): add on_abort for AbortSignal * chore: upgrade example code * fix: fix lint error * fix: fix lint error * Update examples/napi/src/task.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update crates/napi/src/bindgen_runtime/js_values/task.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fmt --------- Co-authored-by: LongYinan Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/bindgen_runtime/js_values/task.rs | 18 +++++++++ .../__tests__/__snapshots__/values.spec.ts.md | 2 + .../__snapshots__/values.spec.ts.snap | Bin 8361 -> 8398 bytes examples/napi/__tests__/values.spec.ts | 15 ++++++++ examples/napi/example.wasi-browser.js | 1 + examples/napi/example.wasi.cjs | 1 + examples/napi/index.cjs | 19 +++++++++ examples/napi/index.d.cts | 2 + examples/napi/src/task.rs | 36 +++++++++++++++++- 9 files changed, 93 insertions(+), 1 deletion(-) diff --git a/crates/napi/src/bindgen_runtime/js_values/task.rs b/crates/napi/src/bindgen_runtime/js_values/task.rs index 9b7df92c..3c37ae7d 100644 --- a/crates/napi/src/bindgen_runtime/js_values/task.rs +++ b/crates/napi/src/bindgen_runtime/js_values/task.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::ffi::c_void; use std::marker::PhantomData; use std::ptr; @@ -50,10 +51,19 @@ impl ScopedTask<'task>> AsyncTask { } } +type AbortCallback = Rc>>>; + /// pub struct AbortSignal { raw_work: Rc>, status: Rc>, + abort: AbortCallback, +} + +impl AbortSignal { + pub fn on_abort(&self, cb: F) { + self.abort.borrow_mut().push(Box::new(cb)); + } } impl UnwindSafe for AbortSignal {} @@ -74,9 +84,11 @@ impl FromNapiValue for AbortSignal { ); let async_work_inner: Rc> = Rc::new(Cell::new(ptr::null_mut())); let task_status = Rc::new(Cell::new(0)); + let abort_cbs = Rc::new(RefCell::new(vec![])); let abort_signal = AbortSignal { raw_work: async_work_inner.clone(), status: task_status.clone(), + abort: abort_cbs.clone(), }; let js_env = Env::from_raw(env); @@ -111,6 +123,7 @@ impl FromNapiValue for AbortSignal { Ok(AbortSignal { raw_work: async_work_inner, status: task_status, + abort: abort_cbs, }) } } @@ -153,6 +166,11 @@ fn on_abort_impl( )?; let abort_controller_stack = Box::leak(Box::from_raw(async_task as *mut AbortSignalStack)); for abort_controller in abort_controller_stack.0.iter() { + // call abort callback + for cb in abort_controller.abort.borrow().iter() { + cb(); + } + // Task Completed, return now if abort_controller.status.get() == 1 { return Ok(ptr::null_mut()); diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.md b/examples/napi/__tests__/__snapshots__/values.spec.ts.md index e31773b3..444d3160 100644 --- a/examples/napi/__tests__/__snapshots__/values.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/values.spec.ts.md @@ -1234,6 +1234,8 @@ Generated by [AVA](https://avajs.dev). ␊ export declare function withAbortController(a: number, b: number, signal: AbortSignal): Promise␊ ␊ + export declare function withAbortSignalHandle(signal: AbortSignal): Promise␊ + ␊ export declare function withinAsyncRuntimeIfAvailable(): void␊ ␊ export declare function withoutAbortController(a: number, b: number): Promise␊ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 3d124f6deb21a0d9c6af7d1867d06dade24f25d0..3b4e8373963a88f7f7998d1af5de87aa4af6e876 100644 GIT binary patch literal 8398 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 literal 8361 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 diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 04a28314..404570e0 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -287,6 +287,7 @@ import { indexSetToRust, indexSetToJs, intoUtf8, + withAbortSignalHandle, } from '../index.cjs' // import other stuff in `#[napi(module_exports)]` import nativeAddon from '../index.cjs' @@ -1460,6 +1461,20 @@ test('async task with different resolved values', async (t) => { t.deepEqual(r2, [0, 1]) }) +AbortSignalTest('with abort signal handle', async (t) => { + const ctrl = new AbortController() + const promise = withAbortSignalHandle(ctrl.signal) + try { + ctrl.abort() + const ret = await promise + t.is(ret, 999) + } catch (err: unknown) { + // sometimes on CI, the scheduled task is able to abort + // so we only allow it to throw AbortError + t.is((err as Error).message, 'AbortError') + } +}) + AbortSignalTest('abort resolved task', async (t) => { const ctrl = new AbortController() await withAbortController(1, 2, ctrl.signal).then(() => ctrl.abort()) diff --git a/examples/napi/example.wasi-browser.js b/examples/napi/example.wasi-browser.js index 86c43280..2583e86b 100644 --- a/examples/napi/example.wasi-browser.js +++ b/examples/napi/example.wasi-browser.js @@ -406,6 +406,7 @@ export const validateTypedArraySlice = __napiModule.exports.validateTypedArraySl export const validateUint8ClampedSlice = __napiModule.exports.validateUint8ClampedSlice export const validateUndefined = __napiModule.exports.validateUndefined export const withAbortController = __napiModule.exports.withAbortController +export const withAbortSignalHandle = __napiModule.exports.withAbortSignalHandle export const withinAsyncRuntimeIfAvailable = __napiModule.exports.withinAsyncRuntimeIfAvailable export const withoutAbortController = __napiModule.exports.withoutAbortController export const xxh64Alias = __napiModule.exports.xxh64Alias diff --git a/examples/napi/example.wasi.cjs b/examples/napi/example.wasi.cjs index 56dfdaf1..12ab879a 100644 --- a/examples/napi/example.wasi.cjs +++ b/examples/napi/example.wasi.cjs @@ -451,6 +451,7 @@ module.exports.validateTypedArraySlice = __napiModule.exports.validateTypedArray module.exports.validateUint8ClampedSlice = __napiModule.exports.validateUint8ClampedSlice module.exports.validateUndefined = __napiModule.exports.validateUndefined module.exports.withAbortController = __napiModule.exports.withAbortController +module.exports.withAbortSignalHandle = __napiModule.exports.withAbortSignalHandle module.exports.withinAsyncRuntimeIfAvailable = __napiModule.exports.withinAsyncRuntimeIfAvailable module.exports.withoutAbortController = __napiModule.exports.withoutAbortController module.exports.xxh64Alias = __napiModule.exports.xxh64Alias diff --git a/examples/napi/index.cjs b/examples/napi/index.cjs index 1fb0aec9..681a2fbc 100644 --- a/examples/napi/index.cjs +++ b/examples/napi/index.cjs @@ -108,7 +108,24 @@ function requireNative() { } } else if (process.platform === 'win32') { if (process.arch === 'x64') { + if (process.report?.getReport?.()?.header?.osName?.startsWith?.('MINGW')) { + try { + return require('./example.win32-x64-gnu.node') + } catch (e) { + loadErrors.push(e) + } try { + const binding = require('@examples/napi-win32-x64-gnu') + const bindingPackageVersion = require('@examples/napi-win32-x64-gnu/package.json').version + if (bindingPackageVersion !== '0.0.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { + throw new Error(`Native binding package version mismatch, expected 0.0.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`) + } + return binding + } catch (e) { + loadErrors.push(e) + } + } else { + try { return require('./example.win32-x64-msvc.node') } catch (e) { loadErrors.push(e) @@ -123,6 +140,7 @@ function requireNative() { } catch (e) { loadErrors.push(e) } + } } else if (process.arch === 'ia32') { try { return require('./example.win32-ia32-msvc.node') @@ -900,6 +918,7 @@ module.exports.validateTypedArraySlice = nativeBinding.validateTypedArraySlice module.exports.validateUint8ClampedSlice = nativeBinding.validateUint8ClampedSlice module.exports.validateUndefined = nativeBinding.validateUndefined module.exports.withAbortController = nativeBinding.withAbortController +module.exports.withAbortSignalHandle = nativeBinding.withAbortSignalHandle module.exports.withinAsyncRuntimeIfAvailable = nativeBinding.withinAsyncRuntimeIfAvailable module.exports.withoutAbortController = nativeBinding.withoutAbortController module.exports.xxh64Alias = nativeBinding.xxh64Alias diff --git a/examples/napi/index.d.cts b/examples/napi/index.d.cts index b87142d1..27628d39 100644 --- a/examples/napi/index.d.cts +++ b/examples/napi/index.d.cts @@ -1195,6 +1195,8 @@ export type VoidNullable = export declare function withAbortController(a: number, b: number, signal: AbortSignal): Promise +export declare function withAbortSignalHandle(signal: AbortSignal): Promise + export declare function withinAsyncRuntimeIfAvailable(): void export declare function withoutAbortController(a: number, b: number): Promise diff --git a/examples/napi/src/task.rs b/examples/napi/src/task.rs index be8a7352..0cac1902 100644 --- a/examples/napi/src/task.rs +++ b/examples/napi/src/task.rs @@ -1,7 +1,34 @@ -use std::thread::sleep; +use std::{sync::mpsc, thread::sleep}; use napi::{bindgen_prelude::*, ScopedTask}; +pub struct SimpleTask { + receiver: mpsc::Receiver, +} + +#[napi] +impl napi::Task for SimpleTask { + type Output = i32; + type JsValue = i32; + + fn compute(&mut self) -> Result { + self.receiver.recv().map_err(|e| { + Error::new( + Status::GenericFailure, + format!("Channel receive error: {}", e), + ) + }) + } + + fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result { + Ok(output) + } + + fn finally(self, _env: napi::Env) -> Result<()> { + Ok(()) + } +} + pub struct DelaySum(u32, u32); #[napi] @@ -33,6 +60,13 @@ pub fn with_abort_controller(a: u32, b: u32, signal: AbortSignal) -> AsyncTask AsyncTask { + let (sender, receiver) = mpsc::channel::(); + signal.on_abort(move || sender.send(999).unwrap()); + AsyncTask::with_signal(SimpleTask { receiver }, signal) +} + struct AsyncTaskVoidReturn {} #[napi]