Fallback callback when calling unavailable function - v8

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);

Related

cy.origin throws error when trying to call a function which has the args's variable as a parameter

cy.visit('somesite1.com');
....
....
const args = {
testObject: myObject
};
cy.origin( 'somesite2.com', { args }, ({testObject}) => {
console.log('print out my test obj', testObject);
someFunction(testObject);}
`
I am trying to use the cross domain feature. I have Cypress 10.3.1. I am able to visit the cross domain but I have trouble passing the variable for further testing. The error I see is
ReferenceError
_actions4 is not defined
Variables must either be defined within the cy.origin() command or passed in using the args option.
myObject is a json object.
Can someone help please?
Krithika
The problem is someFunction is defined outside the cy.origin(), and cannot be accessed.
function someFunction() {
...
}
const args = {
testObject: myObject
};
cy.origin( 'somesite2.com', { args }, ({testObject}) => {
someFunction(testObject); // cannot be accessed here
}
There are severe limitations on using executable code inside the origin callback.
See Arguments
The args object is the only mechanism via which data may be injected into the callback, the callback is not a closure and does not retain access to the JavaScript context in which it was declared. Values passed into args must be serializable.
not a closure means you can't reference things outside the origin in the same way a simple function can.
must be serializable means you cannot pass functions into the origin.
Essentially, it seems only cy. commands can be be used inside the origin.

Passing a lambda with return value into a callback without return value

This question involves boost::asio but is a pure C++ 11 question.
I am new to C++ 11 & lambda techniques which I am trying to use with boost::asio::async_connect for network communication.
Following is my function which attempts an asynchronous connect with the host.
bool MyAsyncConnectFunction() {
//some logic here to check validity of host
if (ip_is_not_resolved)
return false;
the_socket.reset(new tcp::socket(the_io_service));
auto my_connection_handler = [this]
(const boost::system::error_code& errc, const tcp::resolver::iterator& itr)
{
if (errc) {
//Set some variables to false as we are not connected
return false;
}
//Do some stuff as we are successfully connected at this point
return true;
};
//How is async_connect taking a lambda which
boost::asio::async_connect(the_socket, IP_destination, tcp::resolver::iterator(), my_connection_handler);
return true;
}
All works fine. There are no functional issues absolutely. However, I am wondering that boost::asio::async_connect takes a ConnectionHandler without a return type in its last parameter but I am passing a lambda i.e. my_connection_handler which returns a value.
How is it possible that I can pass a lambda with a return value whereas boost::asio::async_connect's 4th param takes a callback without a return value ?
boost::asio::async_connect is a function template that takes a callable as its fourth argument. It does not use the return value of said callable, nor does it care about it. Just as you could write :
auto f = []() { return true; };
f(); // Return value is discarded
The example of #m.s. is good too. Since it is a template, the function resolves the argument according to the template argument deduction rules.

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);
}

V8: Passing object from JavaScript to uv_work function

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.

Resources