[Solved] Determining JavaScript callback signature

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

[Solved] Determining JavaScript callback signature

Postby Gazoo » Mon Oct 02, 2023 11:50 am

Hey Cef-Folks,

Is there any way to determine the function signature of an incoming JavaScript function being passed to CEF?

More specifically, I'm following the super useful JavaScript callback example provided in the CEF wiki here: https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-executing-functions

In it, a function called myFunc() is passed to CEF via a register function:

Code: Select all
<script language="JavaScript">
function myFunc() {
  // do something in JS.
}
window.register(myFunc);
</script>


Once myFunc() triggers the following example code in the MyV8Handler::Execute() implementation:

Code: Select all
bool MyV8Handler::Execute(const CefString& name,
                          CefRefPtr<CefV8Value> object,
                          const CefV8ValueList& arguments,
                          CefRefPtr<CefV8Value>& retval,
                          CefString& exception) {
  if (name == "register") {
    if (arguments.size() == 1 && arguments[0]->IsFunction()) {
      callback_func_ = arguments[0];
      callback_context_ = CefV8Context::GetCurrentContext();
      return true;
    }
  }

  return false;
}


I wonder if there's a way to somehow determine the signature of the function call passed in arguments[0]? If not here, is there some other way to achieve this?

If not - I'm assuming the C++ function triggering the provided callback function, has to know/hard-code the parameters it may take?

Thanks in advance,
Gazoo
Last edited by Gazoo on Sun Oct 08, 2023 9:44 am, edited 1 time in total.
Gazoo
Techie
 
Posts: 10
Joined: Fri Aug 18, 2023 8:48 am

Re: Determining JavaScript callback signature

Postby magreenblatt » Mon Oct 02, 2023 1:03 pm

You can check JavaScript properties on the function object using CefV8Context::Eval. For some ideas on how you might use this see https://stackoverflow.com/questions/483 ... registered
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Re: Determining JavaScript callback signature

Postby magreenblatt » Mon Oct 02, 2023 1:15 pm

Note you would need some way to expose the to-be-evaluated function to the eval’d JS code (like adding a window._getCurrentFunction binding)
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Re: Determining JavaScript callback signature

Postby Gazoo » Tue Oct 03, 2023 2:35 am

Hey magreenblatt,

Thank you so much for creating and working on CEF, and thank you for your response. It's a god-send for someone like me who want to build a multi-touch User-interface to be integrated into an existing C++ application. I've got quite a ways to go to integrate CEF properly, but I just wanted to take a moment to express my appreciation.

Ok - so if I understand you correctly, the CEF C++-side code doesn't directly provide an ability to determine something about the incoming callback function signature. It is however possible to determine the incoming function's signature by running JavaScript via the CefV8Context::Eval() function.

That sounds a bit tricky to me, so I'll probably adopt my fallback approach, which is to bake all my arguments into a single Json string, and handle the value-to-parameter unpacking problem on the JS side entirely.

One last follow-up question I've wondered about concerns transitioning objects from C++ over to the JS side, and back. My approach is to rely on JSON as the intermediate format and have appropriate converters on either side, but it is actually possible to pass objects created in C++ over to the JS side? I'm aware that CEF has the CefV8Value::CreateObject() function, and I've seen some sample code which builds up code in C++ that's callable from the JS side, but my impression so far is that if you want to transfer objects with data between the two 'world', it's easiest to rely on JSON as an intermediary and pack/unpack on either side. Hopefully what I'm asking makes sense.

Cheers,
Lasse
Gazoo
Techie
 
Posts: 10
Joined: Fri Aug 18, 2023 8:48 am

Re: Determining JavaScript callback signature

Postby magreenblatt » Tue Oct 03, 2023 8:48 am

my impression so far is that if you want to transfer objects with data between the two 'world', it's easiest to rely on JSON as an intermediary and pack/unpack on either side

JSON is likely the easiest. If you’re passing a large amount of data in each message you might get better performance using the network stack: https://bitbucket.org/chromiumembedded/ ... t-handling
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Re: Determining JavaScript callback signature

Postby magreenblatt » Tue Oct 03, 2023 8:57 am

