Closed alshdavid closed 6 months ago
This works:
globalThis.pluginFunc = () => console.log('hi')
require('./index.node')
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
let value = cx.global().get_value(&mut cx, "pluginFunc").unwrap();
let value: Handle<JsFunction> = value.downcast(&mut cx).unwrap();
let result: Handle<JsString> = value
.call_with(&mut cx)
.arg(cx.string("Hello"))
.apply(&mut cx)?;
Ok(())
}
Yep, that is correct for calling a function. If you need to hold the function permanently, the Root
type can be used for that. js_func.root()
.
If you need to call into JS from a Rust thread, the Channel
type helps with that.
I am trying to call a JS function on different threads to build a javascript "plugin API" for a Rust based project - so I need to orchestrate everything from my main napi thread but call into functions that live on the worker thread contexts.
Right now I am using a static global variable to hold channels and have the main JS napi instance message the JS worker napi modules - but is it possible to wrap the function pointers from the workers in a struct/scope, store it in the global static variable, and call them from main?
Something like
let ctx_func = cx.global().get_value(&mut cx, "callback").unwrap();
let ctx_func: Handle<JsFunction> = ctx_func.downcast(&mut cx).unwrap();
// I know this doesn't work but you get what I'm trying to achieve
let call_callback = || {
let result = ctx_func
.call_with(&mut cx)
.apply::<JsObject, FunctionContext>(&mut cx)?;
let file_path: Handle<JsString> = result
.downcast(&mut cx)
.unwrap();
return file_path.value(&mut cx);
};
SHARED_STATE.lock().unwrap().push(call_callback);
Current implementation
Plugin to be loaded dynamically https://github.com/alshdavid-labs/reference-node-and-rust/blob/main/plugin/index.js
Javascript entrypoint https://github.com/alshdavid-labs/reference-node-and-rust/blob/main/napi/lib/index.js
Napi function that runs on the main Node context https://github.com/alshdavid-labs/reference-node-and-rust/blob/main/napi/src/register_main.rs
Napi function that runs on the worker Node context https://github.com/alshdavid-labs/reference-node-and-rust/blob/main/napi/src/register_worker.rs
Bonus question How do I resolve a promise from napi so I can make the plugin support async/await syntax?
but is it possible to wrap the function pointers from the workers in a struct/scope, store it in the global static variable, and call them from main? Workers are distinct JS runtimes running on a different thread. Unfortunately, it's not possible to call directly into them from the main thread.
It doesn't need to be a global static. It could be in a JsBox
that JS holds or it could use Neon's equivalent to thread local storage, but it still requires a Channel
to call into the other thread.
Alternatively, you could use standard message passing between themain thread and the worker.
How do I resolve a promise from napi so I can make the plugin support async/await syntax?
https://docs.rs/neon/1.0.0-alpha.4/neon/types/struct.JsPromise.html
Thanks for your help, I know they are basic questions and I really appreciate the support 🙏
Hi, I am exporting a
register_plugin
function that takes a function as an argument, captures it and intends to call it later.At the moment I am just trying to store one function handle in Rust - eventually I will keep a store functions per worker thread and coordinate calling them in their own module context in Rust via channels.
At the moment I am failing on the first step where I am trying to capture a function handle in Rust.
Right now I am trying something like this:
Alternatively, can I call a function registered on a global variable?
That way I can keep the index of functions on the JS side and simply call them from
fn main()
in Rust (assumingrequire('./index.node)
happens after the values are available?)