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',