[epiphany/pgriffis/web-extension-gtask: 7/15] WebExtensions: Rewrite message handling to be async friendly
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/pgriffis/web-extension-gtask: 7/15] WebExtensions: Rewrite message handling to be async friendly
- Date: Thu, 26 May 2022 20:46:21 +0000 (UTC)
commit f9aa9a979077a3e1d8c51b8fafec598ee92ef69c
Author: Patrick Griffis <pgriffis igalia com>
Date: Tue May 24 17:03:09 2022 -0500
WebExtensions: Rewrite message handling to be async friendly
Part-of: <https://gitlab.gnome.org/GNOME/epiphany/-/merge_requests/1119>
.../web-process-extension/ephy-webextension-api.c | 111 ++++++++++++++++++++-
.../resources/js/webextensions-common.js | 14 +--
src/webextension/ephy-web-extension-manager.c | 80 +++++++--------
3 files changed, 148 insertions(+), 57 deletions(-)
---
diff --git a/embed/web-process-extension/ephy-webextension-api.c
b/embed/web-process-extension/ephy-webextension-api.c
index 3b9cb67d7..bdcf38cda 100644
--- a/embed/web-process-extension/ephy-webextension-api.c
+++ b/embed/web-process-extension/ephy-webextension-api.c
@@ -136,6 +136,101 @@ ephy_web_extension_extension_get (void)
return EPHY_WEB_EXTENSION_EXTENSION (g_once (&once_init, ephy_web_extension_extension_create_instance,
NULL));
}
+typedef struct {
+ JSCValue *resolve_callback;
+ JSCValue *reject_callback;
+} EphyMessageData;
+
+static void
+ephy_message_data_free (EphyMessageData *data)
+{
+ g_object_unref (data->reject_callback);
+ g_object_unref (data->resolve_callback);
+ g_free (data);
+}
+
+static EphyMessageData *
+ephy_message_data_new (JSCValue *resolve_callback,
+ JSCValue *reject_callback)
+{
+ EphyMessageData *data = g_new (EphyMessageData, 1);
+ data->resolve_callback = g_object_ref (resolve_callback);
+ data->reject_callback = g_object_ref (reject_callback);
+ return data;
+}
+
+static void
+on_send_message_finish (WebKitWebExtension *extension,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (WebKitUserMessage) response = NULL;
+ GVariant *params;
+
+ response = webkit_web_extension_send_message_to_context_finish (extension, result, &error);
+
+ if (error) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ } else if (strcmp (webkit_user_message_get_name (response), "error") == 0) {
+ params = webkit_user_message_get_parameters (response);
+ g_assert (params);
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "%s", g_variant_get_string (params, NULL));
+ g_task_return_error (task, g_steal_pointer (&error));
+ } else {
+ params = webkit_user_message_get_parameters (response);
+ g_assert (params);
+ g_task_return_pointer (task, g_variant_dup_string (params, NULL), g_free);
+ }
+
+ g_object_unref (task);
+}
+
+static void
+on_ephy_message_finish (EphyWebExtensionExtension *extension,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr (GError) error = NULL;
+ EphyMessageData *message_data = g_task_get_task_data (G_TASK (result));
+ g_autofree char *json = g_task_propagate_pointer (G_TASK (result), &error);
+ g_autoptr (JSCValue) value = jsc_value_new_from_json (jsc_value_get_context
(message_data->resolve_callback), json);
+ g_autoptr (JSCValue) ret = NULL;
+
+ if (error) {
+ ret = jsc_value_function_call (message_data->reject_callback, G_TYPE_STRING, error->message,
G_TYPE_NONE);
+ } else {
+ ret = jsc_value_function_call (message_data->resolve_callback, JSC_TYPE_VALUE, value, G_TYPE_NONE);
+ }
+}
+
+static void
+ephy_send_message (const char *function_name,
+ JSCValue *function_args,
+ JSCValue *resolve_callback,
+ JSCValue *reject_callback,
+ gpointer user_data)
+{
+ EphyWebExtensionExtension *extension = user_data;
+ WebKitUserMessage *message;
+ EphyMessageData *data;
+ GTask *task;
+ char *args_json;
+
+ /* TODO: If function_args is list and last arg is callable, treat it as `chrome` API. */
+ /* TODO: Check for valid types for args, resolve, reject. */
+
+ task = g_task_new (extension, NULL, (GAsyncReadyCallback)on_ephy_message_finish, NULL);
+ data = ephy_message_data_new (resolve_callback, reject_callback);
+ g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify)ephy_message_data_free);
+
+ args_json = jsc_value_to_json (function_args, 0);
+ message = webkit_user_message_new (function_name, g_variant_new_take_string (args_json));
+
+ webkit_web_extension_send_message_to_context (extension->extension, message, NULL,
(GAsyncReadyCallback)on_send_message_finish, task);
+}
+
static void
window_object_cleared_cb (WebKitScriptWorld *world,
WebKitWebPage *page,
@@ -157,6 +252,19 @@ window_object_cleared_cb (WebKitScriptWorld *world,
js_browser = jsc_context_get_value (js_context, "browser");
g_assert (!jsc_value_is_object (js_browser));
+ js_function = jsc_value_new_function (js_context,
+ "ephy_send_message",
+ G_CALLBACK (ephy_send_message),
+ extension, NULL,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_STRING,
+ JSC_TYPE_VALUE,
+ JSC_TYPE_VALUE,
+ JSC_TYPE_VALUE);
+ jsc_context_set_value (js_context, "ephy_send_message", js_function);
+ g_clear_object (&js_function);
+
bytes = g_resources_lookup_data ("/org/gnome/epiphany-web-extension/js/webextensions-common.js",
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
data = g_bytes_get_data (bytes, &data_size);
result = jsc_context_evaluate_with_source_uri (js_context, data, data_size,
"resource:///org/gnome/epiphany-web-extension/js/webextensions-common.js", 1);
@@ -213,14 +321,13 @@ ephy_web_extension_extension_initialize (EphyWebExtensionExtension *extension,
extension->initialized = TRUE;
extension->guid = g_strdup (guid);
+ extension->extension = g_object_ref (wk_extension);
g_signal_connect (webkit_script_world_get_default (),
"window-object-cleared",
G_CALLBACK (window_object_cleared_cb),
extension);
- extension->extension = g_object_ref (wk_extension);
-
ephy_web_extension_extension_update_translations (extension, translations);
g_signal_connect_swapped (extension->extension, "page-created",
diff --git a/embed/web-process-extension/resources/js/webextensions-common.js
b/embed/web-process-extension/resources/js/webextensions-common.js
index f4417b3e3..5c2820d56 100644
--- a/embed/web-process-extension/resources/js/webextensions-common.js
+++ b/embed/web-process-extension/resources/js/webextensions-common.js
@@ -1,12 +1,10 @@
'use strict';
-/* exported runtimeSendMessage, runtimeOnConnect, ephy_message */
+/* exported ephy_message */
+/* global ephy_send_message */
window.browser = {};
-const promises = [];
-let last_promise = 0;
-
class EphyEventListener {
constructor () {
this._listeners = [];
@@ -30,12 +28,10 @@ class EphyEventListener {
}
}
-const ephy_message = function (fn, args, cb) {
- const promise = new Promise (function (resolve, reject) {
- window.webkit.messageHandlers.epiphany.postMessage ({fn: fn, args: args, promise: last_promise});
- last_promise = promises.push({resolve: resolve, reject: reject});
+const ephy_message = function (fn, ...args) {
+ return new Promise (function (resolve, reject) {
+ ephy_send_message (fn, args, resolve, reject);
});
- return promise;
};
window.browser.runtime = {
diff --git a/src/webextension/ephy-web-extension-manager.c b/src/webextension/ephy-web-extension-manager.c
index d51473e07..2ea6b95e1 100644
--- a/src/webextension/ephy-web-extension-manager.c
+++ b/src/webextension/ephy-web-extension-manager.c
@@ -438,66 +438,61 @@ create_page_action_widget (EphyWebExtensionManager *self,
return g_object_ref (event_box);
}
-typedef struct {
- EphyWebExtension *web_extension;
- WebKitWebView *web_view;
-} ScriptMessageData;
-
static void
-ephy_web_extension_handle_script_message (WebKitUserContentManager *ucm,
- WebKitJavascriptResult *js_result,
- gpointer user_data)
+respond_with_error (WebKitUserMessage *message,
+ const char *error)
+{
+ WebKitUserMessage *reply = webkit_user_message_new ("error", g_variant_new_string (error));
+ webkit_user_message_send_reply (message, reply);
+}
+
+static gboolean
+ephy_web_extension_handle_user_message (WebKitWebContext *context,
+ WebKitUserMessage *message,
+ gpointer user_data)
{
- ScriptMessageData *data = user_data;
- EphyWebExtension *web_extension = data->web_extension;
- WebKitWebView *web_view = data->web_view;
- JSCValue *value = webkit_javascript_result_get_js_value (js_result);
- g_autofree char *name_str = NULL;
- g_autoptr (JSCValue) name = NULL;
- g_autoptr (JSCValue) promise = NULL;
+ EphyWebExtension *web_extension = user_data;
+ g_autoptr (JSCContext) js_context = NULL;
+ g_autoptr (JSCValue) args = NULL;
+ const char *name = webkit_user_message_get_name (message);
g_auto (GStrv) split = NULL;
- unsigned int idx;
- if (!jsc_value_is_object (value))
- return;
- if (!jsc_value_object_has_property (value, "promise"))
- return;
- promise = jsc_value_object_get_property (value, "promise");
- if (!jsc_value_is_number (promise))
- return;
-
- name = jsc_value_object_get_property (value, "fn");
- if (!name)
- return;
+ js_context = jsc_context_new ();
+ args = jsc_value_new_from_json (js_context, g_variant_get_string (webkit_user_message_get_parameters
(message), NULL));
- name_str = jsc_value_to_string (name);
- LOG ("%s(): Called for %s, function %s\n", __FUNCTION__, ephy_web_extension_get_name (web_extension),
name_str);
+ LOG ("%s(): Called for %s, function %s (%s)\n", __FUNCTION__, ephy_web_extension_get_name (web_extension),
name, g_variant_get_string (webkit_user_message_get_parameters (message), NULL));
- split = g_strsplit (name_str, ".", 2);
+ split = g_strsplit (name, ".", 2);
if (g_strv_length (split) != 2) {
- g_warning ("Invalid function call, aborting: %s", name_str);
- return;
+ respond_with_error (message, "Invalid function name");
+ return TRUE;
}
- for (idx = 0; idx < G_N_ELEMENTS (api_handlers); idx++) {
+ for (guint idx = 0; idx < G_N_ELEMENTS (api_handlers); idx++) {
EphyWebExtensionApiHandler handler = api_handlers[idx];
if (g_strcmp0 (handler.name, split[0]) == 0) {
g_autofree char *ret = NULL;
g_autofree char *script = NULL;
- g_autoptr (JSCValue) args = jsc_value_object_get_property (value, "args");
+ WebKitUserMessage *reply;
ret = handler.execute (web_extension, split[1], args);
- script = g_strdup_printf ("promises[%.f].resolve(%s);", jsc_value_to_double (promise), ret ? ret : "");
- webkit_web_view_run_javascript (web_view, script, NULL, NULL, NULL);
+ if (ret) {
+ reply = webkit_user_message_new ("", g_variant_new_take_string (g_steal_pointer (&ret)));
+ } else {
+ reply = webkit_user_message_new ("", g_variant_new_string ("{}"));
+ }
- return;
+ webkit_user_message_send_reply (message, reply);
+ return TRUE;
}
}
- g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name_str);
+ g_warning ("%s(): '%s' not implemented by Epiphany!", __FUNCTION__, name);
+ respond_with_error (message, "Not implemented");
+ return TRUE;
}
static void
@@ -688,7 +683,6 @@ create_web_extensions_webview (EphyWebExtension *web_extension)
WebKitSettings *settings;
WebKitWebContext *web_context;
GtkWidget *web_view;
- ScriptMessageData *data;
/* Create an own ucm so new scripts/css are only applied to this web_view */
ucm = webkit_user_content_manager_new ();
@@ -699,6 +693,7 @@ create_web_extensions_webview (EphyWebExtension *web_extension)
"ephy-webextension");
g_signal_connect_object (web_context, "initialize-web-extensions", G_CALLBACK (init_web_extension_api),
web_extension, 0);
+ g_signal_connect (web_context, "user-message-received", G_CALLBACK
(ephy_web_extension_handle_user_message), web_extension);
web_view = g_object_new (WEBKIT_TYPE_WEB_VIEW,
"web-context", web_context,
@@ -710,13 +705,6 @@ create_web_extensions_webview (EphyWebExtension *web_extension)
settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
webkit_settings_set_enable_write_console_messages_to_stdout (settings, TRUE);
- data = g_new0 (ScriptMessageData, 1);
- data->web_extension = web_extension;
- data->web_view = WEBKIT_WEB_VIEW (web_view);
-
- g_signal_connect_data (ucm, "script-message-received::epiphany", G_CALLBACK
(ephy_web_extension_handle_script_message), data, (GClosureNotify)g_free, 0);
- webkit_user_content_manager_register_script_message_handler (ucm, "epiphany");
-
return web_view;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]