[gnome-shell/wip/smartcard: 14/16] misc: add objectManager class



commit e3fdc2858dd53f7027d0ea913e5a85f77c05851c
Author: Ray Strode <rstrode redhat com>
Date:   Thu May 30 10:15:09 2013 -0400

    misc: add objectManager class
    
    The D-Bus ObjectManager interface is fairly recent addition to the
    D-Bus specification. Its purpose is to provide a standardized way
    to track objects dynamically coming and going for a service, and
    to track capabilities dynamically coming and going for those objects
    (by means of interfaces).
    
    This commit adds the requisite code needed to make use of the
    ObjectManager interface.
    
    It will ultimately be needed to implement smartcard support in the
    login screen.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=683437

 js/Makefile.am           |    1 +
 js/misc/objectManager.js |  275 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 0 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index 86fa470..d7de072 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -34,6 +34,7 @@ nobase_dist_js_DATA =         \
        misc/jsParse.js         \
        misc/loginManager.js    \
        misc/modemManager.js    \
+       misc/objectManager.js   \
        misc/params.js          \
        misc/util.js            \
        perf/core.js            \
diff --git a/js/misc/objectManager.js b/js/misc/objectManager.js
new file mode 100644
index 0000000..77a5470
--- /dev/null
+++ b/js/misc/objectManager.js
@@ -0,0 +1,275 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Lang = imports.lang;
+const Params = imports.misc.params;
+const Signals = imports.signals;
+
+// Specified in the D-Bus specification here:
+// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
+const ObjectManagerIface = <interface name="org.freedesktop.DBus.ObjectManager">
+  <method name="GetManagedObjects">
+    <arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
+  </method>
+  <signal name="InterfacesAdded">
+    <arg name="objectPath" type="o"/>
+    <arg name="interfaces" type="a{sa{sv}}" />
+  </signal>
+  <signal name="InterfacesRemoved">
+    <arg name="objectPath" type="o"/>
+    <arg name="interfaces" type="as" />
+  </signal>
+</interface>
+
+const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
+
+const ObjectManager = new Lang.Class({
+    Name: 'ObjectManager',
+    _init: function(params) {
+        params = Params.parse(params, { connection: null,
+                                        name: null,
+                                        objectPath: null,
+                                        knownInterfaces: null,
+                                        cancellable: null,
+                                        onLoaded: null });
+
+        this._connection = params.connection;
+        this._serviceName = params.name;
+        this._managerPath = params.objectPath;
+        this._cancellable = params.cancellable;
+
+        this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection,
+                                                 g_interface_name: ObjectManagerInfo.name,
+                                                 g_interface_info: ObjectManagerInfo,
+                                                 g_name: this._serviceName,
+                                                 g_object_path: this._managerPath,
+                                                 g_flags: Gio.DBusProxyFlags.NONE });
+
+        this._interfaceInfos = {};
+        this._objects = {};
+        this._interfaces = {};
+        this._pendingProxies = [];
+        this._onLoaded = params.onLoaded;
+
+        if (params.knownInterfaces)
+            this._registerInterfaces(params.knownInterfaces);
+
+        this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
+                                      this._cancellable,
+                                      Lang.bind(this, this._onManagerProxyLoaded));
+    },
+
+    _addInterface: function(objectPath, interfaceName, onFinished) {
+        let info = this._interfaceInfos[interfaceName];
+
+        if (!info)
+            return;
+
+        let proxy = new Gio.DBusProxy({ g_connection: this._connection,
+                                        g_name: this._serviceName,
+                                        g_object_path: objectPath,
+                                        g_interface_name: interfaceName,
+                                        g_interface_info: info,
+                                        g_flags: Gio.DBusProxyFlags.NONE });
+
+        this._pendingProxies.push(proxy);
+
+        proxy.init_async(GLib.PRIORITY_DEFAULT,
+                         this._cancellable,
+                         Lang.bind(this, function(initable, result) {
+                             let index = this._pendingProxies.indexOf(proxy);
+
+                             if (index >= 0)
+                                 this._pendingProxies.splice(index, 1);
+
+                             let error = null;
+                             try {
+                                 initable.init_finish(result);
+                             } catch(e) {
+                                 logError(e, 'could not initialize proxy for interface ' + interfaceName);
+
+                                 if (onFinished)
+                                     onFinished();
+                                 return;
+                             }
+
+                             let isNewObject;
+
+                             if (!this._objects[objectPath]) {
+                                 this._objects[objectPath] = {};
+                                 isNewObject = true;
+                             } else {
+                                 isNewObject = false;
+                             }
+
+                             this._objects[objectPath][interfaceName] = proxy;
+
+                             if (!this._interfaces[interfaceName])
+                                 this._interfaces[interfaceName] = [];
+
+                             this._interfaces[interfaceName].push(proxy);
+
+                             if (isNewObject)
+                                 this.emit('object-added', objectPath);
+
+                             this.emit('interface-added', interfaceName, proxy);
+
+                             if (onFinished)
+                                 onFinished();
+                         }));
+    },
+
+    _removeInterface: function(objectPath, interfaceName) {
+        if (!this._objects[objectPath])
+            return;
+
+        let proxy = this._objects[objectPath][interfaceName];
+
+        if (this._interfaces[interfaceName]) {
+            let index = this._interfaces[interfaceName].indexOf(proxy);
+
+            if (index >= 0)
+                this._interfaces[interfaceName].splice(index, 1);
+
+            if (this._interfaces[interfaceName].length == 0)
+                delete this._interfaces[interfaceName];
+        }
+
+        this.emit('interface-removed', interfaceName, proxy);
+
+        this._objects[objectPath][interfaceName] = null;
+
+        if (Object.keys(this._objects[objectPath]).length == 0) {
+            delete this._objects[objectPath];
+            this.emit('object-removed', objectPath);
+        }
+    },
+
+    _onManagerProxyLoaded: function(initable, result) {
+        let error = null;
+        try {
+            initable.init_finish(result);
+        } catch(e) {
+            logError(e, 'could not initialize object manager for object ' + params.name);
+
+            if (this._onLoaded)
+                this._onLoaded();
+            return;
+        }
+
+        this._managerProxy.connectSignal('InterfacesAdded',
+                                         Lang.bind(this, function(objectManager, sender, [objectPath, 
interfaces]) {
+                                             let interfaceNames = Object.keys(interfaces);
+                                             for (let i = 0; i < interfaceNames.length; i++)
+                                                 this._addInterface(objectPath, interfaceNames[i]);
+                                         }));
+        this._managerProxy.connectSignal('InterfacesRemoved',
+                                         Lang.bind(this, function(objectManager, sender, [objectPath, 
interfaceNames]) {
+                                             for (let i = 0; i < interfaceNames.length; i++)
+                                                 this._removeInterface(objectPath, interfaceNames[i]);
+                                         }));
+
+
+        this._managerProxy.GetManagedObjectsRemote(Lang.bind(this, function(result, error) {
+            if (!result) {
+                if (error) {
+                   logError(error, 'could not get remote objects for service ' + this._serviceName + ' path 
' + this._managerPath);
+                }
+
+                if (this._onLoaded)
+                    this._onLoaded();
+                return;
+            }
+
+            let [objects] = result;
+
+            if (Object.keys(this._interfaceInfos).length == 0) {
+                if (this._onLoaded)
+                    this._onLoaded();
+                return;
+            }
+
+            let numLoadInhibitors = 0;
+
+            // First inhibitor is to prevent onLoaded from getting
+            // called until all interfaces have started being added.
+            // Subsequent inhibitors are to prevent onLoaded from getting
+            // called until all interfaces finish getting added.
+            numLoadInhibitors++;
+            let objectPaths = Object.keys(objects);
+            for (let i = 0; i < objectPaths.length; i++) {
+                let objectPath = objectPaths[i];
+                let object = objects[objectPath];
+
+                let interfaceNames = Object.keys(object);
+                for (let j = 0; j < interfaceNames.length; j++) {
+                    let interfaceName = interfaceNames[j];
+
+                    numLoadInhibitors++;
+                    this._addInterface(objectPath,
+                                       interfaceName,
+                                       Lang.bind(this, function() {
+                                           numLoadInhibitors--;
+
+                                           if (numLoadInhibitors == 0) {
+                                               if (this._onLoaded)
+                                                   this._onLoaded();
+                                           }
+                                       }));
+                }
+            }
+            numLoadInhibitors--;
+
+            if (numLoadInhibitors == 0) {
+                if (this._onLoaded)
+                    this._onLoaded();
+            }
+        }));
+    },
+
+    _registerInterfaces: function(interfaces) {
+        for (let i = 0; i < interfaces.length; i++) {
+            let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]);
+
+            this._interfaceInfos[info.name] = info;
+        }
+    },
+
+    getProxy: function(objectPath, interfaceName) {
+        let object = this._objects[objectPath];
+
+        if (!object)
+            return null;
+
+        return object[interfaceName];
+    },
+
+    getProxiesForInterface: function(interfaceName) {
+        let proxyList = this._interfaces[interfaceName];
+
+        if (!proxyList)
+            return [];
+
+        return proxyList;
+    },
+
+    getAllProxies: function() {
+        let proxies = [];
+
+        let objectPaths = Object.keys(this._objects);
+        for (let i = 0; i < objectPaths.length; i++) {
+            let object = this._objects[objectPaths];
+
+            let interfaceNames = Object.keys(object);
+            for (let j = 0; i < interfaceNames.length; i++) {
+                let interfaceName = interfaceNames[i];
+                if (object[interfaceName])
+                    proxies.push(object(interfaceName));
+            }
+        }
+
+        return proxies;
+    }
+});
+Signals.addSignalMethods(ObjectManager.prototype);


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