I'm writing Agueas [1] addon for Node.js
For now I have synchronous code, C++ class looks like this:
class LibAugeas : public node::ObjectWrap {
public:
static void Init(Handle<Object> target);
protected:
augeas * m_aug;
LibAugeas();
~LibAugeas();
static Handle<Value> New(const Arguments& args);
static Handle<Value> get (const Arguments& args);
static Handle<Value> set (const Arguments& args);
static Handle<Value> setm (const Arguments& args);
// other methods
};
Usage of this class in JS:
var lib = require('...');
var aug = new lib.Augeas(...);
aug.set(...);
aug.get(...);
// etc
I'm going to impelement asynchronous code.
The bottleneck is creating augeas object (aug_init) while all or some lenses and files are being loaded and parsed. So the idea is creating augeas object asynchronously, and then pass created JS object in a callback function:
Pure C thread: call aug_init(), aug_load() to get augeas handle.
When ready, use augeas handle to creat JS object (see the first snippet)
Pass created JS object to callback function.
Usage might be as such:
lib.heracles(function(aug) {
if (!aug.error()) {
console.log('Hello!');
// async save:
aug.save(function(err, msg) {
console.log(msg);
});
} else {
console.log('Sad, but true :-(');
}
}
);
And finally, my problem: I do not know how to create JS object in C++ :-)
Constructor static Handle<Value> New(const Arguments& args); returns args.This(), but when I'm in C++ code I do not have args and also can't wrap object.
So, how do I create JS object in C++? Please, don't break my heart saying it is not possible :-)
[1] http://augeas.net
Ok, thanks to everyone :-)
I've found the right way. Here is a static method which creates an JS object wrapping given augeas handle.
Then I can pass this object to callback function from C++ code.
Local<Object> LibAugeas::New(augeas *aug)
{
LibAugeas *obj = new LibAugeas();
obj->m_aug = aug;
Handle<ObjectTemplate> tpl = ObjectTemplate::New();
tpl->SetInternalFieldCount(1); // one field for LibAugeas* pointer (via obj->Wrap())
#define _OBJ_NEW_METHOD(m) NODE_SET_METHOD(tpl, #m, m)
_OBJ_NEW_METHOD(get);
_OBJ_NEW_METHOD(set);
_OBJ_NEW_METHOD(setm);
_OBJ_NEW_METHOD(rm);
_OBJ_NEW_METHOD(mv);
_OBJ_NEW_METHOD(save);
_OBJ_NEW_METHOD(nmatch);
_OBJ_NEW_METHOD(insert);
_OBJ_NEW_METHOD(error);
Local<Object> O = tpl->NewInstance();
obj->Wrap(O);
return O;
}
Related
I've embedded Python (3.6) code into my C++ application successfully. I use the Python/C API to call methods from this library. An overview of the python module is as follows:
class MyClass(object):
def __init__(args: str) -> None:
...
return
def callable_method(*args) -> Tuple:
...
return some_tuple
#staticmethod()
def create_from_cli_args(argv: List[str]) -> 'MyClass':
...
return MyClass(parsed_args)
The static method is a new addition to my code to move exception logic from the __init__ function to another function and yield an object. The C++ code to construct an object before was as follows:
PyObject *module_name = PyUnicode_FromString("module_path.my_class");
// Load the module object
PyObject *module = PyImport_Import(module_name);
if(module == nullptr) return;
Py_DECREF(module_name);
// Get callable list from module
PyObject *dict = PyModule_GetDict(module);
if(dict == nullptr) return;
Py_DECREF(module);
// Builds the name of a callable class
PyObject *my_class = PyDict_GetItemString(dict, "MyClass");
if(python_class == nullptr) return;
// Check if python class is callable
if(!PyCallable_Check(my_class)) return;
// Populate args for class instantiation
PyObject *py_args = PyTuple_New(1);
PyTuple_SetItem(py_args, 0, PyUnicode_FromString("Initialize_Configs"));
// Construct object
PyObject *my_class_obj = PyObject_CallObject(my_class, py_args);
if(my_class_obj == nullptr) return;
The above code snippet works, however, with the addition of the static method I'm trying to use to create an object of my_class, I'm unable to figure out how to call a static method of a class. I've tried using PyObject *my_class = PyDict_GetItemString(dict, "MyClass.create_my_class"); as well as PyObject_CallMethod(my_class, "create_my_class", kargs, kwargs) but that doesn't work either. I'd appreciate any help.
As the person in the comments suggested, I was incorrectly calling the static method. The solution is:
...
if(!PyCallable_Check(my_class)) return;
// A static method can be called the same as a normal method in python.
PyObject *my_class_object = PyObject_CallMethod(my_class, "create_from_cli_args", "s", "--cli_args");
if(!my_class_object) return;
I have a C++ object which inherits from node::ObjectWrap. The object itself manages the resource so it accepts it as an argument in a private constructor.
When object is created from Javascript it's quite straightforward:
void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
// ...
auto handleToCustomResource = resolveFromJSArg(args[0]->ToString());
auto object = new MyObjectWrap(handleToCustomResource);
object->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
However it's not clear how to wrap the object when it originates from C++, here is my recent effort:
public v8::Local<v8::Object> CreateObject(v8::Isolate *isolate, const char *name) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::EscapableHandleScope scope(isolate);
auto object = new MyObjectWrap(handleToMyCustomResource);
v8::Local<v8::Object> instance = // eh don't have an instance??
object->Wrap(instance);
return scope.Escape(instance);
}
How to properly create a JS object so I could use it as an instance for my native object?
One of workarounds I found is to basically have two constructors, one public and one private and then inherit one from another. The public one is available in javascript, while the private is solely used to create an instance for wrapping an existing ObjectWrap object.
v8::Local<v8::FunctionTemplate> privTpl = v8::FunctionTemplate::New(isolate, PrivateNew);
v8::Local<v8::FunctionTemplate> pubTpl = v8::FunctionTemplate::New(isolate, New);
// define prototype
pubTpl->Inherit(privTpl);
exports->Set(v8::String::NewFromUtf8(isolate, "MyObject"), tpl->GetFunction());
I need to refactor class, which handles requests. I don't need chain of responsibility, because in compile time I have specified which request is connected to which handler.
My idea is to create one singleton class which is responsible for all logic.
For example it will have pointer to database object and it will handle requests.
There will be interface for HandlerMessage and many class derived from them.
Suppose we have:
class Singleton {
Database db;
int handleMessage(const Request& in, Response& out);
};
int Singleton::handleMessage(const Request& in, Response& out) {
int result = 0;
HandlerMessage* handler;
if(in.type == RequestType::A)
handler = new HandlerA();
else if(in.type == RequestType::B)
handler = new HandlerB();
else
return -1;
result = handler->handle(in, out);
delete handler;
return result;
}
However HandlerMessage needs to use Database and I wonder how to get use them.
I can pass pointer to database as an argument of handle function in HandlerMessage class.
However it seems to me strange, because all time I will pass the same argument. Moreover not all handlers needs to use database.
My question is:
class MessageHandler {
static Database* db;
}
this a good solutions, where I initialized db from MessageHandler class with db from SingeltonClass in Singleton constructor?
Or it is better to use more sophisticated solutions?
Thank You for any reply!
You can pass the reference to the database in the constructor of the handler like this:
handler = new HandlerA(db); //HandlerA needs to deal with database
handler = new HanlderB(); //HandlerB doesn't need to deal with database
HandlerA can look like this:
class HandlerA : public MessageHandler
{
HandlerA(Database& db) { /* ... */ }
int handle(const Request& in, Response& out) { /* ... */ }
};
I'm writing node.js bindings and I want to generate JSON string from v8::Object instances. I want to do it in C++. Since node.js already has JSON.stringify, I would like to use it. But I don't know how to access it from the C++ code.
You need to grab a reference to the global object, and then grab the stringify method;
Local<Object> obj = ... // Thing to stringify
// Get the global object.
// Same as using 'global' in Node
Local<Object> global = Context::GetCurrent()->Global();
// Get JSON
// Same as using 'global.JSON'
Local<Object> JSON = Local<Object>::Cast(
global->Get(String::New("JSON")));
// Get stringify
// Same as using 'global.JSON.stringify'
Local<Function> stringify = Local<Function>::Cast(
JSON->Get(String::New("stringify")));
// Stringify the object
// Same as using 'global.JSON.stringify.apply(global.JSON, [ obj ])
Local<Value> args[] = { obj };
Local<String> result = Local<String>::Cast(stringify->Call(JSON, 1, args));
Some of the node API's have changed from the publishing of the OP. Assuming a node.js version 7.7.1, the code transforms to something along the lines of;
std::string ToJson(v8::Local<v8::Value> obj)
{
if (obj.IsEmpty())
return std::string();
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> JSON = isolate->GetCurrentContext()->
Global()->Get(v8::String::NewFromUtf8(isolate, "JSON"))->ToObject();
v8::Local<v8::Function> stringify = JSON->Get(
v8::String::NewFromUtf8(isolate, "stringify")).As<v8::Function>();
v8::Local<v8::Value> args[] = { obj };
// to "pretty print" use the arguments below instead...
//v8::Local<v8::Value> args[] = { obj, v8::Null(isolate), v8::Integer::New(isolate, 2) };
v8::Local<v8::Value> const result = stringify->Call(JSON,
std::size(args), args);
v8::String::Utf8Value const json(result);
return std::string(*json);
}
Basically, the code gets the JSON object from the engine, obtains a reference to the function stringify of that object, and then calls it. The code is tantamount to the javascript;
var j = JSON.stringify(obj);
Further v8 based alternatives include using the JSON class.
auto str = v8::JSON::Stringify(v8::Isolate::GetCurrent()->GetCurrentContext(), obj).ToLocalChecked();
v8::String::Utf8Value json{ str };
return std::string(*json);
I use node.js for a while, now I need write an add-on, but I am a newb of c++.
in node.js I can pass optional arguments to function, and check their types.
function hello(arg, options, callback){
if(!callback){
if(typeof options === 'function'){
callback = options;
options = {};
}
}
console.log(typeof arg);
}
But in an addon.
Handle<Value> hello(const Arguments &args) {
HandleScope scope;
printf("%d\n", args.Length());
// how to check type of args[i]
return String::New("world");
}
You should look over the API in http://v8.googlecode.com/svn/trunk/include/v8.h. Most of the functions you are interested are on the Value class. There is documentation online here, http://bespin.cz/~ondras/html/classv8_1_1Value.html but that looks like just some random person's uploaded version of the docs. Not sure if they are online somewhere else.
Something like this should do about the same thing as your JS snippet.
Handle<Value> hello(const Arguments &args) {
HandleScope scope;
Local<Value> arg(args[0]);
Local<Value> options(args[1]);
Local<Value> callback(args[2]);
if (callback.equals(False())) {
if (options->IsFunction()) {
callback = options;
options = Object::New();
}
}
// ...
}