Skip to content

Commit

Permalink
Add async callback example
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhilm committed Jan 20, 2012
1 parent 425d326 commit 9d226b2
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 0 deletions.
146 changes: 146 additions & 0 deletions async/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#include <unistd.h>
#include <v8.h>
#include <node.h>
#include <node_object_wrap.h>
using namespace v8;
using namespace node;

namespace Library {
class Inventory {
public:
Inventory() : items(0) {}

void addStock(int n) {
items += n;
}

int ship(int orders) {
if (orders > items)
return -1;

items -= orders;
return 0;
}

int getItems() {
return items;
}

void reshelve() {
sleep(5);
}

private:
int items;
};
}

namespace binding {

class Inventory;
struct ReshelveBaton {
uv_work_t request;
Persistent<Function> callback;
Inventory *wrapper;
// any other data that has to be sent to the callback
// or for async processing.
};

class Inventory : public ObjectWrap {
public:
Inventory() : ObjectWrap()
, inv(new Library::Inventory()) {};

~Inventory() { delete inv; }

static Handle<Value> New(const Arguments &args) {
Inventory *wrapper = new Inventory();
wrapper->Wrap(args.Holder());
return args.Holder();
}

static Handle<Value> AddStock(const Arguments &args) {
Inventory *wrapper = Unwrap<Inventory>(args.Holder());
int n = args[0]->Uint32Value();

wrapper->inv->addStock(n);
return Undefined();
}

static Handle<Value> Ship(const Arguments &args) {
Inventory *wrapper = Unwrap<Inventory>(args.Holder());
int orders = args[0]->Uint32Value();
int result = wrapper->inv->ship(orders);

if (result == -1)
return ThrowException(String::New("Not enough items"));

return Undefined();
}

static Handle<Value> GetItems(Local<String> property, const AccessorInfo &info) {
Inventory *wrapper = Unwrap<Inventory>(info.Holder());
return Integer::New(wrapper->inv->getItems());
}

static Handle<Value> Reshelve(const Arguments &args) {
Inventory *wrapper = Unwrap<Inventory>(args.Holder());

Handle<Function> cb = Handle<Function>::Cast(args[0]);

ReshelveBaton *baton = new ReshelveBaton();
baton->request.data = baton;
baton->callback = Persistent<Function>::New(cb);
baton->wrapper = wrapper;

uv_queue_work(Loop(), &baton->request, ReshelveAsync, ReshelveAsyncAfter);

return Undefined();
}

static void ReshelveAsync(uv_work_t *req) {
// This runs in a separate thread
// NO V8 interaction should be done
ReshelveBaton *baton = static_cast<ReshelveBaton*>(req->data);
// if you want to modify baton values
// do synchronous work here
baton->wrapper->inv->reshelve();
}

static void ReshelveAsyncAfter(uv_work_t *req) {
ReshelveBaton *baton = static_cast<ReshelveBaton*>(req->data);
Handle<Value> argv[] = { Null() }; // no error
baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);

baton->callback.Dispose();
delete baton;
}

private:
Library::Inventory *inv;
};

extern "C" {
static void Init(Handle<Object> target) {
HandleScope scope;

Handle<FunctionTemplate> inventoryTpl =
FunctionTemplate::New(Inventory::New);

Handle<ObjectTemplate> instance =
inventoryTpl->InstanceTemplate();

instance->SetInternalFieldCount(1);

instance->SetAccessor(String::New("items"), Inventory::GetItems);

NODE_SET_PROTOTYPE_METHOD(inventoryTpl, "addStock", Inventory::AddStock);
NODE_SET_PROTOTYPE_METHOD(inventoryTpl, "ship", Inventory::Ship);
NODE_SET_PROTOTYPE_METHOD(inventoryTpl, "reshelve", Inventory::Reshelve);

target->Set(String::NewSymbol("Inventory"),
inventoryTpl->GetFunction());
}
NODE_MODULE(async, Init)
}
}
10 changes: 10 additions & 0 deletions async/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var inv = new (require('./build/Release/async')).Inventory()

inv.reshelve(function() {
console.log("Reshelving done");
})
console.log("After reshelve in source");
for (var i = 1; i < 5; i++)
setTimeout(function() {
console.log("Tick");
}, i*1000);
13 changes: 13 additions & 0 deletions async/wscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Options

def set_options(opt):
opt.tool_options("compiler_cxx")

def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("node_addon")

def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.target = "async"
obj.source = "main.cc"

0 comments on commit 9d226b2

Please sign in to comment.