I needed to do service autodiscovery for a digital signage application frontend. The frontend consists of Python3 code and some QML that displays some media elements and an embedded webkit element.
This application needs to find a server that will provide it with provisioning information and later on with the content to display. In order to automate the discovery of possible servers I decided to use Avahi over DBUS.
The ide is to start the application which will then scan for suitable services in the local broadcast domain. Each discovered service is resolved to get its hostname and port and is appended to a ListView. From there the deployer can select which server to use for this display.
Now that the application itself is written using PyQt5, using the QtDbus package was the most sane thing to do. At least I thought so. It turned out that QtDbus is not that simple when used in PyQt5.
So in order to spare others from plucking their hair out over how to wire those
components together when browsing for services, I'm publishing my
implementation. It is tested with PyQt 5.6 and PYthon 3.5. It still has some
rough edges, like to handling the Failure
and CacheExhausted
signals. I also
mirroed it on Github
Gists.
#!/usr/bin/python3
import sys
import logging
import signal
from PyQt5.QtCore import QObject, QVariant, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtDBus import QDBus, QDBusConnection, QDBusInterface, QDBusMessage
from models import Server
logger = logging.getLogger(__name__)
signal.signal(signal.SIGINT, signal.SIG_DFL)
class Service(QObject):
def __init__(
self,
interface,
protocol,
name,
stype,
domain,
host=None,
aprotocol=None,
address=None,
port=None,
txt=None
):
super(Service, self).__init__()
self.interface = interface
self.protocol = protocol
self.name = name
self.stype = stype
self.domain = domain
self.host = host
self.aprotocol = aprotocol
self.address = address
self.port = port
self.txt = txt
def __str__(self):
return '{s.name} ({s.stype}.{s.domain})'.format(s=self)
def __eq__(self, other):
return self.__dict__ == other.__dict__
class Discoverer(QObject):
# Use those signals to get notified of changes in subscribed services
# Emitted when initial scanning of avahi services is done
initialized = pyqtSignal()
# Emitted when a new service for our watched type is found
added = pyqtSignal(Service)
removed = pyqtSignal(Service)
def __init__(self, parent, service, interface=-1, protocol=-1, domain='local'):
super(Discoverer, self).__init__(parent)
self.protocol = protocol
self.bus = QDBusConnection.systemBus()
self.bus.registerObject('/', self)
self.server = QDBusInterface(
'org.freedesktop.Avahi',
'/',
'org.freedesktop.Avahi.Server',
self.bus
)
flags = QVariant(0)
flags.convert(QVariant.UInt)
browser_path = self.server.call(
'ServiceBrowserNew',
interface,
self.protocol,
service,
domain,
flags
)
logger.debug('New ServiceBrowser: {}'.format(browser_path.arguments()))
self.bus.connect(
'org.freedesktop.Avahi',
browser_path.arguments()[0],
'org.freedesktop.Avahi.ServiceBrowser',
'ItemNew',
self.onItemNew
)
self.bus.connect(
'org.freedesktop.Avahi',
browser_path.arguments()[0],
'org.freedesktop.Avahi.ServiceBrowser',
'ItemRemove',
self.onItemRemove
)
self.bus.connect(
'org.freedesktop.Avahi',
browser_path.arguments()[0],
'org.freedesktop.Avahi.ServiceBrowser',
'AllForNow',
self.onAllForNow
)
@pyqtSlot(QDBusMessage)
def onItemNew(self, msg):
logger.debug('Avahi service discovered: {}'.format(msg.arguments()))
flags = QVariant(0)
flags.convert(QVariant.UInt)
resolved = self.server.callWithArgumentList(
QDBus.AutoDetect,
'ResolveService',
[
*msg.arguments()[:5],
self.protocol,
flags
]
).arguments()
logger.debug('Avahi service resolved: {}'.format(resolved))
service = Service(*resolved[:10])
self.added.emit(service)
@pyqtSlot(QDBusMessage)
def onItemRemove(self, msg):
arguments = msg.arguments()
logger.debug('Avahi service removed: {}'.format(arguments))
service = Service(*arguments[:5])
self.removed.emit(service)
@pyqtSlot(QDBusMessage)
def onAllForNow(self, msg):
logger.debug('Avahi emitted all signals for discovered peers')
self.initialized.emit()
# Main Function
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
# Create main app
app = QApplication(sys.argv)
# Create avahi discoverer
d = Discoverer(app, '_workstation._tcp')
# Execute the application and exit
sys.exit(app.exec_())#!/usr/bin/python3
Am letzten Septembertag 2014 ging es um 05:30 von Graz aus auf den Präbichl. Die Sonne war noch nicht ganz über die Berge im Osten aufgegangen, als der Aufsteig begann. Vom Parkplatz beim Präbichlerhof ging es über den Theklasteig rauf auf den Reichensteingipel. Kurz vor 09:00, nach nicht ganz zwei Stunden Aufsteig war ich oben angelengt. Die Aussicht war toll, überall in den Tälern lag noch der Nebel und ich konnte eine unglaubliche Fernsicht geniesen.
Marija Kanizaj hat für uns nicht nur die Fotos auf unserer Hochzeit gemacht, sie hat uns auch mit einem Video-Fotobuch überracht, das nochmal die schönsten Momente dieses Tages zusammenfasst.
Die hochauflösende Version mit 650MB gibt es auch als Download.
Während wir unsere Hochzeitsfotos machen liessen, hatten unsere Gäste die Gelegeneheit, und ein paar Fotos von ihnen als andenken zu schiessen. Der Spass stand dabei natürlich im Vordergrund, weshalb es auch viele Accessoires und Verkleidungen gab. Die dabei entstandenen Aufnahmen möchten wir euch natürlich nicht vorenthalten.
Es ist soweit, unsere Fotografin, Marija Kanizaj, ein wahres Genie hinter der Kamera hat unsere Porträt-Reihe abgeschlossen, die wir am Tag unserer Hochzeit auf Schloss Kornberg aufgenommen haben. Viel Spass beim durchschauen!
Danke an unsere Pyrotechniker, die das tolle Feuerwerk am Abend unserer Hochzeit arrangiert und gefilmt haben!
Die hochauflösende Version mit 700MiB gibt es auch als Download.
Peter, der ja auch mein Beistand auf der Hochzeit war, hat uns seine Fotos übermittelt, hier eine kleine Auswahl und den ersten Fotos aus dem Rittersaal auf Schloss Kornberg.
Wir haben es geschafft! Am 30.05.2014 haben Christina und ich uns auf Schloss Kornberg bei Feldbach vor versammelter Familie und Freunden das Ja-Wort gegeben. Vielen lieben Dank an alle, die dies mit uns gefeiert haben und an alle, die für diesen wundervollen Tag gesorgt haben.
Hier einige erste Eindrücke von unserer Fotografin Marja Kanižaj ...
When you need to deploy software or simply work together with someone from far away you usually have several choices on how to accomplish it. The simple solution is to use something like TeamViewer but if all you need to share is a shell, there an easier way.
using screen it is possible to share a shell session across several SSH sessions. The first thing to do is install screen:
aptitude install screen
Now you have to decide which user should be the host for the shared sessions, i.e. which privileges are required during the session. I would recommend to use an unprivileged user.
Next, ask all your external partners to generate a SSH key pair and send your their public key (preferably in an encrypted email).
For each user who will participate in the shared session, create a separate user
Am 1. November haben wir es mal wieder geschafft, Christine kam am Vortag bereits von der Ramsau nach Kindberg und wir brachen um 05:30 von Kindtal aus auf um beim Sonnenaufgang um 6:40 bereits bei den drei Wetterkreuzen zu sein.
Durch den Nebel, der sich über Nacht im Tal gesammelt hatte, gingen wir vom Sagbauern weg bis wir kurz unterhalb der Wetterkreuze endlich freien Nachthimmel über uns hatten und die Sonne sich schon als heller Schimmer am Horizont ankündigte.
Wir wärmten uns bei den Wetterkreuzen mit Tee auf und mit ca. 5 Minuten Verspätung, der Nebel überzog im Osten noch die Fischbacher Alpen, erschien dann die Sonne langsam über dem Nebel.
Bei doch schon sehr frostigen Temperaturen liessen wir uns kurz in den ersten Sonnenstrahlen am Waldrand nieder und frühstückten, bevor wir dann wieder in den Nebel, 100 Meter unter uns, abstiegen und nach Kindtal zurückkehrten.
This blog is powered by ikiwiki.