MeshCLI and RoomServer initialization with identity and storage handler support; update neighbor listing to filter repeaters and zero hop nodes.

This commit is contained in:
Lloyd
2025-12-20 22:03:02 +00:00
parent 6c2c2a13aa
commit f5daf41825
4 changed files with 88 additions and 19 deletions
+2 -1
View File
@@ -557,7 +557,7 @@ class SQLiteHandler:
neighbors = conn.execute("""
SELECT pubkey, node_name, is_repeater, route_type, contact_type,
latitude, longitude, first_seen, last_seen, rssi, snr, advert_count
latitude, longitude, first_seen, last_seen, rssi, snr, advert_count, zero_hop
FROM adverts a1
WHERE last_seen = (
SELECT MAX(last_seen)
@@ -581,6 +581,7 @@ class SQLiteHandler:
"rssi": row["rssi"],
"snr": row["snr"],
"advert_count": row["advert_count"],
"zero_hop": bool(row["zero_hop"]),
}
return result
+63 -5
View File
@@ -16,7 +16,9 @@ class MeshCLI:
save_config_callback: Callable,
identity_type: str = "repeater",
enable_regions: bool = True,
send_advert_callback: Optional[Callable] = None
send_advert_callback: Optional[Callable] = None,
identity = None,
storage_handler = None
):
self.config_path = Path(config_path)
@@ -25,6 +27,8 @@ class MeshCLI:
self.identity_type = identity_type
self.enable_regions = enable_regions
self.send_advert_callback = send_advert_callback
self.identity = identity
self.storage_handler = storage_handler
# Get repeater config shortcut
self.repeater_config = config.get('repeater', {})
@@ -245,8 +249,15 @@ class MeshCLI:
return f"> {power}"
elif param == "public.key":
# TODO: Get from identity
return "Error: Not yet implemented"
if not self.identity:
return "Error: Identity not available"
try:
pubkey = self.identity.get_public_key()
pubkey_hex = pubkey.hex()
return f"> {pubkey_hex}"
except Exception as e:
logger.error(f"Failed to get public key: {e}")
return f"Error: {e}"
elif param == "role":
role = "room_server" if self.identity_type == "room_server" else "repeater"
@@ -498,8 +509,55 @@ class MeshCLI:
def _cmd_neighbors(self) -> str:
"""List neighbors."""
# TODO: Get neighbors from routing table
return "Error: Not yet implemented"
if not self.storage_handler:
return "Error: Storage not available"
try:
neighbors = self.storage_handler.get_neighbors()
if not neighbors:
return "No neighbors discovered yet"
# Filter to only show repeaters and zero hop nodes
filtered_neighbors = {
pubkey: info for pubkey, info in neighbors.items()
if info.get('is_repeater', False) or info.get('zero_hop', False)
}
if not filtered_neighbors:
return "No repeaters or zero hop neighbors discovered yet"
# Format output similar to C++ version
# Format: "<pubkey_prefix> heard Xs ago"
import time
current_time = int(time.time())
lines = []
for pubkey, info in filtered_neighbors.items():
last_seen = info.get('last_seen', 0)
seconds_ago = current_time - last_seen
# Get short pubkey (first 8 chars)
pubkey_short = pubkey[:8] if len(pubkey) >= 8 else pubkey
node_name = info.get('node_name') or 'Unknown'
# Format time ago
if seconds_ago < 60:
time_str = f"{seconds_ago}s ago"
elif seconds_ago < 3600:
time_str = f"{seconds_ago // 60}m ago"
elif seconds_ago < 86400:
time_str = f"{seconds_ago // 3600}h ago"
else:
time_str = f"{seconds_ago // 86400}d ago"
lines.append(f"<{pubkey_short}> {node_name} heard {time_str}")
return "\n".join(lines)
except Exception as e:
logger.error(f"Failed to list neighbors: {e}", exc_info=True)
return f"Error: {e}"
def _cmd_neighbor_remove(self, command: str) -> str:
"""Remove a neighbor."""
+4 -2
View File
@@ -150,9 +150,11 @@ class RoomServer:
save_config_callback,
identity_type="room_server",
enable_regions=False, # Room servers don't support region commands
send_advert_callback=send_room_advert
send_advert_callback=send_room_advert,
identity=local_identity,
storage_handler=sqlite_handler
)
logger.info(f"Room '{room_name}': Initialized CLI handler")
logger.info(f"Room '{room_name}': Initialized CLI handler with identity and storage")
# Enforce hard limit (match C++ MAX_UNSYNCED_POSTS)
if max_posts > MAX_UNSYNCED_POSTS:
+19 -11
View File
@@ -44,18 +44,12 @@ class TextHelper:
self.config = config
self.save_config_callback = save_config_callback
# Initialize CLI handler if config provided
# Store for later CLI initialization (needs identity and storage)
self.config_path = config_path
self.config = config
# Initialize CLI handler later when repeater identity is registered
self.cli = None
if config_path and config and save_config_callback:
self.cli = MeshCLI(
config_path,
config,
save_config_callback,
identity_type="repeater",
enable_regions=True,
send_advert_callback=send_advert_callback
)
logger.info("Initialized CLI handler for repeater commands")
def register_identity(
self,
@@ -98,6 +92,20 @@ class TextHelper:
if identity_type == "repeater":
self.repeater_hash = hash_byte
logger.info(f"Set repeater hash for CLI: 0x{hash_byte:02X}")
# Initialize CLI handler now that we have the repeater identity
if self.config_path and self.config and self.save_config_callback:
self.cli = MeshCLI(
self.config_path,
self.config,
self.save_config_callback,
identity_type="repeater",
enable_regions=True,
send_advert_callback=self.send_advert_callback,
identity=identity,
storage_handler=self.sqlite_handler
)
logger.info("Initialized CLI handler for repeater commands with identity and storage")
# Create RoomServer instance for room_server identities
if identity_type == "room_server" and self.sqlite_handler: