Send events from nodejs node to javascript

I am currently creating an application (Electron) and I need to link it to the C ++ library. I did most of the binding using NodeJS C ++ add-ons, but I don’t have the important part related to receiving events generated by the C ++ library in my Javascript code.

void Event1(int64_t id) { ArrayBufferAllocator allocator; Isolate::CreateParams create_params; create_params.array_buffer_allocator = &allocator; Isolate* isolate = Isolate::New(create_params); { v8::Locker locker(isolate); Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); Local<Context> context = Context::New(isolate); Context::Scope context_scope(context); v8::Local<v8::Value> argv[1] = { Nan::New("OnWillPlayTrack").ToLocalChecked(), // event name }; Nan::MakeCallback(isolate->GetCurrentContext()->Global(),"emit", 1, argv); } isolate->Dispose(); } 

Event1 is called by C ++ lib, which has nothing to do with V8, and now I want to fire the event in JavaScript, back to Node (EventEmitter?). I think the biggest problem is that most v8 features now need to be isolated, and most of the examples found on the Internet are pretty old.

Event1 event in MakeCallBack crashes with:

 Thread 24 Crashed:: App 0 libnode.dylib 0x000000010a81e35b v8::String::NewFromOneByte(v8::Isolate*, unsigned char const*, v8::String::NewStringType, int) + 43 1 libnode.dylib 0x000000010a4b042f node::OneByteString(v8::Isolate*, char const*, int) + 15 2 libnode.dylib 0x000000010a4ba1b2 node::MakeCallback(node::Environment*, v8::Local<v8::Object>, char const*, int, v8::Local<v8::Value>*) + 50 3 libnode.dylib 0x000000010a4ba240 node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, char const*, int, v8::Local<v8::Value>*) + 96 4 addon.node 0x0000000110e62e1f Event1(long long) + 291 (v8.h:6721) 

Any help would be greatly appreciated!

+7
c ++ javascript v8 electron
source share
2 answers

You do not need a separate v8::Isolate to call V8 from your code, you only need one if you want multiple v8 engines run multiple Javascript interpreters in parallel.

I think the reason for your problem is that you are calling V8 from a different thread, which is pretty risky. Use the uv_acync_t structure to signal the "main / V8" stream from your C ++ add-on stream. For more on how to do this, see this thread .

Also, MakeCallback not the proper way to cancel callbacks, see https://github.com/nodejs/nan/issues/284 .

+2
source share

A common practice for emitting events from the Node.js C ++ add-ons module is to port the C ++ component using the javascript component and send them together as a single module. The javascript component passes the callback to the C ++ component. When a C ++ component receives an event, it should call a javascript callback, which in turn should use the EventEmitter to emit .

If you want to see an example of this in practice, I do this in my node-dvbtee module module: http://github.com/mkrufky/node-dvbtee

The source of C ++ add-ons is built from the src/ directory.

The javascript shell can be found in the lib/ directory.

Browse lib/parser.js to find where the listenTables function listenTables called with the callback function as a parameter. Depending on the options module configured, this callback will either call self.push() (for streaming) or self.emit() to generate an event.

To avoid rotting links, a javascript example looks like this:

 var _Dvbtee = require('bindings')('dvbtee.node') var util = require('util') var stream = require('stream') var Parser = function (options) { var self = this if (!(this instanceof Parser)) { return new Parser(options) } self.options = {} if (typeof options === 'object') { self.options.passThru = (options.hasOwnProperty('passThru') && options.passThru) } else { self.options.passThru = false } var _parser = new _Dvbtee.Parser var _listenTables = _Dvbtee.Parser.prototype.listenTables var listenTables = _listenTables.bind(_parser) stream.Transform.call(this, { objectMode: !self.options.passThru }) self._buffer = new Buffer(0) listenTables(function(a,b,c) { // arguments a & b are ignored self.emit('psip', c) }) } util.inherits(Parser, stream.Transform) Parser.prototype._transform = ... 

The C ++ addon component will have to store the provided callback function in a constant descriptor. NAN provides the perfect structure for this: Nan::Callback

The code for the addon C ++ component should look something like this:

 void dvbteeParser::listenTables(const Nan::FunctionCallbackInfo<v8::Value>& info) { dvbteeParser* obj = ObjectWrap::Unwrap<dvbteeParser>(info.Holder()); int lastArg = info.Length() - 1; if ((lastArg >= 0) && (info[lastArg]->IsFunction())) { obj->m_tableReceiver.subscribe(info[lastArg].As<v8::Function>()); } info.GetReturnValue().Set(info.Holder()); } 

...

 void TableReceiver::subscribe(const v8::Local<v8::Function> &fn) { m_cb.SetFunction(fn); } 

... where m_cb is Nan::Callback inside my TableReceiver class. You can indeed call this callback in your own addon event-generation function as follows:

 v8::Local<v8::Value> argv[] = { a, b, c }; m_cb.Call(3, argv); 

where a, b and c are of type v8::Local<v8::Value> . Of course, the argv array can be of any size. Each element corresponds to the argument provided to this callback function.

+2
source share

All Articles