Я довольно новичок в разработке C ++ и дополнения node / v8.
Я пытаюсь обернуть стороннюю C-библиотеку.
Некоторые функции инициализации выполняются довольно долго, и я хотел бы выполнять эти операции асинхронно (с помощью libuv).
Учитывая, что у меня есть следующий код:
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"
//header files of 3rd party lib to be wrapped
#include "3rdparty.h"
using namespace v8;
MyObject::MyObject(void* base) : baseobject_(base) {};
MyObject::~MyObject() {};
void MyObject::Init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("MyObject"), constructor);
}
Handle<Value> MyObject::New(const Arguments& args) {
HandleScope scope;
if (args.IsConstructCall())
{
void* cStruct = NULL;
//
//VERY LONG TAKING OPERATION
//Want to run this async with help of libuv
createStructIn3rdPartyLib(&cStruct);
//create actual Object and pass in cStruct which becomes private field.
MyObject* obj = new MyObject(cStruct);
obj->Wrap(args.This());
return args.This();
}
return scope.Close(Undefined());
}
Я хочу бежать createStructIn3rdPartyLib(&cStruct);
с помощью библиотеки libuv.
Вот то, что я придумал. К сожалению, это дает мне ошибку сегментации, и я не совсем уверен, правильный ли это подход.
Я уже изучил источник других нод-аддонов, но не нашел решения для моей проблемы. 🙁
Любые намеки приветствуются.
#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"
//header files of 3rd party lib to be wrapped
#include "3rdparty.h"
using namespace v8;
// libuv allows us to pass around a pointer to an arbitrary
// object when running asynchronous functions. We create a
// data structure to hold the data we need during and after
// the async work.
typedef struct AsyncData {
Persistent<Function> callback; // callback function
void *3rdpartydata
Arguments *args;
} AsyncData;
MyObject::MyObject() {};
MyObject::~MyObject() {};
void MyObject::Init(Handle<Object> target) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->SetClassName(String::NewSymbol("MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
target->Set(String::NewSymbol("MyObject"), constructor);
target->Set(String::NewSymbol("createObject"),
FunctionTemplate::New(New)->GetFunction(CreateObjectAsync));
}
Handle<Value> MyObject::New(const Arguments& args) {
HandleScope scope;
if (args.IsConstructCall())
{
void* cStruct = NULL;
//
//VERY LONG TAKING OPERATION
//Want to run this async with help of libuv
createStructIn3rdPartyLib(&cStruct);
//create actual Object and pass in cStruct which becomes private field.
MyObject* obj = new MyObject(&cStruct);
obj->Wrap(args.This());
return args.This();
}
return scope.Close(Undefined());
}
Handle<Value> MyObject::CreateObjectAsync(const Arguments& args)
{
HandleScope scope;
// create an async work token
uv_work_t *req = new uv_work_t;
// assign our data structure that will be passed around
AsyncData *asyncData = new AsyncData();
req->data = asyncData;
// expect a function as the 1st argument
// we create a Persistent reference to it so
// it won't be garbage-collected
asyncData->callback = Persistent<Function>::New(
Local<Function>::Cast(args[0]));
*(asyncData->args) = args;
// pass the work token to libuv to be run when a
// worker-thread is available to
uv_queue_work(
uv_default_loop(),
req, // work token
AsyncWork, // work function
(uv_after_work_cb)AsyncAfter // function to run when complete
);
return scope.Close(Undefined());
}// Function to execute inside the worker-thread.
// It is not safe to access V8, or V8 data structures
// here, so everything we need for input and output
// should go on our req->data object.
void MyObject::AsyncWork(uv_work_t *req) {
// fetch our data structure
AsyncData *asyncData = (AsyncData *)req->data;
// run 3rd Party Function.
createStructIn3rdPartyLib(&asyncData->3rdpartydata);
}
// Function to execute when the async work is complete
// this function will be run inside the main event loop
// so it is safe to use V8 again
void MyObject::AsyncAfter(uv_work_t *req) {
HandleScope scope;
// fetch our data structure
AsyncData *asyncData = (AsyncData *)req->data;// create an arguments array for the callback
MyObject *cpBase = new MyObject(asyncData->3rdpartydata);
cpBase->Wrap((*asyncData->args).This());
Handle<Value> argv[] = {Null(),(*asyncData->args).This()};
// surround in a try/catch for safety
TryCatch try_catch;
// execute the callback function
asyncData->callback->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught())
node::FatalException(try_catch);
// dispose the Persistent handle so the callback
// function can be garbage-collected
asyncData->callback.Dispose();
// clean up any memory we allocated
delete asyncData;
delete req;
}
Спасибо!!!
Редактировать:
Я после прочтения больше примеров, таких как привязки нод-огг Я все больше думаю о том, что нахожусь на неправильном пути с моим подходом. Возможно я должен остаться на намного более низком уровне на стороне C / C ++ и реализовать функциональность объекта на стороне javascript.
Задача ещё не решена.
Других решений пока нет …