Nate Nate - 1 year ago 87
Node.js Question

Retrieving and storing V8 object in void * for Node.js Addon

I’m trying to store an object passed from JavaScript to a Node.js Addon in a

void *
. I can’t seem to get this to compile; building with node-gyp produces
error: no matching function for call to 'Cast'

The long version of what I’m trying to do is write a Node.js Addon that runs Csound. Csound works, from a bird’s-eye view, with C functions that take a pointer to an opaque Csound struct as (usually) the first argument. This struct contains a
void *
to “
”, arbitrary data set by a program hosting Csound. Some things that Csound does, like posting messages, are modified with callbacks—function pointers in this case. I need a place to store callbacks for each instance of Csound, so I’m trying to let someone set
to an object from JavaScript, but I also want to set the callbacks for a Csound instance as hidden properties on this

I think the code will need to look something like

#include "csound.h"

#include <node.h>

static void CsoundMessageCallback(CSOUND *Csound, int attributes,
const char *format, va_list valist)
// Call the JavaScript function we stored in the hostData of Csound.

static void _wrap_csoundSetMessageCallback(
const v8::FunctionCallbackInfo<v8::Value>& args)
v8::HandleScope scope(v8::Isolate::GetCurrent());

CSOUND *Csound;
// Pretend we get the Csound instance from args[0] here. This is actually done
// by SWIG <>.

// This does not compile. csoundGetHostData() returns a void *, but I’m assuming
// hostData was set to an object from JavaScript.
v8::Persistent<v8::Object> hostData =

csoundSetMessageCallback(Csound, CsoundMessageCallback);

I’m guessing I need to take a close look at V8’s internal fields, but I’m really not sure.

Answer Source

Typically what I've done in situations like this is I write a wrapper C++ class (inheriting from node's ObjectWrap class) that stores a pointer to the instance of whatever C/C++ class I'm wrapping and has various public methods to interact with that instance.

When new is called from JS land, a new instance of the wrapper C++ class gets created and associated with the new JS object. Then you have JS functions that kick off whatever async tasks that utilize the wrapped library's callbacks.

From there it's just a matter of calling uv_async_send() from the wrapped library's callbacks to signal the main thread and then calling the JS callback from the uv_async callback.

You can see an example of all of this here (especially in the Windows-specific parts):

As far as storing JS callbacks goes, there are different ways to handle that. One solution might be to create a baton object that stores a Persistent copy of the JS callback and the wrapper class instance and store that baton in uv_async_t's user data pointer. This would mean creating a new uv_async_t for every request (which is different than the example I gave above).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download