summaryrefslogtreecommitdiffstats
path: root/tools/EventClients/lib/python/zeroconf.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /tools/EventClients/lib/python/zeroconf.py
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/EventClients/lib/python/zeroconf.py')
-rw-r--r--tools/EventClients/lib/python/zeroconf.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/tools/EventClients/lib/python/zeroconf.py b/tools/EventClients/lib/python/zeroconf.py
new file mode 100644
index 0000000..ee2af14
--- /dev/null
+++ b/tools/EventClients/lib/python/zeroconf.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2008-2013 Team XBMC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""
+Simple wrapper around Avahi
+"""
+
+__author__ = "d4rk@xbmc.org"
+__version__ = "0.1"
+
+try:
+ import time
+ import dbus, avahi
+ from dbus import DBusException
+ from dbus.mainloop.glib import DBusGMainLoop
+ from gi.repository import GLib
+except Exception as e:
+ print("Zeroconf support disabled. To enable, install the following Python modules:")
+ print(" dbus, gi, avahi")
+ pass
+
+SERVICE_FOUND = 1
+SERVICE_LOST = 2
+
+class Browser:
+ """ Simple Zeroconf Browser """
+
+ def __init__( self, service_types = {} ):
+ """
+ service_types - dictionary of services => handlers
+ """
+ self._stop = False
+ self.loop = DBusGMainLoop()
+ self.bus = dbus.SystemBus( mainloop=self.loop )
+ self.server = dbus.Interface( self.bus.get_object( avahi.DBUS_NAME, '/' ),
+ 'org.freedesktop.Avahi.Server')
+ self.handlers = {}
+
+ for type in service_types.keys():
+ self.add_service( type, service_types[ type ] )
+
+
+ def add_service( self, type, handler = None ):
+ """
+ Add a service that the browser should watch for
+ """
+ self.sbrowser = dbus.Interface(
+ self.bus.get_object(
+ avahi.DBUS_NAME,
+ self.server.ServiceBrowserNew(
+ avahi.IF_UNSPEC,
+ avahi.PROTO_UNSPEC,
+ type,
+ 'local',
+ dbus.UInt32(0)
+ )
+ ),
+ avahi.DBUS_INTERFACE_SERVICE_BROWSER)
+ self.handlers[ type ] = handler
+ self.sbrowser.connect_to_signal("ItemNew", self._new_item_handler)
+ self.sbrowser.connect_to_signal("ItemRemove", self._remove_item_handler)
+
+
+ def run(self):
+ """
+ Run the GLib event loop
+ """
+ # Don't use loop.run() because Python's GIL will block all threads
+ loop = GLib.MainLoop()
+ context = loop.get_context()
+ while not self._stop:
+ if context.pending():
+ context.iteration( True )
+ else:
+ time.sleep(1)
+
+ def stop(self):
+ """
+ Stop the GLib event loop
+ """
+ self._stop = True
+
+
+ def _new_item_handler(self, interface, protocol, name, stype, domain, flags):
+ if flags & avahi.LOOKUP_RESULT_LOCAL:
+ # local service, skip
+ pass
+
+ self.server.ResolveService(
+ interface,
+ protocol,
+ name,
+ stype,
+ domain,
+ avahi.PROTO_UNSPEC,
+ dbus.UInt32(0),
+ reply_handler = self._service_resolved_handler,
+ error_handler = self._error_handler
+ )
+ return
+
+
+ def _remove_item_handler(self, interface, protocol, name, stype, domain, flags):
+ if self.handlers[ stype ]:
+ # FIXME: more details needed here
+ try:
+ self.handlers[ stype ]( SERVICE_LOST, { 'type' : stype, 'name' : name } )
+ except:
+ pass
+
+
+ def _service_resolved_handler( self, *args ):
+ service = {}
+ service['type'] = str( args[3] )
+ service['name'] = str( args[2] )
+ service['address'] = str( args[7] )
+ service['hostname'] = str( args[5] )
+ service['port'] = int( args[8] )
+
+ # if the service type has a handler call it
+ try:
+ if self.handlers[ args[3] ]:
+ self.handlers[ args[3] ]( SERVICE_FOUND, service )
+ except:
+ pass
+
+
+ def _error_handler( self, *args ):
+ print('ERROR: %s ' % str( args[0] ))
+
+
+if __name__ == "__main__":
+ def service_handler( found, service ):
+ print("---------------------")
+ print(['Found Service', 'Lost Service'][found-1])
+ for key in service.keys():
+ print(key+" : "+str( service[key] ))
+
+ browser = Browser( {
+ '_xbmc-events._udp' : service_handler,
+ '_xbmc-web._tcp' : service_handler
+ } )
+ browser.run()
+