Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use callbacks for bindings to enable async behavior #2

Merged
merged 1 commit into from Mar 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 16 additions & 9 deletions gui/choc_WebView.h
Expand Up @@ -135,7 +135,8 @@ class WebView
void navigate (const std::string& url);

/// A callback function which can be passed to bind().
using CallbackFn = std::function<choc::value::Value(const choc::value::ValueView& args)>;
using ReplyFn = std::function<void(choc::value::Value, std::string)>;
using CallbackFn = std::function<void(const choc::value::ValueView& args, ReplyFn&& reply)>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clarifying question: in this new world, all functions would be required to call reply (at their leisure), and not be required to return anything. is that right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking thought: I wonder if it's worth supporting both synchronous and async bind() calls. If this were to get upstreamed I think that would be necessary. Maybe have a separate bindWithAsyncReply() method.

That would make the implementation a little more complex, but you should be able to do something like:

// Pseudocode
using CallbackFn = std::function<choc::value::Value(const choc::value::ValueView& args)>;
using AsyncCallbackFn = std::function<void(const choc::value::ValueView& args, ReplyFn&& reply)>;
// ...
unordered_map<string, variant<CallbackFn, AsyncCallbackFn>> bindings;
// ...
invokeBinding() {
   if (holds_alternative<CallbackFn>(b)) {
       doSynchronousCallback();
    } else {
        doAsyncCallback();
    }
}

/// Binds a C++ function to a named javascript function that can be called
/// by code running in the browser.
void bind (const std::string& functionName, CallbackFn&& function);
Expand Down Expand Up @@ -1495,17 +1496,23 @@ inline void WebView::invokeBinding (const std::string& msg)

try
{
auto result = b->second (json["params"]);
b->second (json["params"], [=](choc::value::Value result, std::string const& errorMessage) {
if (!errorMessage.empty())
{
auto call = callbackItem + ".reject(" + choc::json::toString(choc::value::createString(errorMessage)) + "); delete " + callbackItem + ";";
evaluateJavascript (call);
return;
}

auto call = callbackItem + ".resolve(" + choc::json::toString (result) + "); delete " + callbackItem + ";";
auto call = callbackItem + ".resolve(" + choc::json::toString (result) + "); delete " + callbackItem + ";";
evaluateJavascript (call);
});
}
catch (const std::exception& e)
{
auto call = callbackItem + ".reject(" + choc::json::toString(choc::value::createString(e.what())) + "); delete " + callbackItem + ";";
evaluateJavascript (call);
return;
}
catch (const std::exception&)
{}

auto call = callbackItem + ".reject(); delete " + callbackItem + ";";
evaluateJavascript (call);
}
catch (const std::exception&)
{}
Expand Down