128 lines
3.8 KiB
Python
Executable File
128 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""BackOne system tray — opens /app UI and addon deep links."""
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import threading
|
|
import urllib.request
|
|
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
try:
|
|
gi.require_version('AyatanaAppIndicator3', '0.1')
|
|
from gi.repository import AyatanaAppIndicator3 as AppIndicator3
|
|
except (ImportError, ValueError):
|
|
gi.require_version('AppIndicator3', '0.1')
|
|
from gi.repository import AppIndicator3
|
|
|
|
from gi.repository import GLib, Gtk
|
|
|
|
APP_URL = os.environ.get('BACKONE_APP_URL', 'http://127.0.0.1:9993/app/')
|
|
HEALTH_URL = os.environ.get('BACKONE_HEALTH_URL', 'http://127.0.0.1:9993/health')
|
|
ICON_NAME = 'network-workgroup'
|
|
|
|
|
|
class BackOneTray:
|
|
def __init__(self):
|
|
self._windows = []
|
|
self.indicator = AppIndicator3.Indicator.new(
|
|
'backone-tray',
|
|
ICON_NAME,
|
|
AppIndicator3.IndicatorCategory.APPLICATION_STATUS,
|
|
)
|
|
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
|
|
self.indicator.set_menu(self._build_menu())
|
|
try:
|
|
self.indicator.connect('activate', lambda *_: self._open_url(APP_URL))
|
|
except TypeError:
|
|
pass
|
|
self._update_status()
|
|
GLib.timeout_add_seconds(30, self._on_timer)
|
|
|
|
def _build_menu(self):
|
|
menu = Gtk.Menu()
|
|
|
|
def add_item(label, callback):
|
|
item = Gtk.MenuItem(label=label)
|
|
item.connect('activate', lambda *_: callback())
|
|
item.show()
|
|
menu.append(item)
|
|
return item
|
|
|
|
add_item('Open BackOne App', lambda: self._open_url(APP_URL))
|
|
add_item('Voice', lambda: self._open_url(APP_URL + '#/voice'))
|
|
add_item('Video', lambda: self._open_url(APP_URL + '#/video'))
|
|
add_item('Chat', lambda: self._open_url(APP_URL + '#/chat'))
|
|
menu.append(Gtk.SeparatorMenuItem())
|
|
add_item('Restart BackOne Service', self._restart_service)
|
|
add_item('Quit Tray', Gtk.main_quit)
|
|
menu.show()
|
|
return menu
|
|
|
|
def _service_ok(self):
|
|
try:
|
|
with urllib.request.urlopen(HEALTH_URL, timeout=2) as resp:
|
|
return resp.status == 200
|
|
except Exception:
|
|
return False
|
|
|
|
def _update_status(self):
|
|
title = 'BackOne (online)' if self._service_ok() else 'BackOne (offline)'
|
|
self.indicator.set_title(title)
|
|
|
|
def _on_timer(self):
|
|
self._update_status()
|
|
return True
|
|
|
|
def _open_url(self, url):
|
|
if self._try_webkit(url):
|
|
return
|
|
for cmd in (
|
|
['xdg-open', url],
|
|
['gio', 'open', url],
|
|
['sensible-browser', url],
|
|
):
|
|
try:
|
|
subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
return
|
|
except OSError:
|
|
continue
|
|
|
|
def _try_webkit(self, url):
|
|
try:
|
|
gi.require_version('WebKit2', '4.1')
|
|
except ValueError:
|
|
try:
|
|
gi.require_version('WebKit2', '4.0')
|
|
except ValueError:
|
|
return False
|
|
from gi.repository import WebKit2
|
|
|
|
win = Gtk.Window(title='BackOne')
|
|
win.set_default_size(900, 640)
|
|
view = WebKit2.WebView()
|
|
view.load_uri(url)
|
|
win.add(view)
|
|
win.connect('destroy', lambda w: self._windows.remove(w) if w in self._windows else None)
|
|
self._windows.append(win)
|
|
win.show_all()
|
|
return True
|
|
|
|
def _restart_service(self):
|
|
subprocess.Popen(
|
|
['pkexec', 'systemctl', 'restart', 'backone'],
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
|
|
|
|
def main():
|
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
BackOneTray()
|
|
Gtk.main()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|