Merge pull request #209 from napi-rs/env-cleanup-hook

feat(napi): implement env cleanup hook
This commit is contained in:
LongYinan 2020-10-04 16:25:10 +08:00 committed by GitHub
commit 64bf2e81be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 110 additions and 12 deletions

View file

@ -7,7 +7,7 @@ on:
jobs:
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
steps:
@ -15,9 +15,9 @@ jobs:
- name: Setup node
run: |
wget https://nodejs.org/dist/v10.0.0/node-v10.0.0-linux-x64.tar.xz
tar xf node-v10.0.0-linux-x64.tar.xz
echo "::add-path::$(pwd)/node-v10.0.0-linux-x64/bin"
wget https://nodejs.org/dist/v10.2.0/node-v10.2.0-linux-x64.tar.xz
tar xf node-v10.2.0-linux-x64.tar.xz
echo "::add-path::$(pwd)/node-v10.2.0-linux-x64/bin"
- name: Install stable
uses: actions-rs/toolchain@v1

View file

@ -4,7 +4,7 @@ use crate::error::check_status;
use crate::{sys, Either, Env, Error, JsUndefined, NapiValue, Result, Status};
pub struct CallContext<'env> {
pub env: &'env Env,
pub env: &'env mut Env,
raw_this: sys::napi_value,
callback_info: sys::napi_callback_info,
args: &'env [sys::napi_value],
@ -14,7 +14,7 @@ pub struct CallContext<'env> {
impl<'env> CallContext<'env> {
pub fn new(
env: &'env Env,
env: &'env mut Env,
callback_info: sys::napi_callback_info,
raw_this: sys::napi_value,
args: &'env [sys::napi_value],

8
napi/src/cleanup_env.rs Normal file
View 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>);

View file

@ -5,6 +5,7 @@ use std::mem;
use std::os::raw::{c_char, c_void};
use std::ptr;
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
use crate::async_work::{self, AsyncWorkPromise};
use crate::error::check_status;
use crate::js_values::*;
@ -455,13 +456,12 @@ impl Env {
let tagged_object: *mut TaggedObject<T> = mem::transmute(unknown_tagged_object);
(*tagged_object).object.as_mut().ok_or(Error {
status: Status::InvalidArg,
reason: "Invalid argument, nothing attach to js_external".to_owned(),
reason: "nothing attach to js_external".to_owned(),
})
} else {
Err(Error {
status: Status::InvalidArg,
reason: "Invalid argument, T on get_value_external is not the type of wrapped object"
.to_owned(),
reason: "T on get_value_external is not the type of wrapped object".to_owned(),
})
}
}
@ -519,6 +519,41 @@ impl Env {
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))]
pub fn execute<
T: 'static + Send,
@ -665,3 +700,8 @@ unsafe extern "C" fn raw_finalize<T>(
let tagged_object: *mut TaggedObject<T> = mem::transmute(finalize_data);
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);
}

View file

@ -92,6 +92,7 @@
mod async_work;
mod call_context;
mod cleanup_env;
mod env;
mod error;
mod js_values;
@ -100,6 +101,8 @@ mod module;
mod promise;
mod status;
mod task;
#[cfg(napi3)]
pub use cleanup_env::CleanupEnvHook;
#[cfg(napi4)]
pub mod threadsafe_function;
#[cfg(all(feature = "tokio_rt", napi4))]

View file

@ -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> {
let mut async_resource_name = ptr::null_mut();
let s = "napi_rs_threadsafe_function";
let status = unsafe {
check_status(unsafe {
sys::napi_create_string_utf8(
env.0,
s.as_ptr() as *const c_char,
s.len() as u64,
&mut async_resource_name,
)
};
check_status(status)?;
})?;
let initial_thread_count: u64 = 1;
let mut result = ptr::null_mut();

View 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)
})
})

View 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(())
}

View file

@ -7,6 +7,8 @@ extern crate serde_derive;
use napi::{Module, Result};
#[cfg(napi3)]
mod cleanup_env;
#[cfg(napi4)]
mod libuv;
#[cfg(napi4)]
@ -54,6 +56,8 @@ fn init(module: &mut Module) -> Result<()> {
env::register_js(module)?;
object::register_js(module)?;
global::register_js(module)?;
#[cfg(napi3)]
cleanup_env::register_js(module)?;
#[cfg(napi4)]
napi4::register_js(module)?;
#[cfg(napi4)]