From e4a1e75cc03b19a47a47ed3c00930a765348e76d Mon Sep 17 00:00:00 2001 From: MarekWo Date: Thu, 12 Mar 2026 08:15:43 +0100 Subject: [PATCH] fix(socketio): register /chat namespace handler to fix real-time message delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /chat namespace had no server-side connect handler registered. With python-socketio 5.x (always_connect=False), client connections to unregistered namespaces are silently rejected. This caused all SocketIO events (new_message, ack, echo) to never reach the frontend — messages only appeared via the 60s polling fallback. Fixes: - Add @socketio.on('connect', namespace='/chat') handler in main.py - Add optimistic message append: sent messages appear instantly before API round-trip (eliminates 3-4s serial command delay) - Skip own-message SocketIO events to prevent duplicates - Add connect_error handler for frontend debugging - Bump SW cache to v6 Co-Authored-By: Claude Opus 4.6 --- app/device_manager.py | 1 + app/main.py | 15 +++++++++++++++ app/static/js/app.js | 24 ++++++++++++++++++++---- app/static/js/sw.js | 2 +- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/app/device_manager.py b/app/device_manager.py index 3998f8c..1dacb0f 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -388,6 +388,7 @@ class DeviceManager: 'timestamp': ts, 'id': msg_id, }, namespace='/chat') + logger.debug(f"SocketIO emitted new_message for ch{channel_idx} msg #{msg_id}") except Exception as e: logger.error(f"Error handling channel message: {e}") diff --git a/app/main.py b/app/main.py index 27ae76e..4f2bdf5 100644 --- a/app/main.py +++ b/app/main.py @@ -121,6 +121,21 @@ def create_app(): return app +# ============================================================ +# WebSocket handlers for Chat (real-time message push) +# ============================================================ + +@socketio.on('connect', namespace='/chat') +def handle_chat_connect(): + """Handle chat WebSocket connection — required for /chat namespace to accept clients.""" + logger.info("Chat WebSocket client connected") + + +@socketio.on('disconnect', namespace='/chat') +def handle_chat_disconnect(): + logger.debug("Chat WebSocket client disconnected") + + # ============================================================ # WebSocket handlers for Console # ============================================================ diff --git a/app/static/js/app.js b/app/static/js/app.js index 79d1a76..f490c66 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -397,6 +397,10 @@ function connectChatSocket() { console.log('SocketIO connected to /chat'); }); + chatSocket.on('connect_error', (err) => { + console.error('SocketIO /chat connect error:', err.message); + }); + // Real-time new channel message chatSocket.on('new_message', (data) => { // Filter blocked contacts in real-time @@ -410,6 +414,8 @@ function connectChatSocket() { updateUnreadBadges(); checkAndNotify(); } else if (!currentArchiveDate) { + // Skip own messages — already appended optimistically on send + if (data.is_own) return; // Current channel and live view — append message directly (no full reload) appendMessageFromSocket(data); } @@ -1063,6 +1069,19 @@ async function sendMessage() { const sendBtn = document.getElementById('sendBtn'); sendBtn.disabled = true; + // Optimistic append: show sent message immediately before API round-trip + input.value = ''; + updateCharCounter(); + const optimisticId = '_pending_' + Date.now(); + appendMessageFromSocket({ + id: optimisticId, + sender: window.MC_CONFIG?.deviceName || 'Me', + content: text, + timestamp: Math.floor(Date.now() / 1000), + is_own: true, + channel_idx: currentChannelIdx, + }); + try { const response = await fetch('/api/messages', { method: 'POST', @@ -1078,12 +1097,9 @@ async function sendMessage() { const data = await response.json(); if (data.success) { - input.value = ''; - updateCharCounter(); showNotification('Message sent', 'success'); - // Message will appear via SocketIO 'new_message' event (no reload needed). - // Schedule one deferred reload to pick up echo data (echoes arrive within 5-30s). + // Schedule deferred reload to pick up echo data + replace optimistic msg with real one setTimeout(() => loadMessages(), 15000); } else { showNotification('Failed to send: ' + data.error, 'danger'); diff --git a/app/static/js/sw.js b/app/static/js/sw.js index 80b8e0b..3b91650 100644 --- a/app/static/js/sw.js +++ b/app/static/js/sw.js @@ -1,4 +1,4 @@ -const CACHE_NAME = 'mc-webui-v5'; +const CACHE_NAME = 'mc-webui-v6'; const ASSETS_TO_CACHE = [ '/', '/static/css/style.css',