Node-addon-api: Nodejs addon- napi_call_function usage example

Created on 22 Feb 2020  路  8Comments  路  Source: nodejs/node-addon-api

let's assume the following function

napi_value GeoToSeqnum(napi_env env, const napi_callback_info info) {
  napi_status status;
  size_t argc = 1;
  napi_value argv[1];



  status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
  assert(status == napi_ok);

  napi_value cb = argv[2];



    // if (!argv[0].IsNumber() || !argv[1].IsNumber() ){
    //       napi_throw_error(env,0, "Number expected");
    // } 



    uint64_t out_seqnum=10;

  napi_value seqnum[1];
  status = napi_create_int64(env,out_seqnum,  &seqnum);
  assert(status == napi_ok);

  napi_value global;
  status = napi_get_global(env, &global);
  assert(status == napi_ok);

  napi_value result;
  status = napi_call_function(env, global, cb, 1, seqnum, &result);
  assert(status == napi_ok);

  return nullptr;
}

this function returns the following result

var addon = require('bindings')('dggridjs');
// const myaddon = require('./addon');
console.log(addon);
addon.GeoToSeqnum(0,0,function(seqnumber){
  console.log(seqnumber[0]); // must return 10
});

> type sizes: big int: 64 bits / big double: 64 bits

I have two problems, first of all, if I add the following part to the code it can not compile. I want to know how I can check the input type

  if (!argv[0].IsNumber() || !argv[1].IsNumber() ){
          napi_throw_error(env,0, "Number expected");
    } 
==> compile error :error C2228: left of '.IsNumber' must have class/struct/union 

and my second problem is with the output. It seems it is returning output type, which is correct but I need it to return the number. I am confused about using napi functions here.
I'd appreciate your help.
Thanks

stale

All 8 comments

Hi @am2222,
if you want check the type of a value you need to use napi_typeof function.
If you use node-addon-api your code should be something like reported below:

binding.cc

#include <napi.h>

void GeoToSeqnum(const Napi::CallbackInfo& info) {
    if (!info[0].IsNumber() || !info[1].IsNumber()) {
        throw Napi::Error::New(env, "Number expected");
    }
    Napi::Function fn = info[2].As<Napi::Function>();
    uint64_t out_seqnum = 10;
    fn.Call({ Napi::Number::New(env, out_seqnum) }); 
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports["GeoToSeqnum"] = Napi::Function(env, GeoToSeqnum);
}

NODE_API_MODULE(dggridjs, Init)

index.js

var addon = require('bindings')('dggridjs');
// const myaddon = require('./addon');
console.log(addon);
addon.GeoToSeqnum(0,0,function(seqnumber){
  console.log(seqnumber[0]); // must return 10
});

node-addon-api is a only header C++ wrapper for N-API. node-addon-api is distributed as module through npm and to use it you have to follow the setup instruction.

N-API is exported like C API directly from the core of Node.js and you can use it directly and I think that the following example could help to solve your problem.
I hope that this could help you.

@NickNaso thanks for your help, which option do you suggest?
I think I am currently using using N-API but your solution is using nod-addon-api.

Hi @am2222,
you are using C API. In the following example I report the usage of N-API:

#include <assert.h>
#include <node_api.h>

napi_value GeoToSeqnum(napi_env env, const napi_callback_info info) {
  napi_status status;

  size_t argc = 3;
  napi_value args[3];
  status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
  assert(status == napi_ok);

  napi_valuetype type_1st_arg;
  napi_valuetype type_2nd_arg;

  status =  napi_typeof(env, args[0], &type_1st_arg);
  assert(status == napi_ok);

  status =  napi_typeof(env, args[1], &type_2nd_arg);
  assert(status == napi_ok);

  if (type_1st_arg != napi_number || type_2nd_arg != napi_number) {
     napi_throw_type_error(env, "TYPE_ERROR", "Number expected.");
  }
  napi_value cb = args[2];


  uint64_t out_seqnum = 10;
  napi_value argv[1];
  status = napi_create_int64(env, out_seqnum, &argv[0]);
  assert(status == napi_ok);

  napi_value global;
  status = napi_get_global(env, &global);
  assert(status == napi_ok);

  napi_value result;
  status = napi_call_function(env, global, cb, 1, argv, &result);
  assert(status == napi_ok);

  return nullptr;
}

#define DECLARE_NAPI_METHOD(name, func)                                        \
  { name, 0, func, 0, 0, 0, napi_default, 0 }

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_property_descriptor desc = DECLARE_NAPI_METHOD("GeoToSeqnum", GeoToSeqnum);
  status = napi_define_properties(env, exports, 1, &desc);
  assert(status == napi_ok);
  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
const addon = require('bindings')('dggridjs');

addon.GeoToSeqnum(0,0,function(seqnumber){
  console.log(seqnumber); // must return 10
});

Here you can download the example
cb.zip

If you use node-addon-api with C++ your code will be less verbose. Let me know if I can help in some other way.

@NickNaso Thanks for your help, I managed to make it work but there is an strange problem
when I install my package using npm install it crashes while calling a function and when I use node-gyp -j 16 build --debug command my code works fine. I think there is some memory leak somewhere but can not figure out its solution.
can you give me some hints how I can fix it?
here is the package's repository in case it helps
https://github.com/am2222/dggridjs

On linux you can use valgrind to debug memory issues: See https://github.com/nodejs/node/blob/master/doc/guides/investigating_native_memory_leak.md

Hi @am2222,
I took a look at your code and what I understood is that you are exposing to functions:

  • GeoToSeqnum
  • DGGSConstruct
    You are using DGGSConstruct to initialise some native object that maybe you want to reuse on the GeoToSeqnum. Is it right? If yes the most appropriate choice to do is to use the ObjectWrap API. Could you explain the JavaScript API that you want create maybe I can help you in a better way.

@NickNaso Hello,
Thanks for your help, In fact I am trying to call the functions from this class (https://github.com/am2222/dggridjs/blob/master/src/dglib.cpp)
in general this library is a library to make discrate global grid system. each DGGS has a set of parameters that we can define them at beginning and then using that object we can convert different type of indexes. in this example GeoToSeqnum converts a geometry (lat,long) to a big integer value.
I have implicated similar functions in a python wrapper which shows how those functions can be implemented.
https://github.com/am2222/pydggrid/blob/master/src/main.cpp

in general we have three main objects a dgparam which defines the settings, Transformer object which is the main object and a set of functions which transformer have.

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rivertam picture rivertam  路  9Comments

mhdawson picture mhdawson  路  4Comments

alexisfrjp picture alexisfrjp  路  6Comments

sziraqui picture sziraqui  路  5Comments

D-Andreev picture D-Andreev  路  6Comments