diff --git a/snip/sync/discovery.py b/snip/sync/discovery.py index 8b227b7..b92863d 100644 --- a/snip/sync/discovery.py +++ b/snip/sync/discovery.py @@ -1,7 +1,8 @@ """mDNS/Bonjour peer discovery for local network.""" -import asyncio +import json import socket +from pathlib import Path from typing import Any from zeroconf import ServiceInfo, Zeroconf @@ -11,15 +12,22 @@ class DiscoveryService: SERVICE_TYPE = "_snippets._tcp.local." SERVICE_NAME = "snip" - def __init__(self, port: int = 8765): + def __init__(self, port: int = 8765, peer_id: str | None = None): self.port = port + self.peer_id = peer_id or socket.gethostname() self.zeroconf = None self.service_info = None + self._peer_cache_file = Path("~/.snip/peers.json").expanduser() - def register(self, peer_id: str, host: str | None = None): + def register(self, peer_id: str | None = None, host: str | None = None): """Register this peer on the network.""" + if peer_id is None: + peer_id = self.peer_id if host is None: - host = socket.gethostbyname(socket.gethostname()) + try: + host = socket.gethostbyname(socket.gethostname()) + except Exception: + host = "127.0.0.1" self.zeroconf = Zeroconf() self.service_info = ServiceInfo( @@ -27,7 +35,7 @@ class DiscoveryService: f"{self.SERVICE_NAME}_{peer_id}.{self.SERVICE_TYPE}", addresses=[socket.inet_aton(host)], port=self.port, - properties={"peer_id": peer_id}, + properties={"peer_id": peer_id.encode()}, ) self.zeroconf.register_service(self.service_info) @@ -50,9 +58,12 @@ class DiscoveryService: for addr in item.addresses: peer_host = socket.inet_ntoa(addr) peer_id = item.properties.get(b"peer_id", b"").decode() + peer_name = item.name.replace(f".{self.SERVICE_TYPE}", "") peers.append({ "peer_id": peer_id, + "peer_name": peer_name, "host": peer_host, + "addresses": [peer_host], "port": item.port, }) except Exception: @@ -62,19 +73,15 @@ class DiscoveryService: return peers - def discover_peers_async(self, timeout: float = 5.0) -> list[dict[str, Any]]: - """Async version of peer discovery.""" - return asyncio.run(self._discover_async(timeout)) + def save_peer_cache(self, peers: list[dict[str, Any]]): + """Save discovered peers to cache.""" + self._peer_cache_file.parent.mkdir(parents=True, exist_ok=True) + with open(self._peer_cache_file, "w") as f: + json.dump(peers, f) - async def _discover_async(self, timeout: float) -> list[dict[str, Any]]: - peers = [] - zeroconf = Zeroconf() - - try: - await asyncio.sleep(timeout) - except Exception: - pass - finally: - zeroconf.close() - - return peers + def load_peer_cache(self) -> list[dict[str, Any]]: + """Load cached peers.""" + if self._peer_cache_file.exists(): + with open(self._peer_cache_file, "r") as f: + return json.load(f) + return [] \ No newline at end of file