[gnome-shell] extensionDownloader: Use async code for extracting archive
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] extensionDownloader: Use async code for extracting archive
- Date: Wed, 25 Aug 2021 00:00:27 +0000 (UTC)
commit 6bf20837c0acbaccba5d0e9821f19ecdffb69fbc
Author: Florian Müllner <fmuellner gnome org>
Date: Sat Aug 7 00:07:30 2021 +0200
extensionDownloader: Use async code for extracting archive
The code that handles extracting extension archives currently uses
an awkward double-callback system. We can do significantly better
by using an async function and exceptions.
Partially based on code from Marco Trevisan.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1940>
js/ui/extensionDownloader.js | 125 +++++++++++++++++++++----------------------
1 file changed, 61 insertions(+), 64 deletions(-)
---
diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js
index 2659f29d9a..3b64ec4b9c 100644
--- a/js/ui/extensionDownloader.js
+++ b/js/ui/extensionDownloader.js
@@ -10,6 +10,13 @@ const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
+Gio._promisify(Gio.OutputStream.prototype,
+ 'write_bytes_async', 'write_bytes_finish');
+Gio._promisify(Gio.IOStream.prototype,
+ 'close_async', 'close_finish');
+Gio._promisify(Gio.Subprocess.prototype,
+ 'wait_check_async', 'wait_check_finish');
+
var REPOSITORY_URL_DOWNLOAD = 'https://extensions.gnome.org/download-extension/%s.shell-extension.zip';
var REPOSITORY_URL_INFO = 'https://extensions.gnome.org/extension-info/';
var REPOSITORY_URL_UPDATE = 'https://extensions.gnome.org/update-info/';
@@ -25,17 +32,9 @@ function installExtension(uuid, invocation) {
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
_httpSession.queue_message(message, () => {
- const { statusCode } = message;
- if (statusCode !== Soup.KnownStatusCode.OK) {
- const msg = 'Unexpected response: %s'
- .format(Soup.Status.get_phrase(statusCode));
- Main.extensionManager.logExtensionError(uuid, msg);
- invocation.return_dbus_error('org.gnome.Shell.ExtensionError', msg);
- return;
- }
-
let info;
try {
+ checkResponse(message);
info = JSON.parse(message.response_body.data);
} catch (e) {
Main.extensionManager.logExtensionError(uuid, e);
@@ -74,44 +73,38 @@ function uninstallExtension(uuid) {
return true;
}
-function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
- if (message.status_code !== Soup.KnownStatusCode.OK) {
- errback('Unexpected response: %s'
- .format(Soup.Status.get_phrase(message.status_code)));
- return;
- }
-
- try {
- if (!dir.query_exists(null))
- dir.make_directory_with_parents(null);
- } catch (e) {
- errback(e.message);
- return;
- }
+/**
+ * Check return status of reponse
+ *
+ * @param {Soup.Message} message - an http response
+ * @returns {void}
+ * @throws
+ */
+function checkResponse(message) {
+ const { statusCode } = message;
+ const phrase = Soup.Status.get_phrase(statusCode);
+ if (statusCode !== Soup.KnownStatusCode.OK)
+ throw new Error('Unexpected response: %s'.format(phrase));
+}
- let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
- let contents = message.response_body.flatten().get_as_bytes();
- stream.output_stream.write_bytes(contents, null);
- stream.close(null);
- let [success, pid] = GLib.spawn_async(null,
+/**
+ * @param {GLib.Bytes} bytes - archive data
+ * @param {Gio.File} dir - target directory
+ * @returns {void}
+ */
+async function extractExtensionArchive(bytes, dir) {
+ if (!dir.query_exists(null))
+ dir.make_directory_with_parents(null);
+
+ const [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
+ await stream.output_stream.write_bytes_async(bytes,
+ GLib.PRIORITY_DEFAULT, null);
+ stream.close_async(GLib.PRIORITY_DEFAULT, null);
+
+ const unzip = Gio.Subprocess.new(
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
- null,
- GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
- null);
-
- if (!success) {
- errback('Failed to extract extension');
- return;
- }
-
- GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, (o, status) => {
- GLib.spawn_close_pid(pid);
-
- if (status !== 0)
- errback('Failed to extract extension');
- else
- callback();
- });
+ Gio.SubprocessFlags.NONE);
+ await unzip.wait_check_async(null);
}
function downloadExtensionUpdate(uuid) {
@@ -126,12 +119,17 @@ function downloadExtensionUpdate(uuid) {
let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
let message = Soup.form_request_new_from_hash('GET', url, params);
- _httpSession.queue_message(message, session => {
- gotExtensionZipFile(session, message, uuid, dir, () => {
+ _httpSession.queue_message(message, async () => {
+ try {
+ checkResponse(message);
+
+ const bytes = message.response_body.flatten().get_as_bytes();
+ await extractExtensionArchive(bytes, dir);
Main.extensionManager.notifyExtensionUpdate(uuid);
- }, msg => {
- log('Error while downloading update for extension %s: %s'.format(uuid, msg));
- });
+ } catch (e) {
+ log('Error while downloading update for extension %s: %s'
+ .format(uuid, e.message));
+ }
});
}
@@ -226,28 +224,27 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
[global.userdatadir, 'extensions', this._uuid]));
let uuid = this._uuid;
let invocation = this._invocation;
- function errback(msg) {
- log('Error while installing %s: %s'.format(uuid, msg));
- invocation.return_dbus_error('org.gnome.Shell.ExtensionError', msg);
- }
- function callback() {
+ _httpSession.queue_message(message, async () => {
try {
- let extension = Main.extensionManager.createExtensionObject(uuid, dir,
ExtensionUtils.ExtensionType.PER_USER);
+ checkResponse(message);
+
+ const bytes = message.response_body.flatten().get_as_bytes();
+ await extractExtensionArchive(bytes, dir);
+
+ const extension = Main.extensionManager.createExtensionObject(
+ uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
Main.extensionManager.loadExtension(extension);
if (!Main.extensionManager.enableExtension(uuid))
throw new Error('Cannot add %s to enabled extensions gsettings key'.format(uuid));
+
+ invocation.return_value(GLib.Variant.new('(s)', ['successful']));
} catch (e) {
+ log('Error while installing %s: %s'.format(uuid, e.message));
uninstallExtension(uuid);
- errback(e.message);
- return;
+ invocation.return_dbus_error(
+ 'org.gnome.Shell.ExtensionError', e.message);
}
-
- invocation.return_value(GLib.Variant.new('(s)', ['successful']));
- }
-
- _httpSession.queue_message(message, session => {
- gotExtensionZipFile(session, message, uuid, dir, callback, errback);
});
this.close();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]