Desktop-Notification von Server- und Hintergrunddienst

Warum Debian und/oder eine seiner Spielarten? Was muss ich vorher wissen? Wo geht es nach der Installation weiter?
Antworten
scientific
Beiträge: 3020
Registriert: 03.11.2009 13:45:23
Lizenz eigener Beiträge: Artistic Lizenz
Kontaktdaten:

Desktop-Notification von Server- und Hintergrunddienst

Beitrag von scientific » 19.12.2017 16:34:07

Hi Leute!

Immer wieder taucht das Problem auf, dass es "nett" wäre, wenn ein Dienst/Server, der von cron oder systemd aus gestartet wird, am Desktop mittels notification bekannt macht, dass er fertig ist.
Dazu findet man zu hauf die Krücke, sich die Umgebungsvariable DBUS_SESSION_BUS_ADDRESS irgendwie zu krallen, das $DISPLAY ebenfalls, dies dann im Service/Skript zu exportieren und dann notify-send von dort aus zu starten.
Das ganze ist und bleibt aber eine Krücke, die dann mal besser, mal schlechter arbeitet.

Ich hab mich jetzt mal eingehender mit dieser Thematik und mit dbus beschäftigt, da ich gerne eine Notification am Desktop für mein Backup-Programm hätte, das von systemd aus gestartet wird. Ich hab zwar für Gnome3 eine Shell-Extension geschrieben, die aber eben nur auf Gnome3 funktioniert. In der Openbox-Session hingegen sehe ich nicht, wann das Backup fertig ist, das auf die externe Platte geschrieben wird...

Nun gut... ich habe ein Lösung gefunden, die dbus so nützt, wie es vorgesehen ist.

Der Service/Cronjob schickt eine Message an den dbus-SessionBus. In ALLEN graphischen Oberflächen aller eingeloggten User lauscht eine Anwendung am SessionBus von dbus, ob eine Message vom Dienst kommt und schickt dann im Falle des Eintreffens eine Notification - wiederum über dbus an den Notification-Daemon.

Das klingt jetzt furchtbar kompliziert, funktioniert aber wunderbar. Mit dieser Lösung muss keine Xauthority, keine Display oder andere Umgebungsvariable gesucht und exportiert werden...

Wichtig ist, dass in der Graphischen Oberfläche ein Notification-Daemon läuft. Bei Gnome ist der sowieso dabei, für Openbox habe ich Debianxfce4-notifiyd installiert. Sollte aber mit jedem anderen (Debiandunst, Debiannotify-osd,...) auch funktionieren.
Testen kann man, ob ein Notification-Daemon läuft, wenn man in einem Terminal einen Befehl abschickt (ggfs. noch Debianlibnotify-bin installieren)

Code: Alles auswählen

notify-send "Bla" "Blubb"
Damit sollte dann eine Informations-Blase am Desktop mit Bla und Blubb aufpoppen. (Bei Gnome ist diese in der Uhr versteckt. Da erscheint neben der Uhr ein Punkt. Klickt man auf die Uhr öffnet sich ein Dropdown, wo die Notification zu sehen ist)

Jetzt brauchen wir den Listener, der am Systembus in der graphischen Oberfläche lauscht und die Notification auf den Session-Bus übersetzt und weiterschickt:
Dazu legt man eine Datei

Code: Alles auswählen

editor /usr/local/bin/dbus-listener.py
mit folgendem Inhalt an:

Code: Alles auswählen

#!/usr/bin/env python

import dbus, dbus.glib
import gtk

systembus = dbus.SystemBus()
sessionbus = dbus.SessionBus()

notifications = dbus.Interface(sessionbus.get_object('org.freedesktop.Notifications',
                                        '/org/freedesktop/Notifications'), 'org.freedesktop.Notifications')

#Funktioniert leider nicht, daher wird das icon hart codiert
#icon = gtk.icon_theme_get_default().lookup_icon("update-none", 22,
#                         gtk.ICON_LOOKUP_USE_BUILTIN).get_filename()
icon = '/usr/share/icons/oxygen/base/48x48/actions/svn-update.png'

