Merge pull request #25 from rightup/feat/discover

This PR implements control packet handling for repeater discovery, via the new packet type (0x0B CONTROL) and handler for zero-hop packets.
This commit is contained in:
Lloyd
2025-11-27 14:10:01 -08:00
committed by GitHub
2 changed files with 85 additions and 0 deletions
+5
View File
@@ -34,6 +34,11 @@ repeater:
# Recommended: 10 hours for typical deployments
send_advert_interval_hours: 10
# Respond to discovery requests from other nodes
# When enabled, the repeater will automatically respond to discovery packets
# with its node information (node type 2 - repeater)
allow_discovery: true
# Mesh Network Configuration
mesh:
# Global flood policy - controls whether the repeater allows or denies flooding by default
+80
View File
@@ -116,6 +116,13 @@ class RepeaterDaemon:
)
logger.info("Trace handler registered for network diagnostics")
allow_discovery = self.config.get("repeater", {}).get("allow_discovery", True)
if allow_discovery:
self._setup_discovery_handler()
logger.info("Discovery response handler enabled")
else:
logger.info("Discovery response handler disabled")
except Exception as e:
@@ -281,6 +288,79 @@ class RepeaterDaemon:
except Exception as e:
logger.error(f"[TraceHandler] Error processing trace packet: {e}")
def _setup_discovery_handler(self):
"""Set up discovery request/response handling."""
try:
from pymc_core.node.handlers.control import ControlHandler
self.control_handler = ControlHandler(log_fn=logger.info)
self.dispatcher.register_handler(
ControlHandler.payload_type(),
self._control_callback,
)
# Node type 2 = Repeater
node_type = 2
def on_discovery_request(request_data: dict):
"""Handle incoming discovery request."""
try:
tag = request_data.get("tag", 0)
filter_byte = request_data.get("filter", 0)
prefix_only = request_data.get("prefix_only", False)
snr = request_data.get("snr", 0.0)
rssi = request_data.get("rssi", 0)
logger.info(f"[Discovery] Request: tag=0x{tag:08X}, filter=0x{filter_byte:02X}, SNR={snr:+.1f}dB, RSSI={rssi}dBm")
# Check if filter matches our node type (repeater = 2, filter_mask = 0x04)
filter_mask = 1 << node_type # 1 << 2 = 0x04
if (filter_byte & filter_mask) == 0:
logger.debug("[Discovery] Filter doesn't match, ignoring")
return
logger.info("[Discovery] Sending response...")
if self.local_identity:
our_pub_key = self.local_identity.get_public_key()
from pymc_core.protocol.packet_builder import PacketBuilder
response_packet = PacketBuilder.create_discovery_response(
tag=tag,
node_type=node_type,
inbound_snr=snr,
pub_key=our_pub_key,
prefix_only=prefix_only,
)
# Send response asynchronously
asyncio.create_task(self._send_discovery_response(response_packet, tag))
else:
logger.warning("[Discovery] No local identity available for response")
except Exception as e:
logger.error(f"[Discovery] Error handling request: {e}")
self.control_handler.set_request_callback(on_discovery_request)
logger.debug("[Discovery] Handler registered")
except Exception as e:
logger.error(f"Failed to setup discovery handler: {e}")
async def _control_callback(self, packet):
if self.control_handler:
await self.control_handler(packet)
async def _send_discovery_response(self, packet, tag):
try:
success = await self.dispatcher.send_packet(packet, wait_for_ack=False)
if success:
logger.info(f"[Discovery] Response sent for tag 0x{tag:08X}")
else:
logger.warning(f"[Discovery] Failed to send response for tag 0x{tag:08X}")
except Exception as e:
logger.error(f"[Discovery] Error sending response: {e}")
def get_stats(self) -> dict: