[gnome-shell] extensionSystem: Add install-from-HTTP capability



commit d8a98e5467ca59a8203229fc10c9e5ca16158312
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Aug 24 13:08:34 2011 -0400

    extensionSystem: Add install-from-HTTP capability
    
    This adds a new DBus method: InstallExtensionRemote(uuid : s, url : s)
    
    Pass it the UUID of an extension and the URL of a manifest file: the same as a
    metadata.json, but with a special key, '__installer', which is an HTTP location
    that points to an zip file containing the extension. The Shell will download
    and use it to install the extension. In the future, the manifest file may be
    used to automatically detect and install updates.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=654770

 js/ui/extensionSystem.js |   83 ++++++++++++++++++++++++++++++++++++++++++++++
 js/ui/shellDBus.js       |    8 ++++
 2 files changed, 91 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 6bd6b91..8907a8e 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -7,6 +7,7 @@ const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
 const St = imports.gi.St;
 const Shell = imports.gi.Shell;
+const Soup = imports.gi.Soup;
 
 const Config = imports.misc.config;
 
@@ -26,6 +27,15 @@ const ExtensionType = {
     PER_USER: 2
 };
 
+const _httpSession = new Soup.SessionAsync();
+
+// The unfortunate state of gjs, gobject-introspection and libsoup
+// means that I have to do a hack to add a feature.
+// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
+
+if (Soup.Session.prototype.add_feature != null)
+    Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
+
 // Maps uuid -> metadata object
 const extensionMeta = {};
 // Maps uuid -> importer object (extension directory tree)
@@ -81,6 +91,79 @@ function versionCheck(required, current) {
     return false;
 }
 
+function installExtensionFromManifestURL(uuid, url) {
+    _httpSession.queue_message(
+        Soup.Message.new('GET', url),
+        function(session, message) {
+            if (message.status_code != Soup.KnownStatusCode.OK) {
+                logExtensionError(uuid, 'downloading manifest: ' + message.status_code.toString());
+                return;
+            }
+
+            let manifest;
+            try {
+                manifest = JSON.parse(message.response_body.data);
+            } catch (e) {
+                logExtensionError(uuid, 'parsing: ' + e.toString());
+                return;
+            }
+
+            if (uuid != manifest['uuid']) {
+                logExtensionError(uuid, 'manifest: manifest uuids do not match');
+                return;
+            }
+
+            installExtensionFromManifest(manifest, meta);
+        });
+}
+
+function installExtensionFromManifest(manifest, meta) {
+    let uuid = manifest['uuid'];
+    let name = manifest['name'];
+
+    let url = manifest['__installer'];
+    _httpSession.queue_message(Soup.Message.new('GET', url),
+                               function(session, message) {
+                                   gotExtensionZipFile(session, message, uuid);
+                               });
+}
+
+function gotExtensionZipFile(session, message, uuid) {
+    if (message.status_code != Soup.KnownStatusCode.OK) {
+        logExtensionError(uuid, 'downloading extension: ' + message.status_code);
+        return;
+    }
+
+    // FIXME: use a GFile mkstemp-type method once one exists
+    let fd, tmpzip;
+    try {
+        [fd, tmpzip] = GLib.file_open_tmp('XXXXXX.shell-extension.zip');
+    } catch (e) {
+        logExtensionError(uuid, 'tempfile: ' + e.toString());
+        return;
+    }
+
+    let stream = new Gio.UnixOutputStream({ fd: fd });
+    let dir = userExtensionsDir.get_child(uuid);
+    Shell.write_soup_message_to_stream(stream, message);
+    stream.close(null);
+    let [success, pid] = GLib.spawn_async(null,
+                                          ['unzip', '-uod', dir.get_path(), '--', tmpzip],
+                                          null,
+                                          GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
+                                          null);
+
+    if (!success) {
+        logExtensionError(uuid, 'extract: could not extract');
+        return;
+    }
+
+    GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
+        GLib.spawn_close_pid(pid);
+        loadExtension(dir, true, ExtensionType.PER_USER);
+    });
+}
+
 function disableExtension(uuid) {
     let meta = extensionMeta[uuid];
     if (!meta)
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index ae679ad..07f2881 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -43,6 +43,10 @@ const GnomeShellIface = {
               { name: 'DisableExtension',
                 inSignature: 's',
                 outSignature: ''
+              },
+              { name: 'InstallRemoteExtension',
+                inSignature: 's',
+                outSignature: ''
               }
              ],
     signals: [],
@@ -166,6 +170,10 @@ GnomeShell.prototype = {
         global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
     },
 
+    InstallRemoteExtension: function(uuid, url) {
+        ExtensionSystem.installExtensionFromManifestURL(uuid, url);
+    },
+
     get OverviewActive() {
         return Main.overview.visible;
     },



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]