def notify_updates(*args):
    notifications.Notify("Anwendungs Name", 0, icon, "Titel: %s" % (args[0]),
            ' '.join(args[1:]),
            "", {}, -1)

systembus.add_signal_receiver(notify_updates, 'signal_name', 'ein.eindeutiger.BusName')

gtk.main()
Dieses Python-Skript muss noch ausführbar gemacht werden

Code: Alles auswählen

chmod +x /usr/local/bin/dbus-listener.py
Damit dieser Listener in jeder gestarteten graphischen Oberfläche auch gestartet wird, kommt ein Starter nach

Code: Alles auswählen

editor /etc/xdg/autostart/dbus-listener.desktop
mit dem Inhalt:

Code: Alles auswählen

[Desktop Entry]
Version=1.0
Name=Notifications service for background services
Name[de]=Benachrichtigungen für Hintergrunddienste
Exec=/usr/local/bin/dbus-listener.py
TryExec=/usr/local/bin/dbus-listener.py
Icon=xfce4-notifyd
Terminal=false
StartupNotify=false
Type=Application
Categories=GTK;Settings;DesktopSettings;
Entweder man startet dieses Skript einmal manuell zum Testen, oder ausloggen und wieder einloggen (dann kann man mit ps überprüfen, ob der Autostarteintrag funktioniert hat!) und testen.

Code: Alles auswählen

dbus-send --system /ein/eindeutiger/BusName ein.eindeutiger.BusName.signal_name string:"Bla" string:"Blubb"
Wichtig ist "--system", damit die Nachricht an den SystemBus gesendet wird. Es erscheint am Desktop die Notification!
Dies kann man als User und als root testen!

Diese Zeile kann man schon in ein Shell-Skript einbauen, welches z.B. von cron aufgerufen wird. Und das genügt schon.

Ich hab ein Python-Skript, mit welchem ich meine Backups erstelle. In Python gibt es ein dbus-Modul, welches ich verwende. Die Dokumentation dazu ist sehr bescheiden. Ich habe eigentlich nur Informationen für den Listener in Python oder eine Sender an den SessionBus gefunden, aber nicht wie ich ein einfaches Signal an den Systembus sende. Und es hat mich viel Zeit gekostet, das herauszufinden.

Und da ist die einfache Lösung:

Code: Alles auswählen

#!/usr/bin/env python3
"""Python 3.6 script. Creates a Notification pop-up bubble"""
import dbus

OPATH = "/ein/eindeutiger/BusName"
IFACE = "ein.eindeutiger.BusName"
BUS_NAME = "ein.eindeutiger.BusName"

def send_signal(bus, path, dbus_interface, signal_name, signature, *args):
    """Send a signal on the bus."""
    message = dbus.lowlevel.SignalMessage(path, dbus_interface, signal_name)
    message.append(signature=signature, *args)
    bus.send_message(message)


if __name__ == "__main__":
    bus = dbus.SystemBus()
    send_signal(bus, OPATH, IFACE, 'signal_name', 'sss', "Titelergänzung", "Body text", "Noch ein Bodytext")
Hier ist anzumerken, dass "signatur" (im Beispiel bei send_signal das Feld mit 'sss') tricky ist. Infos über die möglichen Signaturen hier https://dbus.freedesktop.org/doc/dbus-p ... data-types
Es folgen auf 'sss' 3 Felder, die Strings sind. Daher besteht die Signatur aus 3x 's'. Wäre nur ein Feld mit einer Integerzahl, lautete die signatur 'i'
Wäre das erste Feld ein String, gefolgt von einem Feld das eine Integerzahl ist, schaut die Signatur 'si' aus.

Die Anzahl der Felder und das Format gibt der Listener von oben vor. Ich habe ihn so gebaut, dass das erste Feld in die Titelzeile eingebaut wird. die weiteren Felder werden zu einem String zusammengefügt und bilden den Body der Notification.
Man kann natürlich auch nur einzelne Worte und Zahlen übergeben und die Meldung im Listener daraus zusammenbauen, oder man übergibt gleich den fertigen Meldungstext.

