NodeJS Addon calling Javascript callback from inside NAN AsyncWorker::Execute - c++

I would like to call a nodejs callback from within my asynchronous addon function. I have seen the synchronous example (here)
and I am using a wonderful asynchronous example (here) as a starting base.
However, when I try to execute a callback that was given to the c++ AsyncWorker child class, I get a Segmentation fault.
Here is my code:
#include <nan.h>
#include <functional>
#include <iostream>
#include <exception>
using namespace Nan;
using namespace v8;
using namespace std;
class ScriptWorker : public AsyncWorker {
public:
ScriptWorker(Callback *callback, const std::map<std::string, Callback*>)
: AsyncWorker(callback), script(script), cbs(cbs) {}
~ScriptWorker() {}
void Execute () {
// ------------------------
// Segmentation fault after
// ------------------------
Local<Value> argv[] = {
New<v8::Number>(id)
};
// -------------------------
// Segmentation fault before
// -------------------------
cbs["getUser"]->Call(1, argv);
}
private:
std::string script;
std::map<std::string, Callback*> cbs;
};
NAN_METHOD(Method) {
Local<Object> array = info[0]->ToObject();
Callback *callback = new Callback(info[1].As<Function>());
// Build up callbacks passed in from javascript.
// Will be a dynamic loop, but for now, hard code the one getUser example.
std::map<std::string, Callback*> cbs;
cbs.insert(std::pair<std::string, Callback*>("getUser",
new Callback(
array->Get(
v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), "getUser")
).As<Function>()
)
));
AsyncQueueWorker(new ScriptWorker(callback, cbs));
}
NAN_MODULE_INIT(Init) {
Nan::Set(target, Nan::New<String>("hello").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(Method)).ToLocalChecked());
}
NODE_MODULE(hello, Init)
My questions:
Should I not use Nan's AsyncWorker and instead roll my own?
How do I setup the Execute function to call into Javascript?

EDIT:
See this repo:
https://github.com/xavero/node_addon_sample
it has a sample on how to work with callback functions and emitting events from C land.
You should not call v8/Nan functions in your Execute method of ScriptWorker, or you will get segment faults. Override the HandleOKCallback function to use the javascript callback.
To call from the javascript, in your c++ addon:
NAN_MODULE_INIT(Init) {
Nan::Set(target, Nan::New("myJsFunctionName").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(Method)).ToLocalChecked());
}
NODE_MODULE(anyNameHere, Init)
And in your javascript:
// run "npm install bindings --save" in console first
var addon = require('bindings')('NativeExtension');
addon.myJsFunctionName({ foo: "bar"}, (arg1,arg2) => console.log(`${arg1} - ${arg2}`))

Related

GetLastInputInfo fails in node addon

My goal is to make a module which provides access to the last time of user interaction (Client side app - not a server app). The Windows API has a function called GetLastInputInfo (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646302(v=vs.85).aspx). Below is the code which should load the time information into last_input and it returns 0/1 for failure/success. Unfortunately, it fails every time.
Addon code:
#include <node.h>
#include <v8.h>
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
using namespace v8;
Handle<Value> TimeSinceInput(const Arguments& args) {
HandleScope scope;
LASTINPUTINFO last_input;
if (::GetLastInputInfo(&last_input)) {
return scope.Close(String::New("Success!"));
}
else {
return scope.Close(String::New("Failed for some reason!"));
}
}
void init(Handle<Object> exports) {
exports->Set(String::NewSymbol("time_since_input"), FunctionTemplate::New(TimeSinceInput)->GetFunction());
}
NODE_MODULE(addon, init)
Any thoughts?
LASTINPUTINFO structure has member cbSize, that should be initialized:
The size of the structure, in bytes. This member must be set to sizeof(LASTINPUTINFO).
It's a common way for versioning in Windows API.

Can't access V8 Context in "callback" function

I am writing a NodeJS addon where I use a C library that lets you register a callback at certain events. When the callback is fired I want to call a NodeJS callback function. The problem is that in my C callback function I get a segmentation fault when trying to do anything V8 related, like creating a HandleScope.
In test.js:
...
myaddon.register(function(data) {
console.log("data: " + JSON.stringify(data));
});
...
In test.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <node.h>
#include <v8.h>
using namespace v8;
void WINAPI myEvent(int num, void * context) {
HandleScope scope; // Segmentation fault here!
Local<Function> * cb = (Local<Function>*)(context);
Local<Object> obj = Object::New();
obj->Set(String::NewSymbol("id"), Number::New(num));
const int argc = 1;
Local<Value> argv[argc] = { obj };
(*cb)->Call(Context::GetCurrent()->Global(), argc, argv);
sleep(1);
}
Handle<Value> RegisterEvent(const Arguments& args) {
HandleScope scope;
Local<Function> cb = Local<Function>::Cast(args[0]);
int callbackId = registerEvent((Event)&myEvent, &cb );
printf("callback id: %i\n", callbackId);
init();
return scope.Close(Integer::New(callbackId));
}
void init(Handle<Object> exports) {
exports->Set(String::NewSymbol("register"),
FunctionTemplate::New(RegisterEvent)->GetFunction());
}
NODE_MODULE(test, init)
EDIT: Updated with real code.
EDIT: I just changed the title of this issue since the problem is probably that my callback function can't access the V8 Context. Since I get a segmentation fault when creating HandleScope instance I can't see what else it might be. In addition to this question I AM trying to find the answer in the V8 documentation, but it is huge and I don't have that much time to test and investigate.
Your handler function myEvent() must be called in V8 thread. If not, you have to post the event notification into the V8 thread:
https://stackoverflow.com/a/15701160/1355844
https://stackoverflow.com/a/22946062/1355844
It appears that you might have forgotten to create a HandleScope for your variable. This should work for you.
void callbackFunc() {
HandleScope scope;
Local<Object> obj = Object::New();
}

