Repeatedly calling a node.js function from c++

I am trying to setup a c++ application that should be able to invoke a function that is part of node.js module

While I could find example code on how to create C++ addons for node.js and also some examples on how to invoke V8 code from C++ I did not run into something like calling a node.js function from c++

I guess ideally the approach would be

  • Setup node.js environment, e.g. compile all necessary modules once
  • When the C++ app needs to, invoke one of the "available" node.js functions with arguments
  • Read and process the function's return values

Ideally the node.js code and the c++ code run in the same process context so that it is not necessary to marshall arguments and return values over some stream type of abstraction.

All tips welcome!

Tx

Peter

I eventually managed to get something going

What I struggled most with is how to deal with the node/v8 event loop so that it is started when the javascript function is invoked but also stops when the javascript function is done so that the calling c++ method continues....basically to wait for all the node async processing to be finished.

Briefly what I did is edit a c++ class that does something along the lines of

  • First initialize node, much like in node.cc methods Node::Init and Node::Start and passing in an argument pointing to a node script that defines the function I will want to call

  • Then register a C++ function in node's global namespace that will be used by the javascript function as a final callback. More or less like

    v8::Locker locker;
    v8::HandleScope handle_scope;
    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
    global->Set(v8::String::New("functionCallback"), v8::FunctionTemplate::New(fnCallback,v8::External::Wrap(this)));
    
  • Then invoke the javascript function

    v8::Handle<v8::Value> value = global->Get(v8::String::New(functionName.c_str()));
    v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
    v8::Handle<v8::Value> *v8Args = new v8::Handle<v8::Value>[functionArguments.size()];
    for (std::vector<std::string>::const_iterator it = functionArguments.begin(); it != functionArguments.end(); ++it) {
       int ix = distance(functionArguments.begin(),it);
       v8Args[ix] = v8::String::New((*it).c_str());
    }
    v8::Handle<v8::Value> fnResult;
    fnResult = func->Call(global, functionArguments.size(), v8Args);
    uv_run(uv_default_loop(),UV_RUN_DEFAULT);
    
  • It is important that the invoked javascript function eventually invokes the global callback, as in (javascript)

    global.functionCallback(result);
    
  • This callback (c++) will then store the result and terminate the event loop

    static v8::Handle<v8::Value> fnCallback(const v8::Arguments& args) {
    ...
    // Stop node event loop so that the "calling" app continues (loop is started in execFn)
    uv_stop(uv_default_loop());
    ...
    

I realize this is a bit terse. If someone is interested I can share the c++ class but my c++/v8/node knowledge is very limited so I'd rather not post that in its entirety

Peter