Allgemein zu dbus ist noch zu sagen:
/ein/eindeutiger/BusName: So ist das Format des Pfades (wozu auch immer der benötigt wird)
ein.eindeutiger.BusName: So ist das Format des Busnamens. Es scheint sinnvoll zu sein, dieses dem Pfad anzupassen (mit . statt /). Der Busname kann aber auch ein einziges eindeutiges Wort sein ("alsdkföjasd" z.B)
signal_name: Das wäre die "Funktion", die angesprochen werden soll.

In meinem Fall lauten diese so:
/at/meinedomain/mkbackup bzw. at.meinedomain.mkbackup und der signal_name lautet interval

Das muss in allen Skripten (auch im Einzeiler mit dbus-send) einheitlich sein.
Für dbus-send ist zu beachten, dass der der Pfad /ein/eindeutiger/BusName lautet, beim Busnamen jedoch der signal_name angehängt wird ein.eindeutiger.BusName.signal_name!!!
Ich bin noch dabei, eine Nomenklatur zu entwickeln, dass ich einen "allgemeinen" Listener für solche Hintergrunddienste habe, den ich nicht nur vom Backupskript sinnvoll mit Namen ansprechen kann.

Ich würd mich sehr über Rückmeldungen freuen.
Leider hab ich noch nicht herausgefunden, ob und wie ich Links und Buttons ein die Notification einbauen kann. Denn für mein Backupskript wärs natürlich fein, gleich einen Button zu haben, wo ich im Fileexplorer direkt zum Backup hüpfen kann (oder die Platte auswerfen). Man kann auch sicher irgendwo noch die urgency und Sichtbarkeitsdauer einstellen. Das hab ich auch noch nicht rausgefunden.
Ich bin froh, endlich einmal bei dbus soweit hinter das Konzept gestiegen zu sein, dass ich diese Notification ohne Krücken zum Laufen gebracht habe :)

Anregungen sind gerne erwünscht. Soll ich auch einen Wikiartikel verfassen?

lg scientific
dann putze ich hier mal nur...

Eine Auswahl meiner Skripte und systemd-units.
https://github.com/xundeenergie

auch als Debian-Repo für Testing einbindbar:
deb http://debian.xundeenergie.at/xundeenergie testing main

Benutzeravatar
Datenteiler
Beiträge: 84
Registriert: 12.10.2008 21:01:46
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Hannover
Kontaktdaten:

Re: Desktop-Notification von Server- und Hintergrunddienst

Beitrag von Datenteiler » 19.12.2017 21:58:24

Hi,

ich find's gut. Einen Wiki-Artikel fände ich super. Buttons kann man in Desktop Notifications in Python mit Libnotify einbauen. Ein interessantes Beispiel habe ich bei Stack Overflow gefunden:

Code: Alles auswählen

#!/usr/bin/python -W ignore

import sys

from gi.repository import Notify
from gi.repository import Gtk

if not Notify.init('Notification Test'):
    print("ERROR: Could not init Notify.")
    sys.exit(1)

notification = Notify.Notification.new(
    "Notification Title",
    "Message...")

notification.set_urgency(Notify.Urgency.NORMAL)
def actionCallback(notification, action, user_data = None):
    print("Callback called: "+action)
    Gtk.main_quit()

notification.add_action("test-action", "Test Action", actionCallback)

if not notification.show():
    print("ERROR: Could not show notification.")
    sys.exit(2)

Gtk.main()
Viele Grüße
Christian

scientific
Beiträge: 3020
Registriert: 03.11.2009 13:45:23
Lizenz eigener Beiträge: Artistic Lizenz
Kontaktdaten:

Re: Desktop-Notification von Server- und Hintergrunddienst

Beitrag von scientific » 22.12.2017 09:18:52

Mag das mal jemand nachstellen, damit ich weiß, ob die Infos ausreichend sind?
dann putze ich hier mal nur...

Eine Auswahl meiner Skripte und systemd-units.
https://github.com/xundeenergie

auch als Debian-Repo für Testing einbindbar:
deb http://debian.xundeenergie.at/xundeenergie testing main

Antworten