Make the addon context-aware
See original GitHub issueIt would be great if we could make node-usb context aware, i.e. so it can be initialized multiple times from different Node.js instances (node_envs). (Actually the addon incorrectly declares itself as context aware, and that’s why users get crashes)
This way it can safely run in Electron and worker threads, probably fixing: #458 #378
This basically requires global variables to be moved to environment-specific data.
Required changes
I've reviewed the code to see the variables we should move, let me know if I'm missing something.At least the following static variables in
Device
(I think node-addon-api already saves constructor for us):And the following hotplug global variables:
And because each context will use different threads, this as well (or protect with a mutex):
I think it would be a good idea to use a different libusb context for each Node.js context, so this too:
As an implication, we also need to implement cleanup (make the addon unloadable) with a cleanup hook. In Windows, we need to tell the thread to exit + join it. Then the tests.
I’m not saying I’ll have time to do this, just opening this to track the issue (and point people complaining about Electron / workers here) and to see what your thoughts are.
Issue Analytics
- State:
- Created a year ago
- Comments:10 (4 by maintainers)
Nice!
The cleanest way as you say is
Napi::Addon
. If you don’t want to refactor all the code into a single class,env.GetInstanceData()
with a struct works just as well (it’s just a bit more verbose to access instance data). Example (the constructor isn’t necessary). It’s also easier to polyfill if we want to preserve support with v10, see below.ah, true. The proper way to make this addon context-aware is using
napi_set_instance_data
/napi_get_instance_data
, which would require dropping support for v10 and requiring v12, but given that v10 reached EOL long ago, and v12 will in a few days, I think that’s reasonable?If you would like to preserve support,
napi_get_instance_data
can be emulated by saving the instance data in the JS module object, with an ObjectWrap like always, and making sure it gets passed to the global callbacks + constructors. It’s more cumbersome but shouldn’t make a significant difference.