[gnome-shell] dbusServices: Add some base classes for small stand-alone services
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] dbusServices: Add some base classes for small stand-alone services
- Date: Thu, 12 Mar 2020 16:16:29 +0000 (UTC)
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]