columba/python/interface_lookup.py
torlando-tech 9b0d0715ca fix: resolve announce interface identification when transport is disabled
The announce_table in RNS is only populated when transport mode is enabled.
On non-transport nodes, interface extraction always returned None, causing
announces to show "Unknown" interface.

Extract interface lookup into python/interface_lookup.py module that checks
announce_table first, then falls back to path_table (which is always
populated regardless of transport mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:31:10 -05:00

74 lines
2.7 KiB
Python

"""
Interface Lookup for Columba
Resolves the receiving interface name for an announce by looking up RNS
internal tables. Checks announce_table first (populated when transport is
enabled), then falls back to path_table (always populated for every announce).
This fixes interface identification on non-transport nodes where the
announce_table is never populated by RNS.
"""
from typing import Optional
from logging_utils import log_debug
def format_interface_name(interface_obj) -> Optional[str]:
"""
Format an RNS interface object into a "ClassName[UserConfiguredName]" string.
Args:
interface_obj: A Reticulum interface object, or None.
Returns:
Formatted string like "TCPInterface[Testnet/1.2.3.4:4242]", or None.
"""
if not interface_obj:
return None
class_name = type(interface_obj).__name__
user_name = getattr(interface_obj, 'name', None)
if user_name and user_name != class_name:
return f"{class_name}[{user_name}]"
return class_name
def get_receiving_interface(destination_hash, announce_table=None, path_table=None) -> Optional[str]:
"""
Extract the receiving interface name for an announce destination hash.
Checks announce_table first (has the full packet, populated when transport
is enabled), then falls back to path_table (always populated for every
announce regardless of transport mode).
Args:
destination_hash: Raw bytes destination hash.
announce_table: RNS.Transport.announce_table dict (or None).
path_table: RNS.Transport.path_table dict (or None).
Returns:
Formatted interface name string, or None if unavailable.
"""
try:
# Try announce_table first (populated when transport is enabled)
if announce_table is not None:
announce_entry = announce_table.get(destination_hash)
if announce_entry is not None and len(announce_entry) > 5:
packet = announce_entry[5] # IDX_AT_PACKET
if packet and hasattr(packet, 'receiving_interface'):
name = format_interface_name(packet.receiving_interface)
if name:
return name
# Fallback to path_table (always populated, stores interface directly at index 5)
if path_table is not None:
path_entry = path_table.get(destination_hash)
if path_entry is not None and len(path_entry) > 5:
interface_obj = path_entry[5] # IDX_PT_RVCD_IF
name = format_interface_name(interface_obj)
if name:
return name
except Exception as e:
log_debug("InterfaceLookup", "get_receiving_interface",
f"Could not extract interface: {e}")
return None