Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repeatedly calling a node.js function from c++

Tags:

c++

node.js

v8

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

like image 945
Peter Avatar asked Mar 23 '23 13:03

Peter


1 Answers

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

like image 184
Peter Avatar answered Mar 31 '23 22:03

Peter