From 84762de76a1c7b5057c802871ac0cad0e6089a3f Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 16 Dec 2020 19:54:30 +0100 Subject: [PATCH] Add Clapper deamon subprocess Daemon is responsible for starting and later watching over spawned "broadwayd" and "remote" app needed for remote playback control. We cannot use systemd n Flatpak, so we make do with running optional background subprocesses. --- ...com.github.rafostar.Clapper.Subprocess.in} | 6 +- bin/meson.build | 13 ++-- clapper_src/daemon.js | 66 +++++++++++++++++++ clapper_src/mainDaemon.js | 6 ++ clapper_src/playerBase.js | 7 +- clapper_src/webApp.js | 36 +++++----- 6 files changed, 104 insertions(+), 30 deletions(-) rename bin/{com.github.rafostar.Clapper.Remote.in => com.github.rafostar.Clapper.Subprocess.in} (69%) create mode 100644 clapper_src/daemon.js create mode 100644 clapper_src/mainDaemon.js diff --git a/bin/com.github.rafostar.Clapper.Remote.in b/bin/com.github.rafostar.Clapper.Subprocess.in similarity index 69% rename from bin/com.github.rafostar.Clapper.Remote.in rename to bin/com.github.rafostar.Clapper.Subprocess.in index 326794ff..b8a463fd 100644 --- a/bin/com.github.rafostar.Clapper.Remote.in +++ b/bin/com.github.rafostar.Clapper.Subprocess.in @@ -3,15 +3,15 @@ /* pkg init enforces the imports path to the folder * named after the pkg name, but I would prefer to have * the bundled subprocess stored in the same directory */ -imports.searchPath.unshift('@datadir@/@PROJECT_NAME@'); +imports.searchPath.unshift('@datadir@/@PACKAGE_NAME@'); const Package = imports.package; Package.init({ - name: '@PACKAGE_NAME@', + name: '@PACKAGE_NAME@.@ID_POSTFIX@', version: '@PACKAGE_VERSION@', prefix: '@prefix@', libdir: '@libdir@', datadir: '@datadir@', }); -Package.run(imports.clapper_src.mainRemote); +Package.run(imports.clapper_src.main@ID_POSTFIX@); diff --git a/bin/meson.build b/bin/meson.build index c36e6978..055bd3cb 100644 --- a/bin/meson.build +++ b/bin/meson.build @@ -1,18 +1,21 @@ -clapper_apps = [ '', '.Remote' ] +clapper_apps = ['', 'Remote', 'Daemon'] foreach id_postfix : clapper_apps + app_postfix = (id_postfix != '') ? '.' + id_postfix : '' + template_type = (id_postfix != '') ? '.Subprocess' : '' + bin_conf = configuration_data() bin_conf.set('GJS', find_program('gjs').path()) - bin_conf.set('PROJECT_NAME', meson.project_name()) - bin_conf.set('PACKAGE_NAME', meson.project_name() + id_postfix) + bin_conf.set('PACKAGE_NAME', meson.project_name()) bin_conf.set('PACKAGE_VERSION', meson.project_version()) + bin_conf.set('ID_POSTFIX', id_postfix) bin_conf.set('prefix', get_option('prefix')) bin_conf.set('libdir', join_paths(get_option('prefix'), get_option('libdir'))) bin_conf.set('datadir', join_paths(get_option('prefix'), get_option('datadir'))) configure_file( - input: 'com.github.rafostar.Clapper' + id_postfix + '.in', - output: 'com.github.rafostar.Clapper' + id_postfix, + input: 'com.github.rafostar.Clapper' + template_type + '.in', + output: 'com.github.rafostar.Clapper' + app_postfix, configuration: bin_conf, install: true, install_dir: get_option('bindir'), diff --git a/clapper_src/daemon.js b/clapper_src/daemon.js new file mode 100644 index 00000000..ce13a8e3 --- /dev/null +++ b/clapper_src/daemon.js @@ -0,0 +1,66 @@ +const { Gio, GLib, GObject } = imports.gi; +const Debug = imports.clapper_src.debug; + +let { debug } = Debug; + +var Daemon = GObject.registerClass( +class ClapperDaemon extends Gio.SubprocessLauncher +{ + _init() + { + /* FIXME: show output when debugging is on */ + const flags = Gio.SubprocessFlags.STDOUT_SILENCE + | Gio.SubprocessFlags.STDERR_SILENCE; + + super._init({ flags }); + + this.errMsg = 'exited with error or was forced to close'; + this.loop = GLib.MainLoop.new(null, false); + + this.broadwayd = this.spawnv(['gtk4-broadwayd', '--port=8086']); + this.broadwayd.wait_async(null, this._onBroadwaydClosed.bind(this)); + + this.setenv('GDK_BACKEND', 'broadway', true); + + const remoteApp = this.spawnv(['com.github.rafostar.Clapper.Remote']); + remoteApp.wait_async(null, this._onRemoteClosed.bind(this)); + + this.loop.run(); + } + + _checkProcResult(proc, result) + { + let hadError = false; + + try { + hadError = proc.wait_finish(result); + } + catch(err) { + debug(err); + } + + return hadError; + } + + _onBroadwaydClosed(proc, result) + { + const hadError = this._checkProcResult(proc, result); + + if(hadError) + debug(`broadwayd ${this.errMsg}`); + + this.broadwayd = null; + this.loop.quit(); + } + + _onRemoteClosed(proc, result) + { + const hadError = this._checkProcResult(proc, result); + + if(hadError) + debug(`remote app ${this.errMsg}`); + + if(this.broadwayd) + this.broadwayd.force_exit(); + } +}); diff --git a/clapper_src/mainDaemon.js b/clapper_src/mainDaemon.js new file mode 100644 index 00000000..93302a4e --- /dev/null +++ b/clapper_src/mainDaemon.js @@ -0,0 +1,6 @@ +const { Daemon } = imports.clapper_src.daemon; + +function main() +{ + new Daemon(); +} diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js index a02ed2e1..35ccf851 100644 --- a/clapper_src/playerBase.js +++ b/clapper_src/playerBase.js @@ -296,13 +296,14 @@ class ClapperPlayerBase extends GstPlayer.Player if(!this.webapp) this.webapp = new WebApp(); - this.webapp.startRemoteApp(); + this.webapp.startDaemonApp(); } else - this.webapp.stopRemoteApp(); + this.webapp.stopDaemonApp(); } else if(this.webserver) { - /* remote app will close too when connection is lost */ + /* remote app will close when connection is lost + * which will cause the daemon to close too */ this.webserver.stopListening(); } break; diff --git a/clapper_src/webApp.js b/clapper_src/webApp.js index e05442d4..ff8ef116 100644 --- a/clapper_src/webApp.js +++ b/clapper_src/webApp.js @@ -14,35 +14,33 @@ class ClapperWebApp extends Gio.SubprocessLauncher super._init({ flags }); - this.remoteApp = null; - this.isRemoteClosing = false; - - this.setenv('GDK_BACKEND', 'broadway', true); + this.daemonApp = null; + this.isDaemonClosing = false; } - startRemoteApp() + startDaemonApp() { - if(this.remoteApp) + if(this.daemonApp) return; - this.remoteApp = this.spawnv([Misc.appId + '.Remote']); - this.remoteApp.wait_async(null, this._onRemoteClosed.bind(this)); + this.daemonApp = this.spawnv([Misc.appId + '.Daemon']); + this.daemonApp.wait_async(null, this._onDaemonClosed.bind(this)); - debug('remote app started'); + debug('daemon app started'); } - stopRemoteApp() + stopDaemonApp() { - if(!this.remoteApp || this.isRemoteClosing) + if(!this.daemonApp || this.isDaemonClosing) return; - this.isRemoteClosing = true; - this.remoteApp.force_exit(); + this.isDaemonClosing = true; + this.daemonApp.force_exit(); - debug('send stop signal to remote app'); + debug('send stop signal to daemon app'); } - _onRemoteClosed(proc, result) + _onDaemonClosed(proc, result) { let hadError; @@ -53,12 +51,12 @@ class ClapperWebApp extends Gio.SubprocessLauncher debug(err); } - this.remoteApp = null; - this.isRemoteClosing = false; + this.daemonApp = null; + this.isDaemonClosing = false; if(hadError) - debug('remote app exited with error'); + debug('daemon app exited with error or was forced to close'); - debug('remote app closed'); + debug('daemon app closed'); } });