diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /tools/EventClients/lib/python/zeroconf.py | |
parent | Initial commit. (diff) | |
download | kodi-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.py | 160 |
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() + |