Remove unfinished web application

It used Broadway as an easy "reuse the same code into web application" way for me, but Broadway
is not very good for this. This feature should be made using some better dedicated framework for
building websites (so it can work better and support different screen sizes).

All the WebSocket functionality needed for this will remain (and be documented at a later point
when expanded and stable), so if anyone would like to make such remote controlling app, will be
free to do so (outside of Clapper code).
This commit is contained in:
Rafał Dzięgiel
2022-02-10 10:22:26 +01:00
parent 54715023c0
commit 83c0e3b598
13 changed files with 15 additions and 458 deletions

View File

@@ -6,4 +6,4 @@ imports.package.init({
prefix: '@prefix@',
libdir: '@libdir@',
});
imports.package.run(imports.src.main@ID_POSTFIX@);
imports.package.run(imports.src.main);

View File

@@ -1,25 +1,19 @@
clapper_apps = ['', 'Remote', 'Daemon']
bin_conf = configuration_data()
foreach id_postfix : clapper_apps
app_postfix = (id_postfix != '') ? '.' + id_postfix : ''
bin_conf.set('GJS', find_program('gjs').path())
bin_conf.set('PACKAGE_NAME', meson.project_name())
bin_conf.set('PACKAGE_VERSION', meson.project_version())
bin_conf.set('prefix', get_option('prefix'))
bin_conf.set('libdir', libdir)
bin_conf = configuration_data()
bin_conf.set('GJS', find_program('gjs').path())
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', libdir)
configure_file(
input: 'com.github.rafostar.Clapper.in',
output: 'com.github.rafostar.Clapper' + app_postfix,
configuration: bin_conf,
install: true,
install_dir: bindir,
install_mode: 'rwxr-xr-x'
)
endforeach
configure_file(
input: 'com.github.rafostar.Clapper.in',
output: 'com.github.rafostar.Clapper',
configuration: bin_conf,
install: true,
install_dir: bindir,
install_mode: 'rwxr-xr-x'
)
clapper_symlink_cmd = 'ln -fs @0@ $DESTDIR@1@'.format(
'com.github.rafostar.Clapper',

View File

@@ -1,25 +0,0 @@
const { GObject } = imports.gi;
const { AppBase } = imports.src.appBase;
const { HeaderBarRemote } = imports.src.headerbarRemote;
const { WidgetRemote } = imports.src.widgetRemote;
var AppRemote = GObject.registerClass({
GTypeName: 'ClapperAppRemote',
},
class ClapperAppRemote extends AppBase
{
vfunc_startup()
{
super.vfunc_startup();
const window = this.active_window;
const clapperWidget = new WidgetRemote();
window.set_child(clapperWidget);
const headerBar = new HeaderBarRemote();
window.set_titlebar(headerBar);
window.maximize();
}
});

View File

@@ -1,70 +0,0 @@
const { Gio, GLib, GObject } = imports.gi;
const Debug = imports.src.debug;
const { debug } = Debug;
var Daemon = GObject.registerClass({
GTypeName: 'ClapperDaemon',
},
class ClapperDaemon extends Gio.SubprocessLauncher
{
_init()
{
const port = ARGV[0] || 8080;
/* 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=' + port]);
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();
}
});

View File

@@ -1,22 +0,0 @@
const { GObject } = imports.gi;
const { HeaderBarBase } = imports.src.headerbarBase;
var HeaderBarRemote = GObject.registerClass({
GTypeName: 'ClapperHeaderBarRemote',
},
class ClapperHeaderBarRemote extends HeaderBarBase
{
_init()
{
super._init();
this.extraButtonsBox.visible = false;
}
_onWindowButtonActivate(action)
{
if(action === 'toggle-maximized')
action = 'toggle_maximized';
this.root.child.sendWs(action);
}
});

View File

@@ -1,6 +0,0 @@
const { Daemon } = imports.src.daemon;
function main()
{
new Daemon();
}

View File

@@ -1,19 +0,0 @@
imports.gi.versions.Gdk = '4.0';
imports.gi.versions.Gtk = '4.0';
imports.gi.versions.Soup = '2.4';
pkg.initGettext();
const Misc = imports.src.misc;
Misc.appId += '.Remote';
const { Gtk, Adw } = imports.gi;
const { AppRemote } = imports.src.appRemote;
function main(argv)
{
Gtk.init();
Adw.init();
new AppRemote().run(argv);
}

View File

@@ -3,7 +3,6 @@ const ByteArray = imports.byteArray;
const Debug = imports.src.debug;
const Misc = imports.src.misc;
const { PlaylistWidget } = imports.src.playlist;
const { WebApp } = imports.src.webApp;
const { debug, warn } = Debug;
const { settings } = Misc;
@@ -43,7 +42,6 @@ class ClapperPlayer extends GstClapper.Clapper
this.visualization_enabled = false;
this.webserver = null;
this.webapp = null;
this.playlistWidget = new PlaylistWidget();
this.seekDone = true;
@@ -675,7 +673,6 @@ class ClapperPlayer extends GstClapper.Clapper
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
break;
case 'webserver-enabled':
case 'webapp-enabled':
const webserverEnabled = settings.get_boolean('webserver-enabled');
if(webserverEnabled) {
@@ -690,22 +687,8 @@ class ClapperPlayer extends GstClapper.Clapper
this.webserver.passMsgData = this.receiveWs.bind(this);
}
this.webserver.startListening();
const webappEnabled = settings.get_boolean('webapp-enabled');
if(!this.webapp && !webappEnabled)
break;
if(webappEnabled) {
if(!this.webapp)
this.webapp = new WebApp();
this.webapp.startDaemonApp(settings.get_int('webapp-port'));
}
}
else if(this.webserver) {
/* remote app will close when connection is lost
* which will cause the daemon to close too */
this.webserver.stopListening();
}
break;

View File

@@ -1,51 +0,0 @@
const { GObject } = imports.gi;
const { WebClient } = imports.src.webClient;
var ClapperState = {
STOPPED: 0,
BUFFERING: 1,
PAUSED: 2,
PLAYING: 3,
};
var PlayerRemote = GObject.registerClass({
GTypeName: 'ClapperPlayerRemote',
},
class ClapperPlayerRemote extends GObject.Object
{
_init()
{
super._init();
this.webclient = new WebClient();
}
set_playlist(playlist)
{
const uris = [];
/* We can not send GioFiles via WebSocket */
for(let source of playlist)
uris.push(this._getSourceUri(source));
this.webclient.sendMessage({
action: 'set_playlist',
value: uris
});
}
set_subtitles(source)
{
this.webclient.sendMessage({
action: 'set_subtitles',
value: this._getSourceUri(source)
});
}
_getSourceUri(source)
{
return (source.get_uri != null)
? source.get_uri()
: source;
}
});

View File

@@ -1,51 +0,0 @@
const { Gio, GObject } = imports.gi;
const Debug = imports.src.debug;
const Misc = imports.src.misc;
const { debug } = Debug;
var WebApp = GObject.registerClass({
GTypeName: 'ClapperWebApp',
},
class ClapperWebApp extends Gio.SubprocessLauncher
{
_init()
{
const flags = Gio.SubprocessFlags.STDOUT_SILENCE
| Gio.SubprocessFlags.STDERR_SILENCE;
super._init({ flags });
this.daemonApp = null;
}
startDaemonApp(port)
{
if(this.daemonApp)
return;
this.daemonApp = this.spawnv([Misc.appId + '.Daemon', String(port)]);
this.daemonApp.wait_async(null, this._onDaemonClosed.bind(this));
debug('daemon app started');
}
_onDaemonClosed(proc, result)
{
let hadError;
try {
hadError = proc.wait_finish(result);
}
catch(err) {
debug(err);
}
this.daemonApp = null;
if(hadError)
debug('daemon app exited with error or was forced to close');
debug('daemon app closed');
}
});

View File

@@ -1,90 +0,0 @@
const { Gio, GObject, Soup } = imports.gi;
const Debug = imports.src.debug;
const Misc = imports.src.misc;
const WebHelpers = imports.src.webHelpers;
const { debug } = Debug;
const { settings } = Misc;
var WebClient = GObject.registerClass({
GTypeName: 'ClapperWebClient',
},
class ClapperWebClient extends Soup.Session
{
_init(port)
{
super._init({
timeout: 3,
use_thread_context: true,
});
this.wsConn = null;
this.connectWebsocket();
}
connectWebsocket()
{
if(this.wsConn)
return;
const port = settings.get_int('webserver-port');
const message = Soup.Message.new('GET', `ws://127.0.0.1:${port}/websocket`);
this.websocket_connect_async(message, null, null, null, this._onWsConnect.bind(this));
debug('connecting WebSocket to Clapper app');
}
sendMessage(data)
{
if(
!this.wsConn
|| this.wsConn.state !== Soup.WebsocketState.OPEN
)
return;
this.wsConn.send_text(JSON.stringify(data));
}
passMsgData(action, value)
{
}
_onWsConnect(session, result)
{
let connection = null;
try {
connection = this.websocket_connect_finish(result);
}
catch(err) {
debug(err);
}
if(!connection)
return this.passMsgData('close');
connection.connect('message', this._onWsMessage.bind(this));
connection.connect('closed', this._onWsClosed.bind(this));
this.wsConn = connection;
debug('successfully connected WebSocket');
}
_onWsMessage(connection, dataType, bytes)
{
const [success, parsedMsg] = WebHelpers.parseData(dataType, bytes);
if(success)
this.passMsgData(parsedMsg.action, parsedMsg.value);
}
_onWsClosed(connection)
{
debug('closed WebSocket connection');
this.wsConn = null;
this.passMsgData('close');
}
});

View File

@@ -1,72 +0,0 @@
const { GObject, Gtk } = imports.gi;
const Buttons = imports.src.buttons;
const Misc = imports.src.misc;
const { PlayerRemote, ClapperState } = imports.src.playerRemote;
var WidgetRemote = GObject.registerClass({
GTypeName: 'ClapperWidgetRemote',
},
class ClapperWidgetRemote extends Gtk.Grid
{
_init(opts)
{
super._init({
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER,
});
Misc.loadCustomCss();
this.player = new PlayerRemote();
this.player.webclient.passMsgData = this.receiveWs.bind(this);
/* FIXME: create better way to add buttons for
* remote app without duplicating too much code */
this.togglePlayButton = new Buttons.IconToggleButton(
'media-playback-start-symbolic',
'media-playback-pause-symbolic'
);
this.togglePlayButton.remove_css_class('flat');
this.togglePlayButton.connect(
'clicked', () => this.sendWs('toggle_play')
);
this.attach(this.togglePlayButton, 0, 0, 1, 1);
}
sendWs(action, value)
{
const data = { action };
/* do not send "null" or "undefined"
* for faster network data transfer */
if(value != null)
data.value = value;
this.player.webclient.sendMessage(data);
}
receiveWs(action, value)
{
switch(action) {
case 'state_changed':
switch(value) {
case ClapperState.STOPPED:
case ClapperState.PAUSED:
this.togglePlayButton.setPrimaryIcon();
break;
case ClapperState.PLAYING:
this.togglePlayButton.setSecondaryIcon();
break;
default:
break;
}
break;
case 'close':
this.root.run_dispose();
break;
default:
break;
}
}
});

View File

@@ -177,20 +177,6 @@
<property name="spin-adjustment">web_server_adjustment</property>
</object>
</child>
<child>
<object class="ClapperPrefsSwitch">
<property name="title" translatable="yes">Run web application in background</property>
<property name="subtitle" translatable="yes">Requires GTK compiled with Broadway backend</property>
<property name="schema-name">webapp-enabled</property>
</object>
</child>
<child>
<object class="ClapperPrefsSpin">
<property name="title" translatable="yes">Web application port</property>
<property name="schema-name">webapp-port</property>
<property name="spin-adjustment">web_app_adjustment</property>
</object>
</child>
</object>
</child>
</object>