73 lines
2.5 KiB
Python
73 lines
2.5 KiB
Python
"""Live service monitor — like `avahi-browse` without -t.
|
|
|
|
Prints events as they happen:
|
|
+ service appeared
|
|
= service appeared and was resolved (address:port)
|
|
- service disappeared
|
|
|
|
With no --type it browses the DNS-SD meta-service
|
|
(`_services._dns-sd._udp.local.`) to discover types dynamically and attaches a
|
|
browser to each — the equivalent of `avahi-browse -a`.
|
|
"""
|
|
import time
|
|
|
|
from zeroconf import Zeroconf, ServiceBrowser, ServiceListener
|
|
|
|
|
|
class _EventListener(ServiceListener):
|
|
def __init__(self, resolve: bool = True) -> None:
|
|
self.resolve = resolve
|
|
|
|
def add_service(self, zc: Zeroconf, type_: str, name: str) -> None: # noqa: N802
|
|
line = f"+ {type_:<30} {name}"
|
|
if self.resolve:
|
|
info = zc.get_service_info(type_, name, timeout=1500)
|
|
if info:
|
|
addrs = ", ".join(info.parsed_addresses() or []) or "-"
|
|
line = f"= {type_:<30} {name} {addrs}:{info.port}"
|
|
print(line, flush=True)
|
|
|
|
def update_service(self, zc: Zeroconf, type_: str, name: str) -> None: # noqa: N802
|
|
return
|
|
|
|
def remove_service(self, zc: Zeroconf, type_: str, name: str) -> None: # noqa: N802
|
|
print(f"- {type_:<30} {name}", flush=True)
|
|
|
|
|
|
class _TypeSpawner(ServiceListener):
|
|
"""On discovering a new service TYPE, attach a browser for it."""
|
|
|
|
def __init__(self, zc: Zeroconf, svc_listener: ServiceListener) -> None:
|
|
self.zc = zc
|
|
self.svc_listener = svc_listener
|
|
self.browsers: dict[str, ServiceBrowser] = {}
|
|
|
|
def add_service(self, zc: Zeroconf, type_: str, name: str) -> None: # noqa: N802
|
|
# For the meta-service, `name` is the discovered type (e.g. _http._tcp.local.)
|
|
if name not in self.browsers:
|
|
self.browsers[name] = ServiceBrowser(zc, name, self.svc_listener)
|
|
|
|
def update_service(self, *a) -> None: # noqa: N802
|
|
return
|
|
|
|
def remove_service(self, *a) -> None: # noqa: N802
|
|
return
|
|
|
|
|
|
def watch(service_type: str | None = None, resolve: bool = True) -> None:
|
|
zc = Zeroconf()
|
|
svc = _EventListener(resolve=resolve)
|
|
try:
|
|
if service_type:
|
|
ServiceBrowser(zc, service_type, svc)
|
|
else:
|
|
ServiceBrowser(zc, "_services._dns-sd._udp.local.",
|
|
_TypeSpawner(zc, svc))
|
|
print("[mdns] watching — Ctrl+C to stop", flush=True)
|
|
while True:
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
finally:
|
|
zc.close()
|