Merge pull request #209 from napi-rs/env-cleanup-hook
feat(napi): implement env cleanup hook
This commit is contained in:
commit
64bf2e81be
9 changed files with 110 additions and 12 deletions
8
.github/workflows/napi3.yaml
vendored
8
.github/workflows/napi3.yaml
vendored
|
@ -7,7 +7,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_test:
|
build_and_test:
|
||||||
name: stable - x86_64-unknown-linux-gnu - node@10.0
|
name: stable - x86_64-unknown-linux-gnu - node@10.2
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -15,9 +15,9 @@ jobs:
|
||||||
|
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
run: |
|
run: |
|
||||||
wget https://nodejs.org/dist/v10.0.0/node-v10.0.0-linux-x64.tar.xz
|
wget https://nodejs.org/dist/v10.2.0/node-v10.2.0-linux-x64.tar.xz
|
||||||
tar xf node-v10.0.0-linux-x64.tar.xz
|
tar xf node-v10.2.0-linux-x64.tar.xz
|
||||||
echo "::add-path::$(pwd)/node-v10.0.0-linux-x64/bin"
|
echo "::add-path::$(pwd)/node-v10.2.0-linux-x64/bin"
|
||||||
|
|
||||||
- name: Install stable
|
- name: Install stable
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::error::check_status;
|
||||||
use crate::{sys, Either, Env, Error, JsUndefined, NapiValue, Result, Status};
|
use crate::{sys, Either, Env, Error, JsUndefined, NapiValue, Result, Status};
|
||||||
|
|
||||||
pub struct CallContext<'env> {
|
pub struct CallContext<'env> {
|
||||||
pub env: &'env Env,
|
pub env: &'env mut Env,
|
||||||
raw_this: sys::napi_value,
|
raw_this: sys::napi_value,
|
||||||
callback_info: sys::napi_callback_info,
|
callback_info: sys::napi_callback_info,
|
||||||
args: &'env [sys::napi_value],
|
args: &'env [sys::napi_value],
|
||||||
|
@ -14,7 +14,7 @@ pub struct CallContext<'env> {
|
||||||
|
|
||||||
impl<'env> CallContext<'env> {
|
impl<'env> CallContext<'env> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
env: &'env Env,
|
env: &'env mut Env,
|
||||||
callback_info: sys::napi_callback_info,
|
callback_info: sys::napi_callback_info,
|
||||||
raw_this: sys::napi_value,
|
raw_this: sys::napi_value,
|
||||||
args: &'env [sys::napi_value],
|
args: &'env [sys::napi_value],
|
||||||
|
|
8
napi/src/cleanup_env.rs
Normal file
8
napi/src/cleanup_env.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
pub(crate) struct CleanupEnvHookData<T: 'static> {
|
||||||
|
pub(crate) data: T,
|
||||||
|
pub(crate) hook: Box<dyn FnOnce(T) -> ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct CleanupEnvHook<T: 'static>(pub(crate) *mut CleanupEnvHookData<T>);
|
|
@ -5,6 +5,7 @@ use std::mem;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
||||||
use crate::async_work::{self, AsyncWorkPromise};
|
use crate::async_work::{self, AsyncWorkPromise};
|
||||||
use crate::error::check_status;
|
use crate::error::check_status;
|
||||||
use crate::js_values::*;
|
use crate::js_values::*;
|
||||||
|
@ -455,13 +456,12 @@ impl Env {
|
||||||
let tagged_object: *mut TaggedObject<T> = mem::transmute(unknown_tagged_object);
|
let tagged_object: *mut TaggedObject<T> = mem::transmute(unknown_tagged_object);
|
||||||
(*tagged_object).object.as_mut().ok_or(Error {
|
(*tagged_object).object.as_mut().ok_or(Error {
|
||||||
status: Status::InvalidArg,
|
status: Status::InvalidArg,
|
||||||
reason: "Invalid argument, nothing attach to js_external".to_owned(),
|
reason: "nothing attach to js_external".to_owned(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error {
|
Err(Error {
|
||||||
status: Status::InvalidArg,
|
status: Status::InvalidArg,
|
||||||
reason: "Invalid argument, T on get_value_external is not the type of wrapped object"
|
reason: "T on get_value_external is not the type of wrapped object".to_owned(),
|
||||||
.to_owned(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,6 +519,41 @@ impl Env {
|
||||||
Ok(uv_loop)
|
Ok(uv_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(napi3)]
|
||||||
|
pub fn add_env_cleanup_hook<T, F>(
|
||||||
|
&mut self,
|
||||||
|
cleanup_data: T,
|
||||||
|
cleanup_fn: F,
|
||||||
|
) -> Result<CleanupEnvHook<T>>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
F: 'static + FnOnce(T) -> (),
|
||||||
|
{
|
||||||
|
let hook = CleanupEnvHookData {
|
||||||
|
data: cleanup_data,
|
||||||
|
hook: Box::new(cleanup_fn),
|
||||||
|
};
|
||||||
|
let hook_ref = Box::leak(Box::new(hook));
|
||||||
|
check_status(unsafe {
|
||||||
|
sys::napi_add_env_cleanup_hook(
|
||||||
|
self.0,
|
||||||
|
Some(cleanup_env::<T>),
|
||||||
|
hook_ref as *mut CleanupEnvHookData<T> as *mut _,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(CleanupEnvHook(hook_ref))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(napi3)]
|
||||||
|
pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
|
check_status(unsafe {
|
||||||
|
sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "libuv", napi4))]
|
#[cfg(all(feature = "libuv", napi4))]
|
||||||
pub fn execute<
|
pub fn execute<
|
||||||
T: 'static + Send,
|
T: 'static + Send,
|
||||||
|
@ -665,3 +700,8 @@ unsafe extern "C" fn raw_finalize<T>(
|
||||||
let tagged_object: *mut TaggedObject<T> = mem::transmute(finalize_data);
|
let tagged_object: *mut TaggedObject<T> = mem::transmute(finalize_data);
|
||||||
Box::from_raw(tagged_object);
|
Box::from_raw(tagged_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
|
||||||
|
let cleanup_env_hook = Box::from_raw(hook_data as *mut CleanupEnvHookData<T>);
|
||||||
|
(cleanup_env_hook.hook)(cleanup_env_hook.data);
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
|
|
||||||
mod async_work;
|
mod async_work;
|
||||||
mod call_context;
|
mod call_context;
|
||||||
|
mod cleanup_env;
|
||||||
mod env;
|
mod env;
|
||||||
mod error;
|
mod error;
|
||||||
mod js_values;
|
mod js_values;
|
||||||
|
@ -100,6 +101,8 @@ mod module;
|
||||||
mod promise;
|
mod promise;
|
||||||
mod status;
|
mod status;
|
||||||
mod task;
|
mod task;
|
||||||
|
#[cfg(napi3)]
|
||||||
|
pub use cleanup_env::CleanupEnvHook;
|
||||||
#[cfg(napi4)]
|
#[cfg(napi4)]
|
||||||
pub mod threadsafe_function;
|
pub mod threadsafe_function;
|
||||||
#[cfg(all(feature = "tokio_rt", napi4))]
|
#[cfg(all(feature = "tokio_rt", napi4))]
|
||||||
|
|
|
@ -124,15 +124,14 @@ impl<T: ToJs> ThreadsafeFunction<T> {
|
||||||
pub fn create(env: &Env, func: JsFunction, to_js: T, max_queue_size: u64) -> Result<Self> {
|
pub fn create(env: &Env, func: JsFunction, to_js: T, max_queue_size: u64) -> Result<Self> {
|
||||||
let mut async_resource_name = ptr::null_mut();
|
let mut async_resource_name = ptr::null_mut();
|
||||||
let s = "napi_rs_threadsafe_function";
|
let s = "napi_rs_threadsafe_function";
|
||||||
let status = unsafe {
|
check_status(unsafe {
|
||||||
sys::napi_create_string_utf8(
|
sys::napi_create_string_utf8(
|
||||||
env.0,
|
env.0,
|
||||||
s.as_ptr() as *const c_char,
|
s.as_ptr() as *const c_char,
|
||||||
s.len() as u64,
|
s.len() as u64,
|
||||||
&mut async_resource_name,
|
&mut async_resource_name,
|
||||||
)
|
)
|
||||||
};
|
})?;
|
||||||
check_status(status)?;
|
|
||||||
|
|
||||||
let initial_thread_count: u64 = 1;
|
let initial_thread_count: u64 = 1;
|
||||||
let mut result = ptr::null_mut();
|
let mut result = ptr::null_mut();
|
||||||
|
|
17
test_module/__test__/cleanup-env.spec.ts
Normal file
17
test_module/__test__/cleanup-env.spec.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import test from 'ava'
|
||||||
|
|
||||||
|
const bindings = require('../index.node')
|
||||||
|
|
||||||
|
test('should be able to add cleanup hook', (t) => {
|
||||||
|
t.notThrows(() => {
|
||||||
|
const ret = bindings.addCleanupHook()
|
||||||
|
t.is(typeof ret, 'object')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should be able to remove cleanup hook', (t) => {
|
||||||
|
t.notThrows(() => {
|
||||||
|
const ret = bindings.addCleanupHook()
|
||||||
|
bindings.removeCleanupHook(ret)
|
||||||
|
})
|
||||||
|
})
|
27
test_module/src/cleanup_env.rs
Normal file
27
test_module/src/cleanup_env.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
use napi::{
|
||||||
|
CallContext, CleanupEnvHook, ContextlessResult, Env, JsExternal, JsUndefined, Module, Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[contextless_function]
|
||||||
|
fn add_cleanup_hook(mut env: Env) -> ContextlessResult<JsExternal> {
|
||||||
|
let hook = env.add_env_cleanup_hook((), |_| {
|
||||||
|
println!("cleanup hook executed");
|
||||||
|
})?;
|
||||||
|
env.create_external(hook).map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
fn remove_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
let hook_external = ctx.get::<JsExternal>(0)?;
|
||||||
|
let hook = *ctx
|
||||||
|
.env
|
||||||
|
.get_value_external::<CleanupEnvHook<()>>(&hook_external)?;
|
||||||
|
ctx.env.remove_env_cleanup_hook(hook)?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_js(module: &mut Module) -> Result<()> {
|
||||||
|
module.create_named_method("addCleanupHook", add_cleanup_hook)?;
|
||||||
|
module.create_named_method("removeCleanupHook", remove_cleanup_hook)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ extern crate serde_derive;
|
||||||
|
|
||||||
use napi::{Module, Result};
|
use napi::{Module, Result};
|
||||||
|
|
||||||
|
#[cfg(napi3)]
|
||||||
|
mod cleanup_env;
|
||||||
#[cfg(napi4)]
|
#[cfg(napi4)]
|
||||||
mod libuv;
|
mod libuv;
|
||||||
#[cfg(napi4)]
|
#[cfg(napi4)]
|
||||||
|
@ -54,6 +56,8 @@ fn init(module: &mut Module) -> Result<()> {
|
||||||
env::register_js(module)?;
|
env::register_js(module)?;
|
||||||
object::register_js(module)?;
|
object::register_js(module)?;
|
||||||
global::register_js(module)?;
|
global::register_js(module)?;
|
||||||
|
#[cfg(napi3)]
|
||||||
|
cleanup_env::register_js(module)?;
|
||||||
#[cfg(napi4)]
|
#[cfg(napi4)]
|
||||||
napi4::register_js(module)?;
|
napi4::register_js(module)?;
|
||||||
#[cfg(napi4)]
|
#[cfg(napi4)]
|
||||||
|
|
Loading…
Reference in a new issue