No.de coupon
Huzzah!
Got my no.de coupon in the mail a couple of days ago.
Now I just gotta figure out what I wanna host at http://sammeh.no.de/....
Creating a proper Buffer in a Node C++ Addon
Despite the wordy title, it's actually a fairly simple problem, with a fairly simple solution.
Let's say you have some binary data you want to provide to Node Javascript. No problem, Node has Buffers for that. Digging through the Node.js source code, you find node_buffer.h, which promises a utopia of an ObjectWrap goodness; you can even memcpy your binary data directly to it using Buffer::Data(bufferObject).
"Fantastic! I'll rock one of those buffers and simply return `bufferObject->handle_`!", I hear you exclaim. Not so fast stud.
If the client were to use this Buffer, they'd get a nasty surprise. It's not a Buffer. You see, Node.js has re-implemented Buffers since 0.2. The Buffer you're playing with from node_buffer.h is actually a SlowBuffer. As the name implies, it's working directly on the heap-allocated memory chunk, so alot of operations on it are quite inefficient. Worse still, the interface provided on SlowBuffer is actually different to the Node.js documentation. Allow me to explain.
The Buffer you're used to dealing with from Node.js user code actually originates from buffer.js. These Buffers are actually just "views" on a proper SlowBuffer, so operations like slicing are literally as quick as allocating a new Buffer object that views the SlowBuffer at a different offset and max length.
So how do you create one of these badboys from C++ to pass directly back to JS calling code? Glad you asked. Like so:
// Some data we want to provide to Node.js userland code.
// This can be binary of course.
const char *data = "Hello world!";
int length = strlen(data);
// This is Buffer that actually makes heap-allocated raw binary available
// to userland code.
node::Buffer *slowBuffer = node::Buffer::New(length);
// Buffer:Data gives us a yummy void* pointer to play with to our hearts
// content.
memcpy(node::Buffer::Data(slowBuffer), data, length);
// Now we need to create the JS version of the Buffer I was telling you about.
// To do that we need to actually pull it from the execution context.
// First step is to get a handle to the global object.
v8::Local<v8::Object> globalObj = v8::Context::GetCurrent()->Global();
// Now we need to grab the Buffer constructor function.
v8::Local<v8::Function> bufferConstructor = v8::Local<v8::Function>::Cast(globalObj->Get(v8::String::New("Buffer")));
// Great. We can use this constructor function to allocate new Buffers.
// Let's do that now. First we need to provide the correct arguments.
// First argument is the JS object Handle for the SlowBuffer.
// Second arg is the length of the SlowBuffer.
// Third arg is the offset in the SlowBuffer we want the .. "Fast"Buffer to start at.
v8::Handle<v8::Value> constructorArgs[3] = { slowBuffer->handle_, v8::Integer::New(length), v8::Integer::New(0) };
// Now we have our constructor, and our constructor args. Let's create the
// damn Buffer already!
v8::Local<v8::Object> actualBuffer = bufferConstructor->NewInstance(3, constructorArgs);
// This Buffer can now be provided to the calling JS code as easy as this:
return scope.Close(actualBuffer);
And that's all folks!
Node.js
Since I haven't updated my blog for a few months I figure now would be a good time to do a bit of a brain dump on what is interesting to me nowadays.
Currently I'm completely immersed in the weird and wondrous world of Node.js. If you are even remotely interested in anything related to web development/engineering, you should already know about Node. Briefly, it's a server side JavaScript (SSJS) implementation built on top of Google's V8 JavaScript engine. It's blisteringly fast, and has already been employed in some big projects to solve some pretty insane scaling problems engineers are facing in large websites.
Currently I'm just getting myself acquainted with Node.js, I've written some random libs that are on my Github. Currently I'm writing a native Node extension called node-gitteh, which provides bindings to the excellent C library libgit2. I'll be using these bindings to manipulate Git repositories from Node as part of a little project I'm going to undertake (more on that later).
Writing these bindings has been interesting, given that I'm writing C++ code for the first time in years, and having more trouble remembering how to use an STL map<> than I am wrangling the bizarro V8 API. I think this definitely warrants a tip of the hat to Google, the internals of V8 are pretty accessible; my only gripe with V8 is a pretty painful lack of hand-holding documentation, however there were plenty of examples of stuff on Github from other kindred Node spirits who've written bindings for things like GD, Mysql, libxml2 and the like.
The thing that has impressed me about Node the most is the amount of talent the community is comprised of. Node is only just over a year old and there is already a mass of quality libraries and frameworks. One I particularly love is Vows, which has made TDD an absolute breeze in Node. If you're just starting out with Node, I thoroughly recommend you get into the habit of using Vows to test your code, ideally writing the tests before you even launch into your next Javascripty wet dream. Seriously, it's worth it.
Of course, Node is not without it's faults. The biggest one currently is lack of threaded-ness, or any kind of concurrency control from JavaScript. Many will argue this is a Good Thing, as it abstracts away the misery that is semaphores, locks, re-entrancy and other goodies that come with thread-safety. However I still think there should be first-class support for concurrent operations in Node user land (read: JavaScript code).
There are some solutions out there that utilize nodes ability to spawn child processes and communicate/control them effectively, to the effect of running a pool of Node processes. However I view these as a kludge, as Node processes do have a pretty decent memory footprint on initialization. Given that Chrome has a way of running completely sandboxes JavaScript execution contexts in parallel (that is, a blocking script in one frame wouldn't block other frames), I'm sure there's an elegant solution to be found.
That's all for now!
