mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-05-21 15:14:45 +02:00
fix: Switch to delay-based delivery — wantAck firmware retries cause duplicates
This commit is contained in:
parent
a80ed6cc7c
commit
914c21e167
1 changed files with 53 additions and 93 deletions
|
|
@ -1,93 +1,53 @@
|
||||||
"""Response handling - delays and message delivery."""
|
"""Response handling - delays and message delivery."""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from .config import ResponseConfig
|
from .config import ResponseConfig
|
||||||
from .connector import MeshConnector
|
from .connector import MeshConnector
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Responder:
|
class Responder:
|
||||||
"""Handles response delivery with pacing."""
|
"""Handles response delivery with pacing."""
|
||||||
|
|
||||||
def __init__(self, config: ResponseConfig, connector: MeshConnector):
|
def __init__(self, config: ResponseConfig, connector: MeshConnector):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
|
|
||||||
async def send_response(
|
async def send_response(
|
||||||
self,
|
self,
|
||||||
messages: list[str] | str,
|
messages: list[str] | str,
|
||||||
destination: Optional[str] = None,
|
destination: Optional[str] = None,
|
||||||
channel: int = 0,
|
channel: int = 0,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Send response messages with ACK-accelerated delivery.
|
"""Send response messages with randomized delay pacing."""
|
||||||
|
if isinstance(messages, str):
|
||||||
DMs: Send -> wait for ACK -> if ACK, send next immediately.
|
messages = [messages]
|
||||||
If no ACK, retry once -> if still no ACK, abort.
|
|
||||||
Broadcasts: delay-based pacing (no ACK available).
|
if not messages:
|
||||||
"""
|
return True
|
||||||
if isinstance(messages, str):
|
|
||||||
messages = [messages]
|
success = True
|
||||||
|
|
||||||
if not messages:
|
for i, msg in enumerate(messages):
|
||||||
return True
|
if i > 0:
|
||||||
|
delay = random.uniform(self.config.delay_min, self.config.delay_max)
|
||||||
success = True
|
await asyncio.sleep(delay)
|
||||||
is_dm = destination is not None
|
|
||||||
|
sent = self.connector.send_message(
|
||||||
for i, msg in enumerate(messages):
|
text=msg,
|
||||||
if is_dm and hasattr(self.connector, 'send_and_wait_ack'):
|
destination=destination,
|
||||||
# Send and wait for ACK
|
channel=channel,
|
||||||
ack = await asyncio.get_event_loop().run_in_executor(
|
)
|
||||||
None,
|
if not sent:
|
||||||
self.connector.send_and_wait_ack,
|
logger.error(f"Failed to send message {i+1}/{len(messages)}")
|
||||||
msg, destination, channel, 30.0,
|
success = False
|
||||||
)
|
break
|
||||||
|
|
||||||
if ack:
|
logger.debug(f"Sent msg {i+1}/{len(messages)}: {msg[:50]}...")
|
||||||
# ACK received - next message sends immediately (no delay)
|
|
||||||
logger.debug(f"ACK msg {i+1}/{len(messages)}: {msg[:50]}...")
|
return success
|
||||||
continue
|
|
||||||
|
|
||||||
# No ACK - retry same message once after short pause
|
|
||||||
logger.warning(f"No ACK for msg {i+1}/{len(messages)}, retrying...")
|
|
||||||
await asyncio.sleep(2.0)
|
|
||||||
|
|
||||||
ack = await asyncio.get_event_loop().run_in_executor(
|
|
||||||
None,
|
|
||||||
self.connector.send_and_wait_ack,
|
|
||||||
msg, destination, channel, 30.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
if ack:
|
|
||||||
logger.debug(f"ACK on retry msg {i+1}/{len(messages)}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Double failure - abort
|
|
||||||
logger.error(f"No ACK after retry msg {i+1}/{len(messages)}, aborting remaining")
|
|
||||||
success = False
|
|
||||||
break
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Broadcasts or fallback: delay-based pacing
|
|
||||||
if i > 0:
|
|
||||||
delay = random.uniform(self.config.delay_min, self.config.delay_max)
|
|
||||||
await asyncio.sleep(delay)
|
|
||||||
|
|
||||||
sent = self.connector.send_message(
|
|
||||||
text=msg,
|
|
||||||
destination=destination,
|
|
||||||
channel=channel,
|
|
||||||
)
|
|
||||||
if not sent:
|
|
||||||
logger.error(f"Failed to send message {i+1}/{len(messages)}")
|
|
||||||
success = False
|
|
||||||
break
|
|
||||||
|
|
||||||
logger.debug(f"Sent msg {i+1}/{len(messages)}: {msg[:50]}...")
|
|
||||||
|
|
||||||
return success
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue