diff -r 4b47b4ce0f12 -r 9ff455817691 connectors/ZeroConfListener.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectors/ZeroConfListener.py Mon Nov 18 13:52:40 2024 +0100 @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# See COPYING file for copyrights details. + +import weakref +from zeroconf import ServiceBrowser, Zeroconf, get_all_addresses +import threading + +service_type = '_Beremiz._tcp.local.' + +class ZeroConfListenerClass: + def __init__(self, dialog): + self.dialog = weakref.ref(dialog) + + self.IfacesMonitorState = None + self.IfacesMonitorTimer = None + self.Browser = None + self.ZeroConfInstance = None + self.PublishedServices = set() + + self.start() + + def __del__(self): + self.stop() + + def start(self): + self.ZeroConfInstance = Zeroconf() + self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self) + # Start the ifaces_monitor timer thread + self.IfacesMonitorTimer = threading.Timer(1.0, self.ifaces_monitor) + self.IfacesMonitorTimer.start() + + def stop(self): + if self.IfacesMonitorTimer is not None: + self.IfacesMonitorTimer.cancel() + self.IfacesMonitorTimer = None + + if self.Browser is not None: + self.Browser.cancel() + self.Browser = None + + if self.ZeroConfInstance is not None: + self.ZeroConfInstance.close() + self.ZeroConfInstance = None + + def update_service(self, zeroconf, _type, name): + self.remove_service(zeroconf, _type, name) + self.add_service(zeroconf, _type, name) + + def add_service(self, zeroconf, _type, name): + dialog = self.dialog() + if not dialog: + return + + info = self.ZeroConfInstance.get_service_info(_type, name) + if info is None: + return + + typename = info.properties.get(b"protocol", None).decode() + ip = str(info.parsed_addresses()[0]) + port = info.port + dialog.addService(typename, ip, port, name) + self.PublishedServices.add(name) + + def remove_service(self, zeroconf, _type, name): + dialog = self.dialog() + if not dialog: + return + + if name in self.PublishedServices: + dialog.removeService(name) + self.PublishedServices.discard(name) + + def ifaces_monitor(self): + dialog = self.dialog() + if not dialog: + return + + NewState = get_all_addresses() + OldState = self.IfacesMonitorState + self.IfacesMonitorState = NewState + do_restart = False + + if OldState is not None: + # detect if a new address appeared + for addr in NewState: + if addr not in OldState: + do_restart = True + break + else: + OldState.remove(addr) + # detect if an address disappeared + if len(OldState) > 0: + do_restart = True + + + if do_restart: + self.stop() + + while self.PublishedServices: + dialog.removeService(self.PublishedServices.pop()) + + self.start() + else: + # Restart the ifaces_monitor timer thread + self.IfacesMonitorTimer = threading.Timer(1.0, self.ifaces_monitor) + self.IfacesMonitorTimer.start()