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>
This commit is contained in:
parent
f16fda5ea1
commit
6bf20837c0
@ -10,6 +10,13 @@ const FileUtils = imports.misc.fileUtils;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
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_DOWNLOAD = 'https://extensions.gnome.org/download-extension/%s.shell-extension.zip';
|
||||||
var REPOSITORY_URL_INFO = 'https://extensions.gnome.org/extension-info/';
|
var REPOSITORY_URL_INFO = 'https://extensions.gnome.org/extension-info/';
|
||||||
var REPOSITORY_URL_UPDATE = 'https://extensions.gnome.org/update-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);
|
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
|
||||||
|
|
||||||
_httpSession.queue_message(message, () => {
|
_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;
|
let info;
|
||||||
try {
|
try {
|
||||||
|
checkResponse(message);
|
||||||
info = JSON.parse(message.response_body.data);
|
info = JSON.parse(message.response_body.data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Main.extensionManager.logExtensionError(uuid, e);
|
Main.extensionManager.logExtensionError(uuid, e);
|
||||||
@ -74,44 +73,38 @@ function uninstallExtension(uuid) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
|
/**
|
||||||
if (message.status_code !== Soup.KnownStatusCode.OK) {
|
* Check return status of reponse
|
||||||
errback('Unexpected response: %s'
|
*
|
||||||
.format(Soup.Status.get_phrase(message.status_code)));
|
* @param {Soup.Message} message - an http response
|
||||||
return;
|
* @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));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
|
* @param {GLib.Bytes} bytes - archive data
|
||||||
|
* @param {Gio.File} dir - target directory
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
async function extractExtensionArchive(bytes, dir) {
|
||||||
if (!dir.query_exists(null))
|
if (!dir.query_exists(null))
|
||||||
dir.make_directory_with_parents(null);
|
dir.make_directory_with_parents(null);
|
||||||
} catch (e) {
|
|
||||||
errback(e.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
const [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
||||||
let contents = message.response_body.flatten().get_as_bytes();
|
await stream.output_stream.write_bytes_async(bytes,
|
||||||
stream.output_stream.write_bytes(contents, null);
|
GLib.PRIORITY_DEFAULT, null);
|
||||||
stream.close(null);
|
stream.close_async(GLib.PRIORITY_DEFAULT, null);
|
||||||
let [success, pid] = GLib.spawn_async(null,
|
|
||||||
|
const unzip = Gio.Subprocess.new(
|
||||||
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
|
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
|
||||||
null,
|
Gio.SubprocessFlags.NONE);
|
||||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
await unzip.wait_check_async(null);
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadExtensionUpdate(uuid) {
|
function downloadExtensionUpdate(uuid) {
|
||||||
@ -126,12 +119,17 @@ function downloadExtensionUpdate(uuid) {
|
|||||||
let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
|
let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
|
||||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
let message = Soup.form_request_new_from_hash('GET', url, params);
|
||||||
|
|
||||||
_httpSession.queue_message(message, session => {
|
_httpSession.queue_message(message, async () => {
|
||||||
gotExtensionZipFile(session, message, uuid, dir, () => {
|
try {
|
||||||
|
checkResponse(message);
|
||||||
|
|
||||||
|
const bytes = message.response_body.flatten().get_as_bytes();
|
||||||
|
await extractExtensionArchive(bytes, dir);
|
||||||
Main.extensionManager.notifyExtensionUpdate(uuid);
|
Main.extensionManager.notifyExtensionUpdate(uuid);
|
||||||
}, msg => {
|
} catch (e) {
|
||||||
log('Error while downloading update for extension %s: %s'.format(uuid, msg));
|
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]));
|
[global.userdatadir, 'extensions', this._uuid]));
|
||||||
let uuid = this._uuid;
|
let uuid = this._uuid;
|
||||||
let invocation = this._invocation;
|
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 {
|
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);
|
Main.extensionManager.loadExtension(extension);
|
||||||
if (!Main.extensionManager.enableExtension(uuid))
|
if (!Main.extensionManager.enableExtension(uuid))
|
||||||
throw new Error('Cannot add %s to enabled extensions gsettings key'.format(uuid));
|
throw new Error('Cannot add %s to enabled extensions gsettings key'.format(uuid));
|
||||||
} catch (e) {
|
|
||||||
uninstallExtension(uuid);
|
|
||||||
errback(e.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
invocation.return_value(GLib.Variant.new('(s)', ['successful']));
|
invocation.return_value(GLib.Variant.new('(s)', ['successful']));
|
||||||
|
} catch (e) {
|
||||||
|
log('Error while installing %s: %s'.format(uuid, e.message));
|
||||||
|
uninstallExtension(uuid);
|
||||||
|
invocation.return_dbus_error(
|
||||||
|
'org.gnome.Shell.ExtensionError', e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_httpSession.queue_message(message, session => {
|
|
||||||
gotExtensionZipFile(session, message, uuid, dir, callback, errback);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
|
Loading…
Reference in New Issue
Block a user