"""In-memory registry of connected gossip peers.""" from __future__ import annotations import threading import time from dataclasses import dataclass, field from typing import Any @dataclass class PeerEntry: peer_id: str addr: str ws: Any # websockets.WebSocketServerProtocol connected_at: float = field(default_factory=time.monotonic) last_seen: float = field(default_factory=time.monotonic) class PeerRegistry: def __init__(self): self._peers: dict[str, PeerEntry] = {} self._lock = threading.Lock() def register(self, peer_id: str, addr: str, ws) -> None: with self._lock: self._peers[peer_id] = PeerEntry(peer_id=peer_id, addr=addr, ws=ws) def unregister(self, peer_id: str) -> None: with self._lock: self._peers.pop(peer_id, None) def touch(self, peer_id: str) -> None: with self._lock: if peer_id in self._peers: self._peers[peer_id].last_seen = time.monotonic() def get(self, peer_id: str) -> PeerEntry | None: with self._lock: return self._peers.get(peer_id) def all_except(self, peer_id: str) -> list[PeerEntry]: with self._lock: return [e for pid, e in self._peers.items() if pid != peer_id] def list_peers(self) -> list[dict]: with self._lock: return [ { "peer_id": e.peer_id, "addr": e.addr, "connected_at": e.connected_at, "last_seen": e.last_seen, } for e in self._peers.values() ] def __len__(self) -> int: with self._lock: return len(self._peers)