From 5658042a7ea273cf3f0c853b1b3fd04abf9bbf51 Mon Sep 17 00:00:00 2001 From: "Maciek \"mab122\" Bator" Date: Fri, 24 Apr 2026 11:57:44 +0200 Subject: [PATCH] fix: wrap announce handlers in _AnnounceHandler objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RNS.Transport.register_announce_handler silently ignores raw callables — it only accepts objects with both `aspect_filter` attribute and `received_announce` method. Both bridge and gossip were registering bound methods directly, so no announces ever fired. Co-Authored-By: Claude Sonnet 4.6 --- src/radicle_reticulum/bridge.py | 13 ++++++++++++- src/radicle_reticulum/gossip.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/radicle_reticulum/bridge.py b/src/radicle_reticulum/bridge.py index eef5a10..57e113c 100644 --- a/src/radicle_reticulum/bridge.py +++ b/src/radicle_reticulum/bridge.py @@ -87,6 +87,17 @@ class TunnelConnection: pass +class _AnnounceHandler: + """Wraps a callback into the object interface RNS.Transport requires.""" + aspect_filter = f"{APP_NAME}.{ASPECT_BRIDGE}" + + def __init__(self, callback): + self._callback = callback + + def received_announce(self, destination_hash, announced_identity, app_data): + self._callback(destination_hash, announced_identity, app_data) + + class RadicleBridge: """Bridges Radicle TCP connections over Reticulum. @@ -188,7 +199,7 @@ class RadicleBridge: self._running = True # Register announce handler to discover other bridges - RNS.Transport.register_announce_handler(self._handle_announce) + RNS.Transport.register_announce_handler(_AnnounceHandler(self._handle_announce)) RNS.log("Registered announce handler for bridge discovery", RNS.LOG_INFO) # Load persisted NIDs first so radicle-node is ready for reconnects diff --git a/src/radicle_reticulum/gossip.py b/src/radicle_reticulum/gossip.py index 003b3bb..9a4ffe0 100644 --- a/src/radicle_reticulum/gossip.py +++ b/src/radicle_reticulum/gossip.py @@ -37,6 +37,17 @@ PATH_REQUEST_TIMEOUT = 15 # seconds to wait for a path before giving up WATCHDOG_DEBOUNCE = 2.0 # seconds to absorb rapid filesystem events before polling +class _AnnounceHandler: + """Wraps a callback into the object interface RNS.Transport requires.""" + aspect_filter = f"{APP_NAME}.{ASPECT_GOSSIP}" + + def __init__(self, callback): + self._callback = callback + + def received_announce(self, destination_hash, announced_identity, app_data): + self._callback(destination_hash, announced_identity, app_data) + + def _radicle_storage_path() -> Path: """Return ~/.radicle/storage, using 'rad path' if available.""" try: @@ -155,7 +166,7 @@ class GossipRelay: def start(self): """Start the relay: announce, begin polling, register announce handler.""" self._running = True - RNS.Transport.register_announce_handler(self._on_announce) + RNS.Transport.register_announce_handler(_AnnounceHandler(self._on_announce)) self.announce() threading.Thread(target=self._startup_announce_loop, daemon=True).start() self._start_watcher()