@polotek (twitter, github, irc, etc.)
*Typical results do not include fun or profit
required (this is important)C library for encrypting data with blowfish.
char* bcrypt_gensalt(u_int8_t log_rounds);
char* bcrypt(const char* password, const char* salt);
Code samples here https://github.com/polotek/node_addons_examples (forthcoming)
// our API
var BCrypt = require('bcrypt').BCrypt;
var salt = '$2a$12$L/QwZlqLTII.Qx/p9kLt5.';
var encrypter = new BCrypt();
console.log( encrypter.encrypt('passw0rd', salt) );
// js
function encrypt() {
this; // could be anything
var arg1 = "loser";
if(arguments.length == 1)
args[0];
return "Hello, " + arg1;
}
// C++
Handle<Value> BCrypt::Encrypt(const Arguments& args) {
args.This(); // of type Handle<Value>
Handle<String> args1;
if(args.Length() == 1) {
args1 = args[0]->ToString();
} else {
args1 = String::New("loser");
}
return String::Concat( String::New("Hello, "), args1 );
}
Each reference to a js value in C/C++ is through a Handle. You need to "unwrap" Handles to get at the data types inside them.
A HandleScope is a temporary construct that keeps track of Handles and cleans them up when the stack pops off.
Always use a HandleScope at the beginning of your function.
Local Handle - Cleaned up by scope after the function exits. Default handle type.
Persistent Handle - These allow you to keep objects around for as long as you need them.
Probably the most important gotcha. Close the scope whenever you return a Handle from a function. Otherwise, the HandleScope will take it right out from under you.
+HandleScope scope;
return v8::Array::New();
+return scope.Close(v8::Array::New());
Remember even innocent looking "literals" are actually Handles! Lots of commits that look like this.
class BCrypt : public node::ObjectWrap {
Handle<Value> BCrypt::Encrypt(const Arguments& args) {
HandleScope scope;
// retrieve your object from "this".
BCrypt *bcrypt_obj = ObjectWrap::Unwrap<BCrypt>(args.This());
// C/C++
class Connection : public node::EventEmitter {
...
v8::Handle<v8::String> close = NODE_PSYMBOL("close");
Emit(close_symbol, 0, NULL);
// js
var conn = new Connection();
conn.on('close', function() { ... });
Check out node/src/node.h for some nice macros and helper functions.
Kind of punting on this even though it's an important topic.
Node uses libeio to turn blocking file operations into non-blocking ones. It also has an API for doing this with any custom call. Push blocking library calls to a background thread. Isaac Schlueter has provided a simple example, node-async-simple. Complete but not comprehensive. Find out how you need to adapt this to your use case.
Don't try to access v8 from another thread. Unwrap everything to C/C++ types and only deal with those.
node-waf comes with node.This process isn't fun. So...
Just find a good one and learn from that. #winning
* libxmljs uses scons. Similar idea, another dependency. Not worth it.
# wscript
srcdir = "."
blddir = "build"
def set_options(opt):
opt.tool_options("compiler_cxx")
opt.tool_options("compiler_cc")
def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("compiler_cc")
conf.check_tool("node_addon")
def build(bld):
bcryptnode = bld.new_task_gen("cxx", "shlib", "node_addon")
bcryptnode.target = "bcrypt_lib"
bcryptnode.source = "src/blowfish.cc src/bcrypt.cc src/bcrypt_node.cc"
$> node --expose_gc addon_test.js
// addon_test.js
var libxmljs = require('libxmljs');
var doc = libxmljs.parseXmlString('<pass><test/></pass>');
console.log(doc.root().name()); // "pass" yay!
// force GC, I hope nothing bad happened
gc();
console.log(doc.root().name()); // Segfaults, destruction and death
Use tools to ensure quality
node_g with instrumenting tools so they can find the actual names of classes and functionsSomeone write some blog posts about these
$> npm help scripts
// package.json
{
"name": "bcrypt",
...
"scripts": {
"install": "node-waf configure build",
"test": "node-waf configure build && nodeunit test/"
},
Is using make more future-proof or just another dependency?
// package.json
{
"name": "libxmljs",
...
"scripts" :
{ "preinstall" : "make node",
"test" : "make test"
}
# MakeFile
node:
node-waf configure build