import logging import socket from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser, ServiceStateChange logger = logging.getLogger() class ZeroconfServer: service_type = None server_name = None server_port = None server_ip = None zeroconf = Zeroconf() service_info = None client_cache = {} properties = {} @classmethod def configure(cls, service_type, server_name, server_port): cls.service_type = service_type cls.server_name = server_name cls.server_port = server_port @classmethod def start(cls, listen_only=False): if not listen_only: cls._register_service() cls._browse_services() @classmethod def stop(cls): cls._unregister_service() cls.zeroconf.close() @classmethod def _register_service(cls): cls.server_ip = socket.gethostbyname(socket.gethostname()) info = ServiceInfo( cls.service_type, f"{cls.server_name}.{cls.service_type}", addresses=[socket.inet_aton(cls.server_ip)], port=cls.server_port, properties=cls.properties, ) cls.service_info = info cls.zeroconf.register_service(info) logger.info(f"Registered zeroconf service: {cls.service_info.name}") @classmethod def _unregister_service(cls): if cls.service_info: cls.zeroconf.unregister_service(cls.service_info) logger.info(f"Unregistered zeroconf service: {cls.service_info.name}") cls.service_info = None @classmethod def _browse_services(cls): browser = ServiceBrowser(cls.zeroconf, cls.service_type, [cls._on_service_discovered]) @classmethod def _on_service_discovered(cls, zeroconf, service_type, name, state_change): info = zeroconf.get_service_info(service_type, name) logger.debug(f"Zeroconf: {name} {state_change}") if service_type == cls.service_type: if state_change == ServiceStateChange.Added or state_change == ServiceStateChange.Updated: cls.client_cache[name] = info else: cls.client_cache.pop(name) @classmethod def found_clients(cls): return [x.split(f'.{cls.service_type}')[0] for x in cls.client_cache.keys()] # Example usage: if __name__ == "__main__": ZeroconfServer.configure("_zordon._tcp.local.", "foobar.local", 8080) try: ZeroconfServer.start() input("Server running - Press enter to end") finally: ZeroconfServer.stop()