Search code examples
c++node.jsfunctionadd-onnode.js-addon

C++ add-on for NodeJS nested functions not being called


I am writing a c++ NodeJs native add-on using the v8 that implements a minimax tic-tac-toe AI.

I have a problem where nested functions are not working.

Here is my code:

namespace Game {
    Move bestMove(...) {
        // implementation
    }
}
namespace addon {
    using namespace v8;
    using std::vector;
    ...

    // this function returns the best move back to nodejs
    void bestMove(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        ...

        auto returnVal = Game::bestMove(params); // Game::bestMove() returns the best move for the computer

        args.GetReturnValue().Set((returnVal.row * 3) + returnVal.col); // returns the move back to nodejs
}

Normally, if the game board is this (computer is o):

    x _ _
    _ _ _
    _ _ _

The function shouldn't return 0 because it is already taken by x. However it seems to always return 0.

After I investigated a bit, I realized that the function Game::bestMove() never gets called.

Add yes, I know this is the problem because after I added std::cout << "Computing"; in the function Move bestMove(), it never got printed to the console.

However, if I add std::cout << "Computing"; in the function addon::bestMove(), it works.

There is also no compile time error thrown.

Thanks for any help.


Solution

  • This answer is only helpful if you're willing to move to using N-API via the C++ bindings, node-addon-api (available via npm). You're using C++ so it is probably the cleanest way to make the coding more straightforward and likely to work. Net, I can't tell you what is wrong with your code from what's posted, so if that's showstopper then no need to read on.

    With node-addon-api your addon would look something like:

    #include <napi.h>
    
    // your move function
    Napi::Value bestMove(const Napi::CallbackInfo& info) {
      Napi::Env env = info.Env();
    
      int move = Game::bestMove(params);
    
      // just return the number and the C++ inline wrappers handle
      // the details
      return Napi::Number::New(env, move);
    }
    
    // the module init function used in the NODE_API_MODULES macro below
    Napi::Object Init(Napi::Env env, Napi::Object exports) {
      Napi::HandleScope scope(env);
    
      // expose the bestMove function on the exports object.
      exports.Set("bestMove", Napi::Function::New(env, bestMove));
    
      return exports;
    }
    
    NODE_API_MODULES(my_game, Init)
    

    In JavaScript you'd just require the bindings file, typically in build/Release/my_game.node (or use the bindings package so you can just require('my_game')). So

    const game = require('my_game')
    ...
    
    move = game.bestMove()
    

    I don't know enough details to flesh out the example any better.

    I worked with Nan before the node-addon-api package and found it frustrating. I didn't try using V8 directly because it ties my application to a specific version of node.

    If you're interested in more details check out https://github.com/nodejs/node-addon-api. It really quite well done.

    Apologies if any of the code above has errors; I just made it up as I went.