Отправка событий из аддона nodejs в javascript

В настоящее время я создаю приложение (Electron), и мне нужно подключить его с библиотекой C ++. Я выполнил большую часть привязки с помощью аддонов NodeJS c ++, но мне не хватает важной части, связанной с получением событий, генерируемых библиотекой c ++, в моем коде Javascript.

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 вызывается библиотекой c ++, которая не имеет ничего общего с V8, и теперь я хочу запустить событие в JavaScript, обратно в Node (EventEmitter?).
Я думаю, что самая большая проблема заключается в том, что большинству функций v8 теперь требуется Isolate, а большинство примеров, найденных в Интернете, довольно старые.

Код Event1 падает на MakeCallBack с:

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)

Любая помощь будет оценена!

7

Решение

Вам не нужно отдельное v8::Isolate чтобы позвонить V8 из вашего кода, вы хотите только один, если вы хотите несколько v8 engines запустить несколько интерпретаторов Javascript параллельно.

Я думаю, что причина вашей проблемы в том, что вы вызываете V8 из другого потока, что довольно рискованно. Используйте uv_acync_t Структура, чтобы сигнализировать ваш поток ‘main / V8’ из вашего потока дополнений C ++. Увидеть эта тема для более подробной информации о том, как это сделать.

Кроме того, MakeCallback является не правильный способ запустить обратные вызовы, см. https://github.com/nodejs/nan/issues/284.

2

Другие решения

Обычная практика для генерации событий из аддонного модуля C ++ Node.js заключается в том, чтобы обернуть компонент C ++ компонентом javascript и отправить их вместе как один модуль. Компонент javascript передает обратный вызов в компонент c ++. Когда компонент C ++ получает событие, он должен вызвать обратный вызов javascript, который, в свою очередь, должен использовать EventEmitter в emit событие.

Если вы хотите увидеть пример этого на практике, я делаю это в своем node-dvbtee дополнительный модуль: http://github.com/mkrufky/node-dvbtee

Исходный код C ++ построен из src/ каталог.

Оболочка Javascript может быть найдена в lib/ каталог.

Загляни внутрь lib/parser.js найти где функция listenTables вызывается с функцией обратного вызова в качестве параметра. В зависимости от настроенного модуля optionsтот перезвон будет либо звонить self.push() (для потоковой передачи) или self.emit() испустить событие.

Чтобы избежать гниения ссылок, пример JavaScript выглядит так:

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 = ...

Компонент аддона c ++ должен был бы хранить предоставленную функцию обратного вызова в постоянном дескрипторе. NAN обеспечивает идеальную структуру для этого: Nan::Callback

Код компонента расширения c ++ должен выглядеть примерно так:

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);
}

… где m_cb это Nan::Callback внутри моего TableReceiver учебный класс. На самом деле вы можете вызвать этот обратный вызов в функции генерации событий вашего собственного аддона следующим образом:

v8::Local<v8::Value> argv[] = {
a,
b,
c
};

m_cb.Call(3, argv);

где a, b и c имеют тип v8::Local<v8::Value>, Конечно, argv массив может иметь любой размер. Каждый элемент соответствует аргументу, предоставленному данной функции обратного вызова.

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector