From 2fbe0aff01e2f086672e720303b74a92129ceea0 Mon Sep 17 00:00:00 2001 From: agessaman Date: Thu, 1 Oct 2026 01:45:54 -0700 Subject: [PATCH] refactor: one accessor for the web viewer bridge Six places in message_handler and command_manager spelled out hasattr(bot, 'web_viewer_integration') and ... and ....bot_integration, then reached through the same chain again to call it. A _viewer_bridge() method on each class returns the bridge or None, and the call sites bind it once with :=. --- modules/command_manager.py | 17 +++++++++-------- modules/message_handler.py | 37 +++++++++++++------------------------ 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/modules/command_manager.py b/modules/command_manager.py index a6bb22b..d80aec3 100644 --- a/modules/command_manager.py +++ b/modules/command_manager.py @@ -419,6 +419,11 @@ class CommandManager: # Record in stats self.record_command_stat(message, command.name, success) + def _viewer_bridge(self) -> Any: + """The web viewer's bot-side bridge, or None when the viewer integration is off.""" + integration = getattr(self.bot, "web_viewer_integration", None) + return integration.bot_integration if integration else None + def record_command_stat(self, message: MeshMessage, command_name: str, response_sent: bool) -> None: """Record one command execution in the stats table, if the stats command is loaded.""" stats_command = self.commands.get('stats') @@ -2262,9 +2267,7 @@ class CommandManager: self.record_command_stat(message, command_name, response_sent) # Capture command data for web viewer - if (hasattr(self.bot, 'web_viewer_integration') and - self.bot.web_viewer_integration and - self.bot.web_viewer_integration.bot_integration): + if viewer := self._viewer_bridge(): try: # Use the response we found, or default if response is None: @@ -2304,7 +2307,7 @@ class CommandManager: self.logger.debug(f"Linked command {command_id} to confirmed transmission: {record.message_type} to {record.target}") break - self.bot.web_viewer_integration.bot_integration.capture_command( + viewer.capture_command( message, command_name, response, success if success is not None else True, command_id ) except Exception as e: @@ -2322,12 +2325,10 @@ class CommandManager: self.record_command_stat(message, command_name, True) # Error message counts as response # Capture failed command for web viewer - if (hasattr(self.bot, 'web_viewer_integration') and - self.bot.web_viewer_integration and - self.bot.web_viewer_integration.bot_integration): + if viewer := self._viewer_bridge(): try: command_id = f"{command_name}_{message.sender_id}_{int(time.time())}" - self.bot.web_viewer_integration.bot_integration.capture_command( + viewer.capture_command( message, command_name, f"Error: {e}", False, command_id ) except Exception as capture_error: diff --git a/modules/message_handler.py b/modules/message_handler.py index 7978ea4..760db46 100644 --- a/modules/message_handler.py +++ b/modules/message_handler.py @@ -632,6 +632,11 @@ class MessageHandler: selected = min(matches, key=lambda row: row.get("timestamp", float("inf"))) return {**selected, RF_MATCH_KEY: RF_MATCH_CHANNEL_AUTHENTICATED}, True + def _viewer_bridge(self) -> Any: + """The web viewer's bot-side bridge, or None when the viewer integration is off.""" + integration = getattr(self.bot, "web_viewer_integration", None) + return integration.bot_integration if integration else None + async def handle_contact_message(self, event: Any, metadata: dict[str, Any] | None = None) -> None: """Handle incoming contact message (DM). @@ -1403,11 +1408,7 @@ class MessageHandler: self.logger.info(log_message) # Capture full packet data for web viewer (for all packets) - if ( - hasattr(self.bot, "web_viewer_integration") - and self.bot.web_viewer_integration - and self.bot.web_viewer_integration.bot_integration - ): + if viewer := self._viewer_bridge(): decoded_packet["routing_info"] = routing_info if is_trace and trace_route_hashes: decoded_packet["path"] = list(trace_route_hashes) @@ -1419,7 +1420,7 @@ class MessageHandler: decoded_packet["snr"] = snr_value if "rssi" in payload: decoded_packet["rssi"] = payload.get("rssi") - self.bot.web_viewer_integration.bot_integration.capture_full_packet_data(decoded_packet) + viewer.capture_full_packet_data(decoded_packet) # Process ADVERT packets for contact tracking (regardless of path length) if routing_info["payload_type"] == "ADVERT": @@ -2868,13 +2869,9 @@ class MessageHandler: await self.process_message(message) # Capture for web viewer live monitor - if ( - hasattr(self.bot, "web_viewer_integration") - and self.bot.web_viewer_integration - and self.bot.web_viewer_integration.bot_integration - ): + if viewer := self._viewer_bridge(): try: - self.bot.web_viewer_integration.bot_integration.capture_channel_message(message) + viewer.capture_channel_message(message) except Exception: pass @@ -3782,13 +3779,9 @@ class MessageHandler: success = False # Capture keyword command data for web viewer - if ( - hasattr(self.bot, "web_viewer_integration") - and self.bot.web_viewer_integration - and self.bot.web_viewer_integration.bot_integration - ): + if viewer := self._viewer_bridge(): try: - self.bot.web_viewer_integration.bot_integration.capture_command( + viewer.capture_command( message, keyword, response, success, command_id ) except Exception as e: @@ -4084,11 +4077,7 @@ class MessageHandler: ) # Notify web viewer of new node - if ( - hasattr(self.bot, "web_viewer_integration") - and self.bot.web_viewer_integration - and self.bot.web_viewer_integration.bot_integration - ): + if viewer := self._viewer_bridge(): try: node_data = { "public_key": public_key, @@ -4096,7 +4085,7 @@ class MessageHandler: "name": contact_name, "role": "repeater", } - self.bot.web_viewer_integration.bot_integration.send_mesh_node_update(node_data) + viewer.send_mesh_node_update(node_data) except Exception as e: self.logger.debug(f"Failed to notify web viewer of new node: {e}")