Boost.Python 'too few template arguments to class_'

I've written part of a class in C++ and I want to be able to use it in conjunction with a Python GUI, so I'm using Boost.Python to try and make it easy. The issue I'm running into is that in following their guide (http://www.boost.org/doc/libs/1_55_0/libs/python/doc/tutorial/doc/html/python/exposing.html), I keep getting the following exception whenever I run bjam:
PacketWarrior/pcap_ext.cc:21:5: error: too few template arguments for class template 'class_'
Obviously it's complaining at me for omitting what they claim are optional arguments to the 'class_' template function, but I can't figure out why. I'm assuming it's a compiler issue but I don't know how to fix it. I'm running OS X 10.9 and using darwin for the default toolset, but GCC throws the same error. My Boost version is 1_55_0 if that helps at all.
Class header file (header guards omitted):
#include <queue>
#include "pcap.h"
#include "Packet.h"
class PacketEngine {
public:
PacketEngine();
~PacketEngine();
const char** getAvailableDevices(char *error_buf);
bool selectDevice(const char* dev);
Packet getNextPacket();
private:
char *selected_device;
char **devices;
int num_devices;
std::queue<Packet> packet_queue;
};
The cc file containing the references to Boost.Python and my class:
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include "PacketEngine.h"
BOOST_PYTHON_MODULE(pcap_ext) {
using namespace boost::python;
class_<PacketEngine>("PacketEngine")
.def("getAvailableDevices", &PacketEngine::getAvailableDevices);
}
And my bjam file (irrelevant parts and comments omitted):
use-project boost : ../../../Downloads/boost_1_55_0 ;
project
: requirements <library>/boost/python//boost_python
<implicit-dependency>/boost//headers
: usage-requirements <implicit-dependency>/boost//headers
;
python-extension pcap_ext : PacketWarrior/pcap_ext.cc ;
install convenient_copy
: pcap_ext
: <install-dependencies>on <install-type>SHARED_LIB <install-type>PYTHON_EXTENSION
<location>.
;
local rule run-test ( test-name : sources + )
{
import testing ;
testing.make-test run-pyd : $(sources) : : $(test-name) ;
}
run-test pcap : pcap_ext pcap.py ;
Any ideas as to how to circumvent this exception are greatly appreciated! I looked into the obvious route of just adding the optional parameters but I don't think they're relevant to my project. The class_ definition can be found here:
http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/class.html
In short, include either:
boost/python.hpp: The Boost.Python convenient header file.
boost/python/class.hpp: The header that defines boost::python::class_.
The current included header files are declaring class_ with no default template arguments from def_visitor.hpp.
Also, trying to directly expose PacketEngine::getAvailableDevices() will likely present a problem:
It accepts a char* argument, but strings are immutable in Python.
There are no types that automatically convert to/from a const char** in Boost.Python.
It may be reasonable for a Python user to expect PacketEngine.getAvailableDevices() to return an iterable type containing Python strs, or throw an exception on error. This can be accomplished in a non-intrusive manner by writing a helper or auxiliary function that delegates to original function, but is exposed to Python as PacketEngine.getAvailableDevices().
Here is a complete example based on the original code:
#include <exception> // std::runtime_error
#include <boost/python.hpp>
namespace {
const char* devices_str[] = {
"device A",
"device B",
"device C",
NULL
};
} // namespace
class PacketEngine
{
public:
PacketEngine() : devices(devices_str) {}
const char** getAvailableDevices(char *error_buf)
{
// Mockup example to force an error on second call.
static bool do_error = false;
if (do_error)
{
strcpy(error_buf, "engine not responding");
}
do_error = true;
return devices;
}
private:
const char **devices;
};
/// #brief Auxiliary function for PacketEngine::getAvailableDevices that
/// provides a more Pythonic API. The original function accepts a
/// char* and returns a const char**. Both of these types are
/// difficult to use within Boost.Python, as strings are immutable
/// in Python, and Boost.Python is focused to providing
/// interoperability to C++, so the const char** type has no direct
/// support.
boost::python::list PacketEngine_getAvailableDevices(PacketEngine& self)
{
// Get device list and error from PacketEngine.
char error_buffer[256] = { 0 };
const char** devices = self.getAvailableDevices(error_buffer);
// On error, throw an exception. Boost.Python will catch it and
// convert it to a Python's exceptions.RuntimeError.
if (error_buffer[0])
{
throw std::runtime_error(error_buffer);
}
// Convert the c-string array to a list of Python strings.
namespace python = boost::python;
python::list device_list;
for (unsigned int i = 0; devices[i]; ++i)
{
const char* device = devices[i];
device_list.append(python::str(device, strlen(device)));
}
return device_list;
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<PacketEngine>("PacketEngine")
.def("getAvailableDevices", &PacketEngine_getAvailableDevices);
}
Interactive usage:
>>> import example
>>> engine = example.PacketEngine()
>>> for device in engine.getAvailableDevices():
... print device
...
device A
device B
device C
>>> devices = engine.getAvailableDevices()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: engine not responding

