edouard@4039: #!/usr/bin/env python edouard@4039: # -*- coding: utf-8 -*- edouard@4039: edouard@4039: # See COPYING file for copyrights details. edouard@4039: edouard@4039: import weakref edouard@4039: from zeroconf import ServiceBrowser, Zeroconf, get_all_addresses edouard@4039: import threading edouard@4039: edouard@4039: service_type = '_Beremiz._tcp.local.' edouard@4039: edouard@4039: class ZeroConfListenerClass: edouard@4039: def __init__(self, dialog): edouard@4039: self.dialog = weakref.ref(dialog) edouard@4039: edouard@4039: self.IfacesMonitorState = None edouard@4039: self.IfacesMonitorTimer = None edouard@4039: self.Browser = None edouard@4039: self.ZeroConfInstance = None edouard@4039: self.PublishedServices = set() edouard@4039: edouard@4039: self.start() edouard@4039: edouard@4039: def __del__(self): edouard@4039: self.stop() edouard@4039: edouard@4039: def start(self): edouard@4039: self.ZeroConfInstance = Zeroconf() edouard@4039: self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self) edouard@4039: # Start the ifaces_monitor timer thread edouard@4039: self.IfacesMonitorTimer = threading.Timer(1.0, self.ifaces_monitor) edouard@4039: self.IfacesMonitorTimer.start() edouard@4039: edouard@4039: def stop(self): edouard@4039: if self.IfacesMonitorTimer is not None: edouard@4039: self.IfacesMonitorTimer.cancel() edouard@4039: self.IfacesMonitorTimer = None edouard@4039: edouard@4039: if self.Browser is not None: edouard@4039: self.Browser.cancel() edouard@4039: self.Browser = None edouard@4039: edouard@4039: if self.ZeroConfInstance is not None: edouard@4039: self.ZeroConfInstance.close() edouard@4039: self.ZeroConfInstance = None edouard@4039: edouard@4039: def update_service(self, zeroconf, _type, name): edouard@4039: self.remove_service(zeroconf, _type, name) edouard@4039: self.add_service(zeroconf, _type, name) edouard@4039: edouard@4039: def add_service(self, zeroconf, _type, name): edouard@4039: dialog = self.dialog() edouard@4039: if not dialog: edouard@4039: return edouard@4039: edouard@4039: info = self.ZeroConfInstance.get_service_info(_type, name) edouard@4039: if info is None: edouard@4039: return edouard@4039: edouard@4039: typename = info.properties.get(b"protocol", None).decode() edouard@4039: ip = str(info.parsed_addresses()[0]) edouard@4039: port = info.port edouard@4039: dialog.addService(typename, ip, port, name) edouard@4039: self.PublishedServices.add(name) edouard@4039: edouard@4039: def remove_service(self, zeroconf, _type, name): edouard@4039: dialog = self.dialog() edouard@4039: if not dialog: edouard@4039: return edouard@4039: edouard@4039: if name in self.PublishedServices: edouard@4039: dialog.removeService(name) edouard@4039: self.PublishedServices.discard(name) edouard@4039: edouard@4039: def ifaces_monitor(self): edouard@4039: dialog = self.dialog() edouard@4039: if not dialog: edouard@4039: return edouard@4039: edouard@4039: NewState = get_all_addresses() edouard@4039: OldState = self.IfacesMonitorState edouard@4039: self.IfacesMonitorState = NewState edouard@4039: do_restart = False edouard@4039: edouard@4039: if OldState is not None: edouard@4039: # detect if a new address appeared edouard@4039: for addr in NewState: edouard@4039: if addr not in OldState: edouard@4039: do_restart = True edouard@4039: break edouard@4039: else: edouard@4039: OldState.remove(addr) edouard@4039: # detect if an address disappeared edouard@4039: if len(OldState) > 0: edouard@4039: do_restart = True edouard@4039: edouard@4039: edouard@4039: if do_restart: edouard@4039: self.stop() edouard@4039: edouard@4039: while self.PublishedServices: edouard@4039: dialog.removeService(self.PublishedServices.pop()) edouard@4039: edouard@4039: self.start() edouard@4039: else: edouard@4039: # Restart the ifaces_monitor timer thread edouard@4039: self.IfacesMonitorTimer = threading.Timer(1.0, self.ifaces_monitor) edouard@4039: self.IfacesMonitorTimer.start()