From f46aa1f67ac078dd67a1ef894aa4866724472697 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Mon, 25 Jan 2021 11:46:58 +0800 Subject: [PATCH] fix(napi): throw JavaScript error in tsfn rather than rust thread panic --- napi/src/threadsafe_function.rs | 45 ++++++++++++++++++- .../napi4/threadsafe_function.spec.ts | 14 ++++++ test_module/__test__/napi4/tsfn-throw.js | 5 +++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 test_module/__test__/napi4/tsfn-throw.js diff --git a/napi/src/threadsafe_function.rs b/napi/src/threadsafe_function.rs index 81c70c09..f60dd8f4 100644 --- a/napi/src/threadsafe_function.rs +++ b/napi/src/threadsafe_function.rs @@ -302,5 +302,48 @@ unsafe extern "C" fn call_js_cb( ); } } - debug_assert!(status == sys::Status::napi_ok, "CallJsCB failed"); + if status == sys::Status::napi_pending_exception { + let mut error_result = ptr::null_mut(); + assert_eq!( + sys::napi_get_and_clear_last_exception(raw_env, &mut error_result), + sys::Status::napi_ok + ); + assert_eq!( + sys::napi_fatal_exception(raw_env, error_result), + sys::Status::napi_ok + ); + } else if status != sys::Status::napi_ok { + let error_code: Status = status.into(); + let error_code_string = format!("{:?}", error_code); + let mut error_code_value = ptr::null_mut(); + assert_eq!( + sys::napi_create_string_utf8( + raw_env, + error_code_string.as_ptr() as *const _, + error_code_string.len(), + &mut error_code_value + ), + sys::Status::napi_ok, + ); + let error_msg = "Call JavaScript callback failed in thread safe function"; + let mut error_msg_value = ptr::null_mut(); + assert_eq!( + sys::napi_create_string_utf8( + raw_env, + error_msg.as_ptr() as *const _, + error_msg.len(), + &mut error_msg_value, + ), + sys::Status::napi_ok, + ); + let mut error_value = ptr::null_mut(); + assert_eq!( + sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value), + sys::Status::napi_ok, + ); + assert_eq!( + sys::napi_fatal_exception(raw_env, error_value), + sys::Status::napi_ok + ); + } } diff --git a/test_module/__test__/napi4/threadsafe_function.spec.ts b/test_module/__test__/napi4/threadsafe_function.spec.ts index 9bb067a4..c158d928 100644 --- a/test_module/__test__/napi4/threadsafe_function.spec.ts +++ b/test_module/__test__/napi4/threadsafe_function.spec.ts @@ -1,3 +1,6 @@ +import { execSync } from 'child_process' +import { join } from 'path' + import test from 'ava' import { napiVersion } from '../napi-version' @@ -72,3 +75,14 @@ test('should work with napi ref', (t) => { }) } }) + +test('should be able to throw error in tsfn', (t) => { + if (napiVersion < 4) { + t.is(bindings.testThreadsafeFunction, undefined) + return + } + + t.throws(() => { + execSync(`node ${join(__dirname, 'tsfn-throw.js')}`) + }) +}) diff --git a/test_module/__test__/napi4/tsfn-throw.js b/test_module/__test__/napi4/tsfn-throw.js new file mode 100644 index 00000000..4c630a4d --- /dev/null +++ b/test_module/__test__/napi4/tsfn-throw.js @@ -0,0 +1,5 @@ +const bindings = require('../../index.node') + +bindings.testThreadsafeFunction(() => { + throw Error('Throw in thread safe function') +})