I need a way to invoke JS callbacks from a C library that uses contexts.
Here's an example:
const ctx1 = mylib_init();
mylib_set_event_callback(ctx1, () => {
console.log("EVENT");
});
Napi::FunctionReference cb;
bool done = false; // Used to prevent crash on multithreading.
// TSFN would obviously be used; this is just to shorten it.
extern "C" void onEvent(mylib_t* handle, void* userdata) {
if (cb != nullptr && !done) {
done = true;
cb.Call({});
}
}
Napi::Value MyWrapper::SetEventCallback(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Object global = env.Global();
// info[0] = mylib_t* previously converted to a BigInt.
// info[1] = JS callback
mylib_t* handle = convertJSBigIntToHandle(info[0]);
r_cb = Napi::Persistent(info[1].As<Napi::Function>());
const auto ret = mylib_set_callback(handle, onEvent, nullptr);
return env.Null();
}
This works (the JS callback is run), but the problem is that the callback is global.
If I have ctx2 and call mylib_set_event_callback again, it will overwrite the callback from ctx1.
How can I convert this so that callbacks for ctx1 and ctx2 will both be called?
Your callback is global because it is in a global variable.
You should place the
Napi::FunctionReferencein themylib_tstructure.If you cannot modify that structure, I see that you can pass a a context pointer in
userdata- you are passingnullptr. Create dynamically aNapi::FunctionReferencewithnewand pass this pointer so that you can have it inonEvent.You should also properly the reference when the structure is destroyed or the function is replaced.