From 948828cf306295a4c8bfa80d3aad68b7a705e20a Mon Sep 17 00:00:00 2001 From: agessaman Date: Sun, 7 Sep 2025 19:52:31 -0700 Subject: [PATCH] Add DM retry settings and improve message sending reliability with meshcore-2.1.6+ integration --- config.ini.example | 10 +++++++ modules/command_manager.py | 53 +++++++++++++++++++++++++++++++------- modules/core.py | 10 +++++++ requirements.txt | 1 + 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/config.ini.example b/config.ini.example index 7e86072..38e3423 100644 --- a/config.ini.example +++ b/config.ini.example @@ -55,6 +55,16 @@ bot_tx_rate_limit_seconds = 1.0 # Recommended: 100-500ms for busy networks, 0 for quiet networks tx_delay_ms = 250 +# DM retry settings for improved reliability (meshcore-2.1.6+) +# Maximum number of retry attempts for failed DM sends +dm_max_retries = 3 + +# Maximum flood attempts (when path reset is needed) +dm_max_flood_attempts = 2 + +# Number of attempts before switching to flood mode +dm_flood_after = 2 + # Timezone for bot operations # Use standard timezone names (e.g., "America/New_York", "Europe/London", "UTC") # Leave empty to use system timezone diff --git a/modules/command_manager.py b/modules/command_manager.py index d56b6b2..317ace1 100644 --- a/modules/command_manager.py +++ b/modules/command_manager.py @@ -197,30 +197,65 @@ class CommandManager: contact_name = contact.get('name', contact.get('adv_name', recipient_id)) self.logger.info(f"Sending DM to {contact_name}: {content}") - # Import send_msg from meshcore-cli - from meshcore_cli.meshcore_cli import send_msg - - # Use send_msg to send the actual message (not a command) - result = await send_msg(self.bot.meshcore, contact, content) + # Try to use send_msg_with_retry if available (meshcore-2.1.6+) + try: + # Use the meshcore commands interface for send_msg_with_retry + if hasattr(self.bot.meshcore, 'commands') and hasattr(self.bot.meshcore.commands, 'send_msg_with_retry'): + self.logger.debug("Using send_msg_with_retry for improved reliability") + + # Use send_msg_with_retry with configurable retry parameters + max_attempts = self.bot.config.getint('Bot', 'dm_max_retries', fallback=3) + max_flood_attempts = self.bot.config.getint('Bot', 'dm_max_flood_attempts', fallback=2) + flood_after = self.bot.config.getint('Bot', 'dm_flood_after', fallback=2) + timeout = 0 # Use suggested timeout from meshcore + + self.logger.debug(f"Attempting DM send with {max_attempts} max attempts") + result = await self.bot.meshcore.commands.send_msg_with_retry( + contact, + content, + max_attempts=max_attempts, + max_flood_attempts=max_flood_attempts, + flood_after=flood_after, + timeout=timeout + ) + else: + # Fallback to regular send_msg for older meshcore versions + self.logger.debug("send_msg_with_retry not available, using send_msg") + result = await self.bot.meshcore.commands.send_msg(contact, content) + + except AttributeError: + # Fallback to regular send_msg for older meshcore versions + self.logger.debug("send_msg_with_retry not available, using send_msg") + result = await self.bot.meshcore.commands.send_msg(contact, content) # Check if the result indicates success if result: if hasattr(result, 'type') and result.type == EventType.ERROR: - self.logger.error(f"Failed to send DM: {result.payload}") + self.logger.error(f"❌ DM failed to {contact_name}: {result.payload}") return False elif hasattr(result, 'type') and result.type == EventType.MSG_SENT: - self.logger.info(f"Successfully sent DM to {contact_name}") + # For send_msg_with_retry, check if we got an ACK (result is not None means ACK received) + if hasattr(self.bot.meshcore, 'commands') and hasattr(self.bot.meshcore.commands, 'send_msg_with_retry'): + # We used send_msg_with_retry, so result being returned means ACK was received + self.logger.info(f"✅ DM sent and ACK received from {contact_name}") + else: + # We used regular send_msg, so just log the send + self.logger.info(f"✅ DM sent to {contact_name}") self.bot.rate_limiter.record_send() self.bot.bot_tx_rate_limiter.record_tx() return True else: # If result is not None but doesn't have expected attributes, assume success - self.logger.info(f"DM sent to {contact_name} (result: {result})") + self.logger.info(f"✅ DM sent to {contact_name} (result: {result})") self.bot.rate_limiter.record_send() self.bot.bot_tx_rate_limiter.record_tx() return True else: - self.logger.error(f"Failed to send DM: No result returned") + # This means send_msg_with_retry failed to get an ACK after all retries + if hasattr(self.bot.meshcore, 'commands') and hasattr(self.bot.meshcore.commands, 'send_msg_with_retry'): + self.logger.error(f"❌ DM to {contact_name} failed - no ACK received after retries") + else: + self.logger.error(f"❌ DM to {contact_name} failed - no result returned") return False except Exception as e: diff --git a/modules/core.py b/modules/core.py index fb7b22c..b23a8a3 100644 --- a/modules/core.py +++ b/modules/core.py @@ -154,6 +154,16 @@ bot_tx_rate_limit_seconds = 1.0 # Recommended: 100-500ms for busy networks, 0 for quiet networks tx_delay_ms = 250 +# DM retry settings for improved reliability (meshcore-2.1.6+) +# Maximum number of retry attempts for failed DM sends +dm_max_retries = 3 + +# Maximum flood attempts (when path reset is needed) +dm_max_flood_attempts = 2 + +# Number of attempts before switching to flood mode +dm_flood_after = 2 + # Timezone for bot operations # Use standard timezone names (e.g., "America/New_York", "Europe/London", "UTC") # Leave empty to use system timezone diff --git a/requirements.txt b/requirements.txt index f5928d0..3efdbf4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,3 +11,4 @@ geopy>=2.3.0 maidenhead>=1.4.0 pytz>=2023.3 aiohttp>=3.8.0 +meshcore>=2.1.6