24

I'm currently developing a simulator that runs on a server and should display data in the browser.

For serving files, communication and things like that, I'd like to use Node.js. But, I'm not sure if it will perform as well as I'd want it to in the computation department, so I would like to develop the simulation part in C++.

The simulation is divided into separate "worlds", which all start with some initial parameters.

What is the best way to do this?

corazza
  • 31,222
  • 37
  • 115
  • 186
  • Perhaps the simplest way is to fork the C program from node.js and then have a callback collect its output. – Paul Sep 16 '12 at 14:08
  • Did you benchmark? just saying, V8 (the javascript engine behind node) can be pretty fast even for computationally expensive operations, IMHO you should check exactly how it performs before jumping to C/C++. – Mahn Sep 16 '12 at 14:09
  • Although it sounds more like you are thinking about what language you want to choose. In that case, I would recommend keeping everything in one language. Why use two languages if you can avoid it? – Paul Sep 16 '12 at 14:11
  • Well I just feel like I'm using a webserver framework for scientific research (plan to submit this to some competitions), somethong Node wasn't intended to be used for. – corazza Sep 16 '12 at 15:21
  • Yep, I've pretty much decided. I'll make the simulation engine as a standalone class in C++, and then have it ran by scripts, either Python or Node.js (probably Node.js). – corazza Sep 16 '12 at 20:56
  • Please all, see the clarification. – corazza Sep 16 '12 at 22:02

1 Answers1

47

Well, V8 allows for C++ code to be called from JavaScript.

So you can have 3 parts of your code:

  • Normal C++, unaware of node.js and V8. This would be where World is.
  • Glue node.js/V8-C++ code, allowing JS to "see" parts of your World class.
  • Normal JavaScript code, which communicates with the C++ side via the "glue" layer

First, understand how V8 and C++ communicate. Google provides a guide for this: https://developers.google.com/v8/embed

Then, you need node.js specific glue. See http://www.slideshare.net/nsm.nikhil/writing-native-bindings-to-nodejs-in-c and http://syskall.com/how-to-write-your-own-native-nodejs-extension

From the slideshare link above:

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

using namespace v8;

extern "C" {
   static void init(Handle<Object> target) {}
   NODE_MODULE(module_name, init)
}

We can expand that into something closer to what you want:

src/world.h

#ifndef WORLD_H_
#define WORLD_H_

class World {
    public:
        void update();
};

extern World MyWorld;

#endif

src/world.cpp

#include "world.h"
#include <iostream>

using std::cout;
using std::endl;

World MyWorld;

void World::update() {
    cout << "Updating World" << endl;
}

src/bind.cpp

#include <v8.h>
#include <node.h>
#include "world.h"

using namespace v8;

static Handle<Value> UpdateBinding(const Arguments& args) {
    HandleScope scope;

    MyWorld.update();

    return Undefined();
}

static Persistent<FunctionTemplate> updateFunction;

extern "C" {
   static void init(Handle<Object> obj) {
      v8::HandleScope scope;

        Local<FunctionTemplate> updateTemplate = FunctionTemplate::New(UpdateBinding);

        updateFunction = v8::Persistent<FunctionTemplate>::New(updateTemplate);

      obj->Set(String::NewSymbol("update"), updateFunction->GetFunction());
   }

   NODE_MODULE(world, init)
}

demo/demo.js

var world = require('../build/Release/world.node');
world.update();

wscript

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.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
  # This is the name of our extension.
  obj.target = "world"
  obj.source = "src/world.cpp src/bind.cpp"
  obj.uselib = []

On Linux shell, some setup:

node-waf configure

To build, run:

node-waf

To test:

node demo/demo.js

Output:

Updating World
luiscubal
  • 24,773
  • 9
  • 57
  • 83
  • @Bane Just remember that most node.js-related functions are based on callbacks. The way I wrote this, "update()" would be a blocking synchronous function, which may or may not be a problem for you. – luiscubal Sep 17 '12 at 14:51
  • +1 this is pretty cool, wasn't aware of these custom glue layers. – Mahn Sep 18 '12 at 00:07
  • An additional warning: This code was tested with a stable Node version, but the newest unstable versions will not work, because of significant changes in v8. – luiscubal Dec 21 '13 at 23:36
  • Is this still the best solution in 2016 and modern node (v6 and such)? It still looks relevant but checking just in case. – Majster Aug 02 '16 at 19:54
  • @Majster Not sure, but probably not because the unstable versions in 2013 was already different. – luiscubal Aug 19 '16 at 22:52