fix: wrap announce handlers in _AnnounceHandler objects

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 <noreply@anthropic.com>
This commit is contained in:
Maciek "mab122" Bator 2026-04-24 11:57:44 +02:00
parent fd6c1b4f05
commit 5658042a7e
2 changed files with 24 additions and 2 deletions

View File

@ -87,6 +87,17 @@ class TunnelConnection:
pass 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: class RadicleBridge:
"""Bridges Radicle TCP connections over Reticulum. """Bridges Radicle TCP connections over Reticulum.
@ -188,7 +199,7 @@ class RadicleBridge:
self._running = True self._running = True
# Register announce handler to discover other bridges # 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) RNS.log("Registered announce handler for bridge discovery", RNS.LOG_INFO)
# Load persisted NIDs first so radicle-node is ready for reconnects # Load persisted NIDs first so radicle-node is ready for reconnects

View File

@ -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 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: def _radicle_storage_path() -> Path:
"""Return ~/.radicle/storage, using 'rad path' if available.""" """Return ~/.radicle/storage, using 'rad path' if available."""
try: try:
@ -155,7 +166,7 @@ class GossipRelay:
def start(self): def start(self):
"""Start the relay: announce, begin polling, register announce handler.""" """Start the relay: announce, begin polling, register announce handler."""
self._running = True self._running = True
RNS.Transport.register_announce_handler(self._on_announce) RNS.Transport.register_announce_handler(_AnnounceHandler(self._on_announce))
self.announce() self.announce()
threading.Thread(target=self._startup_announce_loop, daemon=True).start() threading.Thread(target=self._startup_announce_loop, daemon=True).start()
self._start_watcher() self._start_watcher()