From 34c60515ad378f5dc6b79781c7946bfb4d582fde Mon Sep 17 00:00:00 2001 From: MarekWo Date: Sun, 28 Dec 2025 16:59:32 +0100 Subject: [PATCH] fix(bridge): Add auto-recv thread to sync messages every 30s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL FIX: Messages stopped arriving after switching to persistent session. Root cause: meshcli in interactive mode (Popen stdin/stdout) doesn't receive messages automatically - requires explicit 'recv' command. Changes: - Add auto_recv_thread that calls 'recv' every 30 seconds in background - This ensures continuous message synchronization without breaking /cli - Messages are saved to .msgs file by meshcli as usual - Add TZ=Europe/Warsaw to both containers for correct timestamps in logs Technical details: - auto-recv runs in separate thread via command queue (no blocking) - First recv after 5s delay (let session initialize) - Uses execute_command() internally, so respects command serialization - Thread stops gracefully on shutdown_flag 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- docker-compose.yml | 2 ++ meshcore-bridge/bridge.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 76f10ed..747a9d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: - MC_SERIAL_PORT=${MC_SERIAL_PORT} - MC_CONFIG_DIR=/root/.config/meshcore - MC_DEVICE_NAME=${MC_DEVICE_NAME} + - TZ=Europe/Warsaw networks: - meshcore-net healthcheck: @@ -47,6 +48,7 @@ services: - FLASK_HOST=${FLASK_HOST:-0.0.0.0} - FLASK_PORT=${FLASK_PORT:-5000} - FLASK_DEBUG=${FLASK_DEBUG:-false} + - TZ=Europe/Warsaw env_file: - .env depends_on: diff --git a/meshcore-bridge/bridge.py b/meshcore-bridge/bridge.py index dbcd854..d9baad8 100644 --- a/meshcore-bridge/bridge.py +++ b/meshcore-bridge/bridge.py @@ -74,10 +74,14 @@ class MeshCLISession: self.stderr_thread = None self.stdin_thread = None self.watchdog_thread = None + self.auto_recv_thread = None # Shutdown flag self.shutdown_flag = threading.Event() + # Auto-recv interval (seconds) - periodic message sync + self.auto_recv_interval = 30 + # Start session self._start_session() @@ -110,6 +114,9 @@ class MeshCLISession: self.watchdog_thread = threading.Thread(target=self._watchdog, daemon=True, name="watchdog") self.watchdog_thread.start() + self.auto_recv_thread = threading.Thread(target=self._auto_recv, daemon=True, name="auto-recv") + self.auto_recv_thread.start() + # Initialize session settings time.sleep(0.5) # Let meshcli initialize self._init_session_settings() @@ -277,6 +284,32 @@ class MeshCLISession: logger.info("watchdog thread exiting") + def _auto_recv(self): + """Thread: Periodically call recv to sync messages in background""" + logger.info(f"auto-recv thread started (interval: {self.auto_recv_interval}s)") + + # Wait a bit before first recv to let session initialize + time.sleep(5) + + while not self.shutdown_flag.is_set(): + try: + # Execute recv command via internal queue + logger.debug("Auto-recv: fetching new messages") + result = self.execute_command(['recv'], timeout=RECV_TIMEOUT) + + if result['success']: + logger.debug("Auto-recv: messages synced successfully") + else: + logger.warning(f"Auto-recv failed: {result.get('stderr', 'unknown error')}") + + except Exception as e: + logger.error(f"Auto-recv error: {e}") + + # Wait for next interval (or until shutdown) + self.shutdown_flag.wait(self.auto_recv_interval) + + logger.info("auto-recv thread exiting") + def _is_advert_json(self, line): """Check if line is a JSON advert""" try: