[gnome-shell] dbusServices: Add some base classes for small stand-alone services



commit 574c560677e71963d604c16e7c3ca55b5f75fefb
Author: Florian Müllner <fmuellner gnome org>
Date:   Wed Mar 4 03:06:57 2020 +0100

    dbusServices: Add some base classes for small stand-alone services
    
    There are a couple of D-Bus services that are currently provided by
    gnome-shell for which it makes sense to move them fully or partially
    into separate processes:
    
     - screen recording (performance)
     - FDO notifications (security)
     - Extensions (portalization)
    
    Add some base classes and build system glue to take care of the
    common boilerplate.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/547

 js/dbusServices/dbus-service.in         |   5 +
 js/dbusServices/dbus-service.service.in |   3 +
 js/dbusServices/dbusService.js          | 159 ++++++++++++++++++++++++++++++++
 js/dbusServices/meson.build             |  40 ++++++++
 js/meson.build                          |   1 +
 meson.build                             |   1 +
 6 files changed, 209 insertions(+)
---
diff --git a/js/dbusServices/dbus-service.in b/js/dbusServices/dbus-service.in
new file mode 100644
index 0000000000..524166102d
--- /dev/null
+++ b/js/dbusServices/dbus-service.in
@@ -0,0 +1,5 @@
+imports.package.start({
+    name: '@PACKAGE_NAME@',
+    prefix: '@prefix@',
+    libdir: '@libdir@',
+});
diff --git a/js/dbusServices/dbus-service.service.in b/js/dbusServices/dbus-service.service.in
new file mode 100644
index 0000000000..3b0d09abec
--- /dev/null
+++ b/js/dbusServices/dbus-service.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=@service@
+Exec=@gjs@ @pkgdatadir@/@service@
diff --git a/js/dbusServices/dbusService.js b/js/dbusServices/dbusService.js
new file mode 100644
index 0000000000..21b8f9c4bf
--- /dev/null
+++ b/js/dbusServices/dbusService.js
@@ -0,0 +1,159 @@
+/* exported DBusService, ServiceImplementation */
+
+const { Gio, GLib } = imports.gi;
+
+const Signals = imports.signals;
+
+const IDLE_SHUTDOWN_TIME = 2; // s
+
+var ServiceImplementation = class {
+    constructor(info, objectPath) {
+        this._objectPath = objectPath;
+        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(info, this);
+
+        this._injectTracking('return_dbus_error');
+        this._injectTracking('return_error_literal');
+        this._injectTracking('return_gerror');
+        this._injectTracking('return_value');
+        this._injectTracking('return_value_with_unix_fd_list');
+
+        this._senders = new Map();
+
+        this._hasSignals = this._dbusImpl.get_info().signals.length > 0;
+        this._shutdownTimeoutId = 0;
+
+        // subclasses may override this to disable automatic shutdown
+        this._autoShutdown = true;
+    }
+
+    // subclasses may override this to own additional names
+    register() {
+    }
+
+    export() {
+        this._dbusImpl.export(Gio.DBus.session, this._objectPath);
+    }
+
+    unexport() {
+        this._dbusImpl.unexport();
+    }
+
+    /**
+     * _handleError:
+     * @param {Gio.DBusMethodInvocation}
+     * @param {Error}
+     *
+     * Complete @invocation with an appropriate error if @error is set;
+     * useful for implementing early returns from method implementations.
+     *
+     * @returns {bool} - true if @invocation was completed
+     */
+
+    _handleError(invocation, error) {
+        if (error === null)
+            return false;
+
+        if (error instanceof GLib.Error) {
+            invocation.return_gerror(error);
+        } else {
+            let name = error.name;
+            if (!name.includes('.')) // likely a normal JS error
+                name = `org.gnome.gjs.JSError.${name}`;
+            invocation.return_dbus_error(name, error.message);
+        }
+
+        return true;
+    }
+
+    _maybeShutdown() {
+        if (!this._autoShutdown)
+            return;
+
+        if (this._senders.size > 0)
+            return;
+
+        this.emit('shutdown');
+    }
+
+    _queueShutdownCheck() {
+        if (this._shutdownTimeoutId)
+            GLib.source_remove(this._shutdownTimeoutId);
+
+        this._shutdownTimeoutId = GLib.timeout_add_seconds(
+            GLib.PRIORITY_DEFAULT, IDLE_SHUTDOWN_TIME,
+            () => {
+                this._shutdownTimeoutId = 0;
+                this._maybeShutdown();
+
+                return GLib.SOURCE_REMOVE;
+            });
+    }
+
+    _trackSender(sender) {
+        if (this._senders.has(sender))
+            return;
+
+        this._senders.set(sender,
+            this._dbusImpl.get_connection().watch_name(
+                sender,
+                Gio.BusNameWatcherFlags.NONE,
+                null,
+                () => this._untrackSender(sender)));
+    }
+
+    _untrackSender(sender) {
+        const id = this._senders.get(sender);
+
+        if (id)
+            this._dbusImpl.get_connection().unwatch_name(id);
+
+        if (this._senders.delete(sender))
+            this._queueShutdownCheck();
+    }
+
+    _injectTracking(methodName) {
+        const { prototype } = Gio.DBusMethodInvocation;
+        const origMethod = prototype[methodName];
+        const that = this;
+
+        prototype[methodName] = function (...args) {
+            origMethod.apply(this, args);
+
+            if (that._hasSignals)
+                that._trackSender(this.get_sender());
+
+            that._queueShutdownCheck();
+        };
+    }
+};
+Signals.addSignalMethods(ServiceImplementation.prototype);
+
+var DBusService = class {
+    constructor(name, service) {
+        this._name = name;
+        this._service = service;
+        this._loop = new GLib.MainLoop(null, false);
+
+        this._service.connect('shutdown', () => this._loop.quit());
+    }
+
+    run() {
+        // Bail out when not running under gnome-shell
+        Gio.DBus.watch_name(Gio.BusType.SESSION,
+            'org.gnome.Shell',
+            Gio.BusNameWatcherFlags.NONE,
+            null,
+            () => this._loop.quit());
+
+        this._service.register();
+
+        Gio.DBus.own_name(Gio.BusType.SESSION,
+            this._name,
+            Gio.BusNameOwnerFlags.REPLACE,
+            () => this._service.export(),
+            null,
+            () => this._loop.quit());
+
+        this._loop.run();
+    }
+};
diff --git a/js/dbusServices/meson.build b/js/dbusServices/meson.build
new file mode 100644
index 0000000000..c2c4d6392f
--- /dev/null
+++ b/js/dbusServices/meson.build
@@ -0,0 +1,40 @@
+launcherconf = configuration_data()
+launcherconf.set('PACKAGE_NAME', meson.project_name())
+launcherconf.set('prefix', prefix)
+launcherconf.set('libdir', libdir)
+
+dbus_services = {
+}
+
+config_dir = '@0@/..'.format(meson.current_build_dir())
+
+foreach service, dir : dbus_services
+  configure_file(
+    input: 'dbus-service.in',
+    output: service,
+    configuration: launcherconf,
+    install_dir: pkgdatadir,
+  )
+
+  serviceconf = configuration_data()
+  serviceconf.set('service', service)
+  serviceconf.set('gjs', gjs.path())
+  serviceconf.set('pkgdatadir', pkgdatadir)
+
+  configure_file(
+    input: 'dbus-service.service.in',
+    output: service + '.service',
+    configuration: serviceconf,
+    install_dir: servicedir
+  )
+
+  gnome.compile_resources(
+    service + '.src',
+    service + '.src.gresource.xml',
+    dependencies: [config_js],
+    source_dir: ['.', '..', dir, config_dir],
+    gresource_bundle: true,
+    install: true,
+    install_dir: pkgdatadir
+  )
+endforeach
diff --git a/js/meson.build b/js/meson.build
index 4a572c53ff..9a230d65d7 100644
--- a/js/meson.build
+++ b/js/meson.build
@@ -1,4 +1,5 @@
 subdir('misc')
+subdir('dbusServices')
 
 js_resources = gnome.compile_resources(
   'js-resources', 'js-resources.gresource.xml',
diff --git a/meson.build b/meson.build
index 8b22b72157..5d51db668b 100644
--- a/meson.build
+++ b/meson.build
@@ -142,6 +142,7 @@ endif
 mutter_typelibdir = mutter_dep.get_pkgconfig_variable('typelibdir')
 python = find_program('python3')
 sassc = find_program('sassc')
+gjs = find_program('gjs')
 
 cc = meson.get_compiler('c')
 


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