www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - nodejs extension in D (with some help from C++)

Hi

Just wanted to share how I have managed to interface node.js with 
D using C++ bridge and NAN. So far I have been using C++ and rust 
for this but for obvious reasons (that would be a long story to 
explain) I wanted to go with D. One of the show stoppers was the 
lack of well established (or I don't know if that exists) library 
of framework to help with that.

Anyway I have managed to do this using information gathered from 
various places and I wanted to share if anyone runs into the same 
issue.

First I created a d lib using dub.

Simple code for the library:

import std.string;

extern (C++) immutable(char)* D_func(const char *s) {
         import std.string;
         return toStringz(fromStringz(s) ~ "-response");
}

Code for the c++ file which is the interface to the node.js


#include <nan.h>

char *D_func(const char *);
extern "C" int rt_init();
extern "C" int rt_term();

// NAN_METHOD is a Nan macro enabling convenient way of creating 
native node functions.
// It takes a method's name as a param. By C++ convention, I used 
the Capital cased name.
NAN_METHOD(Hello) {

     // send this to D code
     const char *s = "request";
     // Initialize the D runtime
     rt_init();
     // Create an instance of V8's String type
     auto message = Nan::New(D_func(s)).ToLocalChecked();
     // Shut down D
     rt_term();
     // 'info' is a macro's "implicit" parameter - it's a bridge 
object between C++ and JavaScript runtimes
     // You would use info to both extract the parameters passed 
to a function as well as set the return value.
     info.GetReturnValue().Set(message);
}

// Module initialization logic
NAN_MODULE_INIT(Initialize) {
     // Export the `Hello` function (equivalent to `export 
function Hello (...)` in JS)
     NAN_EXPORT(target, Hello);
}

// Create the module called "addon" and initialize it with 
`Initialize` function (created with NAN_MODULE_INIT macro)
NODE_MODULE(addon, Initialize);

finally the binding.gyp that links the whole thing together and 
builds the Node.js extension.

the binding.gyp

{
   "targets": [
     {
       "include_dirs": [
         "<!(node -e \"require('nan')\")"
       ],
       "target_name": "addon",
       "sources": [ "main.cpp" ],
       "libraries": [ "-L/path/to/dlang_library", 
"-ldlang_library",
                      "-L/path/to/phobos/library", "-lphobos2" ]
     }
   ]
}

and the package.json
```
{
   "name": "call_d_from_nodejs",
   "version": "1.0.0",
   "description": "",
   "main": "index.js",
   "scripts": {
     "compile": "node-gyp rebuild",
     "start": "node main.js",
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
   "dependencies": {
     "nan": "^2.8.0",
     "node-gyp": "^3.6.2"
   }
}
```

enjoy, any questions let me know. :)
Jan 05