Blame js/misc/objectManager.js

Packit Service ed5168
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
Packit Service ed5168
Packit Service ed5168
const { Gio, GLib } = imports.gi;
Packit Service ed5168
const Params = imports.misc.params;
Packit Service ed5168
const Signals = imports.signals;
Packit Service ed5168
Packit Service ed5168
// Specified in the D-Bus specification here:
Packit Service ed5168
// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
Packit Service ed5168
const ObjectManagerIface = `
Packit Service ed5168
<node>
Packit Service ed5168
<interface name="org.freedesktop.DBus.ObjectManager">
Packit Service ed5168
  <method name="GetManagedObjects">
Packit Service ed5168
    <arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
Packit Service ed5168
  </method>
Packit Service ed5168
  <signal name="InterfacesAdded">
Packit Service ed5168
    <arg name="objectPath" type="o"/>
Packit Service ed5168
    <arg name="interfaces" type="a{sa{sv}}" />
Packit Service ed5168
  </signal>
Packit Service ed5168
  <signal name="InterfacesRemoved">
Packit Service ed5168
    <arg name="objectPath" type="o"/>
Packit Service ed5168
    <arg name="interfaces" type="as" />
Packit Service ed5168
  </signal>
Packit Service ed5168
</interface>
Packit Service ed5168
</node>`;
Packit Service ed5168
Packit Service ed5168
const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
Packit Service ed5168
Packit Service ed5168
var ObjectManager = class {
Packit Service ed5168
    constructor(params) {
Packit Service ed5168
        params = Params.parse(params, { connection: null,
Packit Service ed5168
                                        name: null,
Packit Service ed5168
                                        objectPath: null,
Packit Service ed5168
                                        knownInterfaces: null,
Packit Service ed5168
                                        cancellable: null,
Packit Service ed5168
                                        onLoaded: null });
Packit Service ed5168
Packit Service ed5168
        this._connection = params.connection;
Packit Service ed5168
        this._serviceName = params.name;
Packit Service ed5168
        this._managerPath = params.objectPath;
Packit Service ed5168
        this._cancellable = params.cancellable;
Packit Service ed5168
Packit Service ed5168
        this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection,
Packit Service ed5168
                                                 g_interface_name: ObjectManagerInfo.name,
Packit Service ed5168
                                                 g_interface_info: ObjectManagerInfo,
Packit Service ed5168
                                                 g_name: this._serviceName,
Packit Service ed5168
                                                 g_object_path: this._managerPath,
Packit Service ed5168
                                                 g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
Packit Service ed5168
Packit Service ed5168
        this._interfaceInfos = {};
Packit Service ed5168
        this._objects = {};
Packit Service ed5168
        this._interfaces = {};
Packit Service ed5168
        this._onLoaded = params.onLoaded;
Packit Service ed5168
Packit Service ed5168
        if (params.knownInterfaces)
Packit Service ed5168
            this._registerInterfaces(params.knownInterfaces);
Packit Service ed5168
Packit Service ed5168
        // Start out inhibiting load until at least the proxy
Packit Service ed5168
        // manager is loaded and the remote objects are fetched
Packit Service ed5168
        this._numLoadInhibitors = 1;
Packit Service ed5168
        this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
Packit Service ed5168
                                      this._cancellable,
Packit Service ed5168
                                      this._onManagerProxyLoaded.bind(this));
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _tryToCompleteLoad() {
Packit Service ed5168
        if (this._numLoadInhibitors == 0)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        this._numLoadInhibitors--;
Packit Service ed5168
        if (this._numLoadInhibitors == 0) {
Packit Service ed5168
            if (this._onLoaded)
Packit Service ed5168
                this._onLoaded();
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _addInterface(objectPath, interfaceName, onFinished) {
Packit Service ed5168
        let info = this._interfaceInfos[interfaceName];
Packit Service ed5168
Packit Service ed5168
        if (!info) {
Packit Service ed5168
           if (onFinished)
Packit Service ed5168
               onFinished();
Packit Service ed5168
           return;
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        let proxy = new Gio.DBusProxy({ g_connection: this._connection,
Packit Service ed5168
                                       g_name: this._serviceName,
Packit Service ed5168
                                       g_object_path: objectPath,
Packit Service ed5168
                                       g_interface_name: interfaceName,
Packit Service ed5168
                                       g_interface_info: info,
Packit Service ed5168
                                       g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
Packit Service ed5168
Packit Service ed5168
        proxy.init_async(GLib.PRIORITY_DEFAULT,
Packit Service ed5168
                         this._cancellable,
Packit Service ed5168
                         (initable, result) => {
Packit Service ed5168
               let error = null;
Packit Service ed5168
               try {
Packit Service ed5168
                   initable.init_finish(result);
Packit Service ed5168
               } catch(e) {
Packit Service ed5168
                   logError(e, 'could not initialize proxy for interface ' + interfaceName);
Packit Service ed5168
Packit Service ed5168
                   if (onFinished)
Packit Service ed5168
                       onFinished();
Packit Service ed5168
                   return;
Packit Service ed5168
               }
Packit Service ed5168
Packit Service ed5168
               let isNewObject;
Packit Service ed5168
               if (!this._objects[objectPath]) {
Packit Service ed5168
                   this._objects[objectPath] = {};
Packit Service ed5168
                   isNewObject = true;
Packit Service ed5168
               } else {
Packit Service ed5168
                   isNewObject = false;
Packit Service ed5168
               }
Packit Service ed5168
Packit Service ed5168
               this._objects[objectPath][interfaceName] = proxy;
Packit Service ed5168
Packit Service ed5168
               if (!this._interfaces[interfaceName])
Packit Service ed5168
                   this._interfaces[interfaceName] = [];
Packit Service ed5168
Packit Service ed5168
               this._interfaces[interfaceName].push(proxy);
Packit Service ed5168
Packit Service ed5168
               if (isNewObject)
Packit Service ed5168
                   this.emit('object-added', objectPath);
Packit Service ed5168
Packit Service ed5168
               this.emit('interface-added', interfaceName, proxy);
Packit Service ed5168
Packit Service ed5168
               if (onFinished)
Packit Service ed5168
                   onFinished();
Packit Service ed5168
        });
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _removeInterface(objectPath, interfaceName) {
Packit Service ed5168
        if (!this._objects[objectPath])
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        let proxy = this._objects[objectPath][interfaceName];
Packit Service ed5168
Packit Service ed5168
        if (this._interfaces[interfaceName]) {
Packit Service ed5168
            let index = this._interfaces[interfaceName].indexOf(proxy);
Packit Service ed5168
Packit Service ed5168
            if (index >= 0)
Packit Service ed5168
                this._interfaces[interfaceName].splice(index, 1);
Packit Service ed5168
Packit Service ed5168
            if (this._interfaces[interfaceName].length == 0)
Packit Service ed5168
                delete this._interfaces[interfaceName];
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        this.emit('interface-removed', interfaceName, proxy);
Packit Service ed5168
Packit Service ed5168
        this._objects[objectPath][interfaceName] = null;
Packit Service ed5168
Packit Service ed5168
        if (Object.keys(this._objects[objectPath]).length == 0) {
Packit Service ed5168
            delete this._objects[objectPath];
Packit Service ed5168
            this.emit('object-removed', objectPath);
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onManagerProxyLoaded(initable, result) {
Packit Service ed5168
        let error = null;
Packit Service ed5168
        try {
Packit Service ed5168
            initable.init_finish(result);
Packit Service ed5168
        } catch(e) {
Packit Service ed5168
            logError(e, 'could not initialize object manager for object ' + this._serviceName);
Packit Service ed5168
Packit Service ed5168
            this._tryToCompleteLoad();
Packit Service ed5168
            return;
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        this._managerProxy.connectSignal('InterfacesAdded',
Packit Service ed5168
                                         (objectManager, sender, [objectPath, interfaces]) => {
Packit Service ed5168
                                             let interfaceNames = Object.keys(interfaces);
Packit Service ed5168
                                             for (let i = 0; i < interfaceNames.length; i++)
Packit Service ed5168
                                                 this._addInterface(objectPath, interfaceNames[i]);
Packit Service ed5168
                                         });
Packit Service ed5168
        this._managerProxy.connectSignal('InterfacesRemoved',
Packit Service ed5168
                                         (objectManager, sender, [objectPath, interfaceNames]) => {
Packit Service ed5168
                                             for (let i = 0; i < interfaceNames.length; i++)
Packit Service ed5168
                                                 this._removeInterface(objectPath, interfaceNames[i]);
Packit Service ed5168
                                         });
Packit Service ed5168
Packit Service ed5168
        if (Object.keys(this._interfaceInfos).length == 0) {
Packit Service ed5168
            this._tryToCompleteLoad();
Packit Service ed5168
            return;
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        this._managerProxy.connect('notify::g-name-owner', () => {
Packit Service ed5168
            if (this._managerProxy.g_name_owner)
Packit Service ed5168
                this._onNameAppeared();
Packit Service ed5168
            else
Packit Service ed5168
                this._onNameVanished();
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        if (this._managerProxy.g_name_owner)
Packit Service ed5168
            this._onNameAppeared();
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onNameAppeared() {
Packit Service ed5168
        this._managerProxy.GetManagedObjectsRemote((result, error) => {
Packit Service ed5168
            if (!result) {
Packit Service ed5168
                if (error) {
Packit Service ed5168
                   logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
Packit Service ed5168
                }
Packit Service ed5168
Packit Service ed5168
                this._tryToCompleteLoad();
Packit Service ed5168
                return;
Packit Service ed5168
            }
Packit Service ed5168
Packit Service ed5168
            let [objects] = result;
Packit Service ed5168
Packit Service ed5168
            if (!objects) {
Packit Service ed5168
                this._tryToCompleteLoad();
Packit Service ed5168
                return;
Packit Service ed5168
            }
Packit Service ed5168
Packit Service ed5168
            let objectPaths = Object.keys(objects);
Packit Service ed5168
            for (let i = 0; i < objectPaths.length; i++) {
Packit Service ed5168
                let objectPath = objectPaths[i];
Packit Service ed5168
                let object = objects[objectPath];
Packit Service ed5168
Packit Service ed5168
                let interfaceNames = Object.getOwnPropertyNames(object);
Packit Service ed5168
                for (let j = 0; j < interfaceNames.length; j++) {
Packit Service ed5168
                    let interfaceName = interfaceNames[j];
Packit Service ed5168
Packit Service ed5168
                    // Prevent load from completing until the interface is loaded
Packit Service ed5168
                    this._numLoadInhibitors++;
Packit Service ed5168
                    this._addInterface(objectPath,
Packit Service ed5168
                                       interfaceName,
Packit Service ed5168
                                       this._tryToCompleteLoad.bind(this));
Packit Service ed5168
                }
Packit Service ed5168
            }
Packit Service ed5168
            this._tryToCompleteLoad();
Packit Service ed5168
        });
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _onNameVanished() {
Packit Service ed5168
        let objectPaths = Object.keys(this._objects);
Packit Service ed5168
        for (let i = 0; i < objectPaths.length; i++) {
Packit Service ed5168
            let objectPath = objectPaths[i];
Packit Service ed5168
            let object = this._objects[objectPath];
Packit Service ed5168
Packit Service ed5168
            let interfaceNames = Object.keys(object);
Packit Service ed5168
            for (let j = 0; j < interfaceNames.length; j++) {
Packit Service ed5168
                let interfaceName = interfaceNames[j];
Packit Service ed5168
Packit Service ed5168
                if (object[interfaceName])
Packit Service ed5168
                    this._removeInterface(objectPath, interfaceName);
Packit Service ed5168
            }
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _registerInterfaces(interfaces) {
Packit Service ed5168
        for (let i = 0; i < interfaces.length; i++) {
Packit Service ed5168
            let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]);
Packit Service ed5168
            this._interfaceInfos[info.name] = info;
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    getProxy(objectPath, interfaceName) {
Packit Service ed5168
        let object = this._objects[objectPath];
Packit Service ed5168
Packit Service ed5168
        if (!object)
Packit Service ed5168
            return null;
Packit Service ed5168
Packit Service ed5168
        return object[interfaceName];
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    getProxiesForInterface(interfaceName) {
Packit Service ed5168
        let proxyList = this._interfaces[interfaceName];
Packit Service ed5168
Packit Service ed5168
        if (!proxyList)
Packit Service ed5168
            return [];
Packit Service ed5168
Packit Service ed5168
        return proxyList;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    getAllProxies() {
Packit Service ed5168
        let proxies = [];
Packit Service ed5168
Packit Service ed5168
        let objectPaths = Object.keys(this._objects);
Packit Service ed5168
        for (let i = 0; i < objectPaths.length; i++) {
Packit Service ed5168
            let object = this._objects[objectPaths];
Packit Service ed5168
Packit Service ed5168
            let interfaceNames = Object.keys(object);
Packit Service ed5168
            for (let j = 0; j < interfaceNames.length; j++) {
Packit Service ed5168
                let interfaceName = interfaceNames[j];
Packit Service ed5168
                if (object[interfaceName])
Packit Service ed5168
                    proxies.push(object(interfaceName));
Packit Service ed5168
            }
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        return proxies;
Packit Service ed5168
    }
Packit Service ed5168
};
Packit Service ed5168
Signals.addSignalMethods(ObjectManager.prototype);