Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail to invoke the cached JS Callback, due to the error "napi call failed InvalidArg" #224

Closed
stuartZhang opened this issue Aug 22, 2023 · 1 comment

Comments

@stuartZhang
Copy link

stuartZhang commented Aug 22, 2023

Hello,

I'd like to globally hold a reference of the callback function originating from the JS side in the Rust static variable so that the callback function can be invoked within any Rust functions.

At the moment, the callback function is able to be stored in a Rust static variable, by virtue of both the lifetime parameter 'static and the macro std::thread_local!. Nevertheless, the later invocation against the retained callback function brings about a runtime error "napi call failed InvalidArg".

My code snippet is as follows

/// static variable storing the JS Callback function
std::thread_local! {
    static LOGGER: RefCell<Option<Box<dyn Fn(String)>>> = RefCell::new(None);
}
/// the wrapper for invoking the cached js callback function
fn log(text: String) -> bool {
    LOGGER.with(|log| {
        let log = log.borrow();
        if let Some(log) = log.as_ref() {
            log(text);
            true
        } else {
            false
        }
    })
}
#[node_bindgen]
fn set_logger<F: Fn(String) + 'static>(logger: F) {
    let logger: Box<dyn Fn(String)> = Box::new(logger);
    LOGGER.with(|log| {
        log.borrow_mut().replace(logger); // Store the js callback function into the static variable
    });
    log("[set_logger]".to_string()); // Succeed to immediately invoke it.
}
#[node_bindgen]
fn get_edition() -> GitEdition {
    log("Failure".to_string()); // Fail! A runtime error "napi call failed InvalidArg" will be thrown.
    GitEdition::default()
}
const addon = require('./dist/index.node');
addon.setLogger(function(text){console.log(text)});
addon.getEdition(); // Fail here.

Are there any workarounds useful to solve the problem?

To my knowledge, there is a struct Closure in the wasm_bindgen crate for the same purpose. By means of wasm_bindgen::closure::Closure, a JS callback function conveyed into the WASM module is augmented and able to be invoked across the different exported function API.

Is there the counterpart of the struct wasm_bindgen::closure::Closure in the node_bindgen crate?

@sehz
Copy link
Collaborator

sehz commented Aug 30, 2023

That's an interesting possibility. We haven't done anything in WASM integration but welcome any contribution in that area

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants