diff --git a/app/device_manager.py b/app/device_manager.py index d05f026..895c9a0 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -1252,7 +1252,7 @@ class DeviceManager: 'id': msg_id, }, namespace='/chat') - return {'success': True, 'message': 'Message sent', 'id': msg_id} + return {'success': True, 'message': 'Message sent', 'id': msg_id, 'timestamp': ts} except Exception as e: logger.error(f"Failed to send channel message: {e}") diff --git a/app/meshcore/cli.py b/app/meshcore/cli.py index 7cec645..0f81b0d 100644 --- a/app/meshcore/cli.py +++ b/app/meshcore/cli.py @@ -60,20 +60,17 @@ def recv_messages() -> Tuple[bool, str]: return True, "Messages are received automatically via events" -def send_message(text: str, reply_to: Optional[str] = None, channel_index: int = 0) -> Tuple[bool, str, Optional[int]]: - """Send a message to a channel. Returns (success, message, msg_id).""" +def send_message(text: str, reply_to: Optional[str] = None, channel_index: int = 0) -> Dict: + """Send a message to a channel. Returns result dict with id and timestamp.""" if reply_to: text = f"@[{reply_to}] {text}" try: dm = _get_dm() - result = dm.send_channel_message(channel_index, text) - if result['success']: - return True, result.get('message', 'Message sent'), result.get('id') - return False, result.get('error', 'Failed to send message'), None + return dm.send_channel_message(channel_index, text) except Exception as e: logger.error(f"send_message error: {e}") - return False, str(e), None + return {'success': False, 'error': str(e)} # ============================================================================= diff --git a/app/routes/api.py b/app/routes/api.py index 294712f..9d1b28c 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -601,21 +601,22 @@ def send_message(): channel_idx = data.get('channel_idx', 0) # Send message via meshcli - success, message, msg_id = cli.send_message(text, reply_to=reply_to, channel_index=channel_idx) + result = cli.send_message(text, reply_to=reply_to, channel_index=channel_idx) - if success: + if result['success']: # v2: Echo tracking is handled automatically by DeviceManager events return jsonify({ 'success': True, 'message': 'Message sent successfully', 'channel_idx': channel_idx, - 'id': msg_id, + 'id': result.get('id'), + 'timestamp': result.get('timestamp'), }), 200 else: return jsonify({ 'success': False, - 'error': message + 'error': result.get('error', 'Failed to send message') }), 500 except Exception as e: diff --git a/app/static/js/app.js b/app/static/js/app.js index 3681725..4b497dd 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -1325,6 +1325,10 @@ async function sendMessage() { const wrapper = document.querySelector(`.message-wrapper[data-msg-id="${optimisticId}"]`); if (wrapper) wrapper.dataset.msgId = data.id; } + // Use server timestamp to prevent poll-triggered reload due to clock skew + if (data.timestamp) { + markChannelAsRead(currentChannelIdx, data.timestamp); + } } else { showNotification('Failed to send: ' + data.error, 'danger'); }