V8: Passing object from JavaScript to uv_work function - v8

OK, I have a function in C++ that I need to call from JavaScript, and one of the parameters is a JavaScript object. The JavaScript looks like this:
var message = {
fieldA: 42,
fieldB: "moo"
};
myObj.send(message, function (err) { console.log("Result: " + err); });
In the send() routine I need to call a native function in another C library that may block. All functions in this library may block so I've been using uv_queue_work extensively.
This routine is the first time I've hit an issue and it is because of the JavaScript object. The C++ code looks like this:
struct SendMessageRequest
{
Persistent<Object> message;
Persistent<Function> callback;
int result;
};
Handle<Value> MyObj::Send(const Arguments& args)
{
HandleScope scope;
// Parameter checking done but not included here
Local<Object> message = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[1]);
// Send data to worker thread
SendMessageRequest* request = new SendMessageRequest;
request->message = Persistent<Object>::New(message);
request->callback = Persistent<Function>::New(callback);
uv_work_t* req = new uv_work_t();
req->data = request;
uv_queue_work(uv_default_loop(), req, SendMessageWorker, SendMessageWorkerComplete);
return scope.Close(Undefined());
}
This is all fine, the problem comes when I try to access request->message in the SendMessageWorker function.
void SendMessageWorker(uv_work_t* req)
{
SendMessageRequest* request = (SendMessageRequest*)req->data;
Local<Array> names = request->message->GetPropertyNames();
// CRASH
It seems that calling methods off of request->message causes an Access Violation on a really small address (probably a NULL pointer reference somewhere in V8/node). So using request->message directly must be wrong. I know to access the callback function I need to do this:
request->callback->Call(Context::GetCurrent()->Global(), 1, argv);
Do I need to use Context::GetCurrent()->Global() in order to access methods off of the Object class that is wrapped by the Persistent template? If so how do I do that?

The code in SendMessageWorker is not executed on the JavaScript - what uv_queue_work does is execute your SendMessageWorker in a separate thread, so it can let the node.js code run as well, and when it's ready, SendMessageWorkerComplete is executed back on the JavaScript thread.
So you can't use JavaScript variables in SendMessageWorker - if you really need to, you'd have to convert them to e.g. C++ string before calling uv_queue_work.

Related

How to serve multiple interfaces in Capnproto

In the calculator example, I have added a new interface in the capnp file like below:
interface Main {
getCalculator #0 () -> (calculator :Calculator);
}
My objective is to make use of multiple interfaces through one implementation Main. How can I achieve this? The extra client code is below (when I try to use calculator it throws a null capability exception):
capnp::EzRpcClient client1(argv[1]);
Main::Client main = client1.getMain<Main>();
auto& waitScope1 = client1.getWaitScope();
auto request1 = main.getCalculatorRequest();
auto evalPromise1 = request1.send();
auto response1 = evalPromise1.wait(waitScope1);
auto calculator = response1.getCalculator();
auto request = calculator.evaluateRequest();
request.getExpression().setLiteral(123);
// Send it, which returns a promise for the result (without blocking).
auto evalPromise = request.send();
// Using the promise, create a pipelined request to call read() on the
// returned object, and then send that.
auto readPromise = evalPromise.getValue().readRequest().send();
// Now that we've sent all the requests, wait for the response. Until this
// point, we haven't waited at all!
auto response = readPromise.wait(waitScope1);
KJ_ASSERT(response.getValue() == 123);
Changes to the server's main implementation file are given below:
class MainImpl : public Main::Server {
public:
kj::Promise<void> getCalculator(GetCalculatorContext context) override {
context.getResults();
return kj::READY_NOW;
}
};
The main function in server serves MainImpl. I do get the calculator object but how can I further invoke methods on that object?
Your getCalculator() function on the server side does not do anything right now. You need to actually set the result if you want the Calculator to get back to the client. That's why you get your "null capability exception".
Something like this:
class MainImpl : public Main::Server {
public:
kj::Promise<void> getCalculator(GetCalculatorContext context) override {
context.getResults().setCalculator(<the calculator capability>);
return kj::READY_NOW;
}
};
That will require you to create the Calculator client on the server side (i.e. you won't do Calculator::Client calculator = client.getMain<Calculator>(); on the client side anymore, since calculator will come from getCalculator()).

Wakanda callMethod synchronous mode

I'm trying to use callMethod() from a method executed on the server.
In this case, I should be able to call it in synchronous mode. However, through trial and error I have found that in this context (i.e. on the server), the method requires three parameters rather than the two mentioned in the docs.
It requires
the first parameter to be a string
the second parameter to be an array
the third parameter to be an object
I've tried quite a few combinations with these parameters but nothing seems to work. At the same time, Wakanda doesn't throw an error as long as the parameters are in the correct form.
Any ideas would be more than welcome.
TIA
Let's suppose we have two variable, one containing the name of the dataClass and the second the name of the dataClass's method :
var myDataClass = "User";
var myMethod = "addUser";
To use the dataClass 'User' and call the method 'addUser' you can do it this way :
var currentClass = ds.dataClasses[myDataClass];
currentClass[myMethod]()
The method callMethod() is a clientSide method, it should be used on prototyper Js files.
try to use it on a button.click event :
button1.click = function button1_click (event)
{
ds.User.callMethod({method:"method1", onSuccess:myFunction, onError:failure});
function myFunction(){
return true;
}
function failure(){
return false;
}
};
To call method in a serverSide js File in a synchronous mode, you can just make the call in this manner :
var test = ds.User.method1();

v8: can't get calling function name in a functioncallback

I want to make a log of every function called when i run a js script.
So i want to make a callback for all the functions in javascript like this:
global->Set(v8::String::NewFromUtf8(isolate, "print"), v8::FunctionTemplate::New(isolate, LogName));
global->Set(v8::String::NewFromUtf8(isolate, "eval"), v8::FunctionTemplate::New(isolate, LogName));
global->Set(v8::String::NewFromUtf8(isolate, "unescape"), v8::FunctionTemplate::New(isolate, LogName));
I define my function like this:
void LogName(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::String::Utf8Value str_caller(args.Callee());
printf("%s", str_caller);
}
This is printed when unescape is called: function unescape() { [native code] }
But if do:
object = v8::Handle<v8::Object>::Cast(context->Global()->Get(v8::String::NewFromUtf8(isolate, "String")));
object->Set(v8::String::NewFromUtf8(isolate, "fromCharCode"), v8::FunctionTemplate::New(isolate, LogName)->GetFunction());
This is printed when String.fromCharCode is called: function () { [native code] }
Why in the second example i don't have the functions name, like for example "fromCharCode" ?
I'm still pretty new to V8 but have run into this exact same problem. I've found only one solution so far. I'm not sure if it is ideal, but there are no other solutions so here goes...
Notice the functions where getting the name works are where you are adding a FunctionTemplate value to an ObjectTemplate (that is presumably then used as the global template parameter when you create the Context). Also notice in the ones that don't work you are trying to add a Function to the global Object for that existing Context, and this is when getting the Callee name fails (returns a blank string).
The only solution I've found so far is to keep a persistent handle to the ObjectTemplate you create for global scope, add the FunctionTemplate to that when you go to register your new function, and then create a new Context that uses that modified ObjectTemplate. After this then calls to the function will return the Callee name as desired.
To try to illustrate this with some code:
Isolate *gIsolate;
Persistent<ObjectTemplate> gTemplate;
Persistent<Context> gContext;
// Adds a new function to the global object template
void AddFunction(const char *name, FunctionCallback func)
{
// Get global template
Local<ObjectTemplate> global = ObjectTemplate::New(gIsolate, gTemplate);
// Add new function to it
global->Set(String::NewFromUtf8(gIsolate, name), FunctionTemplate::New(gIsolate, func));
}
void FirstTimeInit()
{
gIsolate = Isolate::New();
HandleScope handle_scope(gIsolate);
Handle<ObjectTemplate> global = ObjectTemplate::New(gIsolate);
// Store global template in persistent handle
gTemplate.Reset(gIsolate, global);
// Register starting functions
AddFunction( "print", LogName );
AddFunction( "eval", LogName );
AddFunction( "unescape", LogName );
// Create context
Handle<Context> context = Context::New(gIsolate, NULL, global);
gContext.Reset(gIsolate, context);
}
void AddOtherFunction()
{
AddFunction( "fromCharCode", LogName );
Local<ObjectTemplate> global = ObjectTemplate::New(gIsolate, gTemplate);
// Create a new context from the modified global template
Local<Context> newContext = Context::New(gIsolate, nil, global);
// Update persistent context handle to reference the new one
gContext.Reset(gIsolate, newContext);
}

Fallback callback when calling unavailable function

Is it possible to set a fallback callback which is called when the user wants to call a function which does not exists? E.g.
my_object.ThisFunctionDoesNotExists(2, 4);
Now I want that a function is getting called where the first parameter is the name and a stack (or something like that) with the arguments passed. To clarify, the fallback callback should be a C++ function.
Assuming your question is about embedded V8 engine which is inferred from tags, you can use harmony Proxies feature:
var A = Proxy.create({
get: function (proxy, name) {
return function (param) {
console.log(name, param);
}
}
});
A.hello('world'); // hello world
Use --harmony_proxies param to enable this feature. From C++ code:
static const char v8_flags[] = "--harmony_proxies";
v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1);
Other way:
There is a method on v8::ObjectTemplate called SetNamedPropertyHandler so you can intercept property access. For example:
void GetterCallback(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info)
{
// This will be called on property read
// You can return function here to call it
}
...
object_template->SetNamedPropertyHandler(GetterCallback);

Scoped javascript callback in scala lift

So I've been playing around with Lift in Scala, and I've been enjoying it a lot. I might just be missing something that exists in the lift javascript library, but I haven't been able to find any way of using a scoped javascript callback. It seems that the lift way of handling callbacks is to pass the callback as function name and have lift return a JsCmd that Call()s the function.
My lift code is heavily based on this example http://demo.liftweb.net/json_more
And my javascript looks kinda like
function operation(config) {
var actions = config.actions,
action = actions.shift(),
name = config.name;
function chainAction(response) {
if (actions.length > 0) {
action = actions.shift();
action.action(name, chainAction);
}
}
action.action(name, chainAction);
}
operation({
name: "ajax",
actions: [
{ action: ajaxCall1 },
{ action: ajaxCall2 }
]
});
Where I'd want ajaxCall1 and ajaxCall2, to be AJAX calls to lift. i.e. callNoParam() in the lift example, and chainAction to be the scoped callback. Is there a way to do this in lift that I'm missing? For clarity, I have been able to get this code to call the lift function, but not to handle the callback correctly.
Thanks.
Edit
Upon reading through the lift-generated javascript code, it looks like there are indeed placeholders for success/failure callbacks. In particular, it looks like this line of lift
AllJsonHandler.is.jsCmd
is generating this line of javascript
function F86737576748N5SY25(obj) {liftAjax.lift_ajaxHandler('F86737576748N5SY25='+ encodeURIComponent(JSON.stringify(obj)), null,null);}
which references this method
lift_ajaxHandler: function(theData, theSuccess, theFailure, responseType)
But not allowing me to pass theSuccess or theFailure which look like they are being passed along into jQuery.ajax() calls. My investigation continues. If anyone has any good resources on is.jsCmd it would be appreciated.
Below is a piece of code that adds a Javascript function doCallback to the page (in #placeholder). This function will print a line to the console and then do an ajaxCall back to the server to the function commandCallback.
def addExecuteCallback(ns: NodeSeq):NodeSeq = {
val log = JsRaw("console.log('[doCallback] Generated from Lift.');").cmd &
SHtml.ajaxCall(JsRaw("commandString"), commandCallback _)._2.cmd
val f = JsCmds.Function("doCallback", List[String](), log)
("#placeholder" #> JsCmds.Script(f)).apply(ns)
}
At the end of commandCallback, you can return:
JsCmds.Run("chainAction('" + valueOfResponse + "');")

Resources