You might also want to use CefMessageRouter instead of implementing the routing yourself: https://bitbucket.org/chromiumembedded/ ... age-router
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Re: Determining JavaScript callback signature

Postby Gazoo » Wed Oct 04, 2023 6:26 am

JSON is likely the easiest. If you’re passing a large amount of data in each message you might get better performance using the network stack: https://bitbucket.org/chromiumembedded/ ... t-handling


That's great advice. In the future, I'll be passing audio-data between the front-end and back-end to render a waveform, and if that strains the JSON-based approach, I'll definitely look into it. Thanks!

You might also want to use CefMessageRouter instead of implementing the routing yourself: https://bitbucket.org/chromiumembedded/ ... age-router


Also great advice, which I adhere to.

I hope you don't mind me being a bit verbose in order to ensure clarity. My understanding is that the CefMessageRouter implements asynchronous polling. I.e. cefQuery() is called in JS, polling the C++ back-end for data. I also want to push some data from the C++ to JS.

Since I'm not a huge fan of executing raw JavaScript (https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-executejavascript), I opted to use the approach mentioned in my first post - having JS register a function that the C++ back-end is at liberty to call any time it so pleases, i.e. actively pushing, rather than polling.

In short, CefMessageRouter appears to support a polling - but not pushing - approach, is that correct?

Cheers,
Lasse
Gazoo
Techie
 
Posts: 10
Joined: Fri Aug 18, 2023 8:48 am

Re: Determining JavaScript callback signature

Postby magreenblatt » Wed Oct 04, 2023 8:56 am

CefMessageRouter supports subscriptions, which are long-lived JS function registrations that can be called from the C++ side multiple times. See here in the documentation.
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Re: Determining JavaScript callback signature

Postby Gazoo » Wed Oct 04, 2023 10:20 am

Thank you for the on-going responses magreenblatt, really appreciate it.

I'm quite confused about the subscriptions support you pointed out. I've followed the existing stand-alone example (https://bitbucket.org/chromiumembedded/cef-project/src/master/examples/message_router/?at=master) to implement CefMessageRouter in my code. However the example html code doesn't set the 'persistent' boolean property, so I'm guessing it's just demonstrating the one-time request feature.

Setting 'persistent' to true on the JavaScript side is easy enough, but I'm unsure how to leverage the C/C++ CefMessageRouter after that. I've peeked inside both cef_message_router.h (https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_message_router.h) and cef_message_router.cc (https://github.com/chromiumembedded/cef/blob/master/libcef_dll/wrapper/cef_message_router.cc), and they're a bit daunting to me.

Some general questions about subscriptions support are:
  • When my custom message handler (which is derived from CefMessageRouterBrowserSide::Handler) receives the "CefRefPtr<Callback> callback" object inside OnQuery(), do I need to store it in my custom message handler, or is there a way to query all persistently stored callbacks in the underlying object? If yes, are they accessible via the request string?
  • If I do need to store callbacks in my custom message handler, what's the recommended way to check if they've expired?
  • Is there any tutorial code for using subscriptions like the stand-alone example for the one-time request feature?

Cheers,
Lasse
Gazoo
Techie
 
Posts: 10
Joined: Fri Aug 18, 2023 8:48 am

Re: Determining JavaScript callback signature

Postby magreenblatt » Wed Oct 04, 2023 10:43 am

When my custom message handler (which is derived from CefMessageRouterBrowserSide::Handler) receives the "CefRefPtr<Callback> callback" object inside OnQuery(), do I need to store it in my custom message handler? If I do need to store callbacks in my custom message handler, what's the recommended way to check if they've expired?

In OnQuery when the |persistent| argument is true you can store an entry in a std::map keyed by query_id. Remove the entry when OnQueryCanceled is called for the same query_id.
Is there any tutorial code for using subscriptions like the stand-alone example for the one-time request feature?

There's an example at media_router_test.cc that should be pretty easy to follow (note in this case it's limited to one subscription per browser).
magreenblatt
Site Admin
 
Posts: 12744
Joined: Fri May 29, 2009 6:57 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 14 guests