Use LuaBind to call Lua functions inside a class when Lua is bound inside THAT class

Basically, I just want to be able to have a clean Lua instance made inside of my Manager class, then export the functions in the class to Lua, so that I can call functions on the already created C++ class inside of Lua.
This is the current way I am looking at solving the issue. It compiles but nothing happens in Lua.
Does anyone know what I am doing wrong, or does anyone have any other suggestions?
Manager.lua
newObject("Object", 1234)
printAll()
Manager.h
#ifndef MANAGER_H
#define MANAGER_H
#include <iostream>
#include <vector>
#include <string>
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "luabind/luabind.hpp"
#include "Object.h"
class Manager
{
private :
lua_State *L;
std::vector<Object> obj;
public :
Manager();
void newObject(std::string t, int nm);
void printAll();
};
#endif
Manager.cpp
#include "Manager.h"
Manager::Manager()
{
luabind::open(L);
luabind::module(L) [
luabind::class_<Manager>("Manager")
.def(luabind::constructor<>())
.def("newObject", &Manager::newObject)
];
luaL_dofile(L, "Manager.lua");
}
void Manager::newObject(std::string t, int nm)
{
if(t == "Object")
{
Object object(nm);
obj.push_back(object);
}
}
void Manager::printAll()
{
for(unsigned int i = 0; i < obj.size(); i++)
std::cout << obj[i].getNum() << std::endl;
}
so that I can call functions on the already created C++ class inside of Lua.
If you use Luabind to create a class, and then provide members of that class, then Luabind will do exactly that. It will expose a class to Lua that has members.
You cannot call a member function in C++ without an object of that class's type. And therefore, when you expose a class and its members through Luabind, you will not be able to call member functions in Lua without an object of that class's type.
Therefore, if you have some global Manager object, the proper way to expose this to Lua is to expose the object itself to Lua. Use Luabind to get the global table, then put a pointer to your Manager object in it. Alternatively, you can pass the Manager object instance as a parameter when you execute the script.
The second method would work something like this:
//Load the script as a Lua chunk.
//This pushes the chunk onto the Lua stack as a function.
int errCode = luaL_loadfile(L, "Manager.lua");
//Check for errors.
//Get the function from the top of the stack as a Luabind object.
luabind::object compiledScript(luabind::from_stack(L, -1));
//Call the function through Luabind, passing the manager as the parameter.
luabind::call_function<void>(compiledScript, this);
//The function is still on the stack from the load call. Pop it.
lua_pop(L, 1);
Your Lua script can get an instance with Lua's varargs mechanism:
local manager = ...
manager:newObject("Object", 1234)
manager:printAll()

Access violation when exporting a C++ class to Lua using LuaBind

I'm trying to export a simple class to Lua using LuaBind. I took the code from two sites which showed roughly the same way to do it, but it's still failing.
// Default headers
#include <iostream>
#include <string>
// Lua headers
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "luabind/luabind.hpp"
// Sample class
class NumberPrinter
{
public:
NumberPrinter( int number ) : m_number( number ) {}
void print() { std::cout << m_number << "\n"; }
private:
int m_number;
};
int main() {
// Create Lua state and load sample file
lua_State *luaState = lua_open();
luabind::open( luaState );
// Set up bind to number class
luabind::module( luaState ) [
luabind::class_<NumberPrinter>( "NumberPrinter" )
.def( luabind::constructor<int>() )
.def( "print", &NumberPrinter::print )
];
// Use the class in Lua
luaL_dostring( luaState,
"Print2000 = NumberPrinter(2000)\n"
"Print2000:print()\n"
);
// Clean up Lua state
lua_close( luaState );
getchar();
return 0;
}
When running that code, luabind::module causes the following runtime error and has no other information in debug mode:
Unhandled exception at 0x690008f5 in
Lua Playground.exe: 0xC0000005: Access
violation.
I would encourage you to get this started with the binaries and sample VS2008 solution available from this website. It has the exact same sample code you are trying to run (minus the typos) and it worked well on my machine. If it still doesn't work, you'll need help from the Lua community. A minidump is probably required to help them diagnose this, just the exception message isn't enough.