Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing ASYNC CPP nodejs (0.5.3+) modules

I´m searching for a way to build c++ modules for NodeJs with the current release (0.5.9). By using the following tutorial and abstracting from nodes node_file.cc I was able to build a module by my self for node 0.5.3.

  • https://github.com/jedp/node-rot13/blob/master/src/rot13.cpp

But with node 0.5.4 some of the API´s must have changed because because I´m no longer able to warp functions with eio_* anymore.

Looking at node_file.cc I discovered that the eio_* wrapping is replaced by new ReqWrap classes.

For Example in this macro: https://gist.github.com/1303926

No I wonder what's the best way of writing async extensions?

like image 881
Alex Avatar asked Oct 21 '11 14:10

Alex


1 Answers

Basically looking at the crypto node module solved my problem this module was not poluted with macros like the file module. I came up with a simple async module that calculates the sum of two integers:

#include <v8.h>
#include <node.h>
#include <stdlib.h>
#include <errno.h>

using namespace node;
using namespace v8;

struct Test_req
{
    ssize_t result;
    ssize_t int1;
    ssize_t int2;
    Persistent<Function> callback;
};

void TestWorker(uv_work_t* req)
{
    Test_req* request = (Test_req*)req->data;
    request->result = request->int1 + request->int2;
}

void TestAfter(uv_work_t* req)
{
    HandleScope scope;

    Test_req* request = (Test_req*)req->data;
    delete req;

    Handle<Value> argv[2];

        // XXX: Error handling
    argv[0] = Undefined();
    argv[1] = Integer::New(request->result);

    TryCatch try_catch;

    request->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught()) 
    {
        FatalException(try_catch);
    }

    request->callback.Dispose();

    delete request;
}


static Handle<Value> Test(const Arguments& args)
{

    HandleScope scope;

    if ( args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsNumber() )
    {
        return ThrowException(Exception::TypeError(String::New("Bad argument")));
    }

    ssize_t int1 ( args[0]->Int32Value() );
    ssize_t int2 ( args[1]->Int32Value() );

    if ( args[2]->IsFunction() )
    {
        Local<Function> callback = Local<Function>::Cast(args[2]);

        Test_req* request = new Test_req;
        request->callback = Persistent<Function>::New(callback);

        request->int1 = int1;
        request->int2 = int2;

        uv_work_t* req = new uv_work_t();
        req->data = request;

        uv_queue_work(uv_default_loop(), req, TestWorker, TestAfter);
    }
    else
    {
        return ThrowException(Exception::TypeError(String::New("Callback missing")));
    }

    return Undefined();
}

extern "C"
{
    static void init(Handle<Object> target)
    {
        HandleScope scope;
    }
}
NODE_MODULE(node_AsyncTest, init);

On the node side you call the module like this:

var foo = process.binding('AsyncTest');

foo.Test(1,2,function(err,data){
  console.log(err,data);
});

result:

undefined 3

Hope this is helpful ;)

Ps: Since the lack of node compiling extensions under windows. I´m building this directly into the core of the node windows port with the Visual Studio build solution.

like image 91
Alex Avatar answered Oct 05 '22 05:10

Alex