fixed messaging!

This commit is contained in:
2025-05-28 14:06:36 +02:00
parent 2a1b6f8a22
commit 082924a3ba
11 changed files with 315 additions and 273 deletions

View File

@@ -1,127 +1,45 @@
// Global state and socket management
// Global state and polling management
if (typeof window.ChatManager === 'undefined') {
window.ChatManager = (function() {
let instance = null;
let socket = null;
let pollInterval = null;
const state = {
addedMessageIds: new Set(),
messageQueue: new Set(),
connectionState: {
hasJoined: false,
isConnected: false,
isConnected: true,
lastMessageId: null,
connectionAttempts: 0,
socketId: null
pollAttempts: 0
}
};
function init(conversationId) {
if (instance) {
console.log('[ChatManager] Instance already exists, returning existing instance');
return instance;
}
console.log('[ChatManager] Initializing new instance for conversation:', conversationId);
// Initialize message IDs from existing messages
$('.message').each(function() {
const messageId = $(this).data('message-id');
if (messageId) {
state.addedMessageIds.add(messageId);
}
});
// Create socket instance
socket = io(window.location.origin, {
path: '/socket.io/',
transports: ['polling', 'websocket'],
upgrade: true,
reconnection: true,
reconnectionAttempts: Infinity,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 20000,
autoConnect: true,
forceNew: true,
multiplex: false,
pingTimeout: 60000,
pingInterval: 25000,
upgradeTimeout: 10000,
rememberUpgrade: true,
rejectUnauthorized: false,
extraHeaders: {
'X-Forwarded-Proto': 'https'
}
});
// Set up socket event handlers
socket.on('connect', function() {
state.connectionState.isConnected = true;
state.connectionState.connectionAttempts++;
state.connectionState.socketId = socket.id;
console.log('Socket connected:', {
attempt: state.connectionState.connectionAttempts,
socketId: socket.id,
existingSocketId: state.connectionState.socketId,
transport: socket.io.engine.transport.name
});
// Always rejoin the room on connect
console.log('Joining conversation room:', conversationId);
socket.emit('join_conversation', {
conversation_id: conversationId,
timestamp: new Date().toISOString(),
socketId: socket.id
});
state.connectionState.hasJoined = true;
});
socket.on('disconnect', function(reason) {
console.log('Disconnected from conversation:', {
reason: reason,
socketId: socket.id,
connectionState: state.connectionState,
transport: socket.io.engine?.transport?.name
});
state.connectionState.isConnected = false;
state.connectionState.socketId = null;
});
socket.on('connect_error', function(error) {
console.error('Connection error:', error);
// Try to reconnect with polling if websocket fails
if (socket.io.engine?.transport?.name === 'websocket') {
console.log('WebSocket failed, falling back to polling');
socket.io.opts.transports = ['polling'];
}
});
socket.on('error', function(error) {
console.error('Socket error:', error);
});
// Add heartbeat to keep connection alive
setInterval(function() {
if (socket.connected) {
socket.emit('heartbeat', {
timestamp: new Date().toISOString(),
socketId: socket.id,
transport: socket.io.engine.transport.name
state.connectionState.lastMessageId = Math.max(state.connectionState.lastMessageId || 0, messageId);
console.log('[ChatManager] Initialized with existing message:', {
messageId: messageId,
lastMessageId: state.connectionState.lastMessageId
});
}
}, 15000);
// Handle transport upgrade
socket.io.engine.on('upgrade', function() {
console.log('Transport upgraded to:', socket.io.engine.transport.name);
});
socket.io.engine.on('upgradeError', function(err) {
console.error('Transport upgrade error:', err);
// Fall back to polling
socket.io.opts.transports = ['polling'];
});
// Start polling for new messages
startPolling(conversationId);
instance = {
socket: socket,
state: state,
cleanup: cleanup
};
@@ -129,12 +47,97 @@ if (typeof window.ChatManager === 'undefined') {
return instance;
}
function startPolling(conversationId) {
console.log('[ChatManager] Starting polling for conversation:', conversationId);
// Clear any existing polling
if (pollInterval) {
console.log('[ChatManager] Clearing existing polling interval');
clearInterval(pollInterval);
}
// Poll every 3 seconds
pollInterval = setInterval(() => {
console.log('[ChatManager] Polling interval triggered');
fetchNewMessages(conversationId);
}, 3000);
// Initial fetch
console.log('[ChatManager] Performing initial message fetch');
fetchNewMessages(conversationId);
}
function fetchNewMessages(conversationId) {
const url = `/conversations/${conversationId}/messages`;
const params = new URLSearchParams();
if (state.connectionState.lastMessageId) {
params.append('last_message_id', state.connectionState.lastMessageId);
}
console.log('[ChatManager] Fetching new messages:', {
url: url,
params: params.toString(),
lastMessageId: state.connectionState.lastMessageId
});
fetch(`${url}?${params.toString()}`)
.then(response => response.json())
.then(data => {
console.log('[ChatManager] Received messages response:', {
success: data.success,
messageCount: data.messages ? data.messages.length : 0,
messages: data.messages
});
if (data.success && data.messages) {
state.connectionState.pollAttempts = 0;
processNewMessages(data.messages);
}
})
.catch(error => {
console.error('[ChatManager] Error fetching messages:', error);
state.connectionState.pollAttempts++;
// If we've had too many failed attempts, try to reconnect
if (state.connectionState.pollAttempts > 5) {
console.log('[ChatManager] Too many failed attempts, restarting polling');
startPolling(conversationId);
}
});
}
function processNewMessages(messages) {
console.log('[ChatManager] Processing new messages:', {
messageCount: messages.length,
currentLastMessageId: state.connectionState.lastMessageId,
existingMessageIds: Array.from(state.addedMessageIds)
});
messages.forEach(message => {
console.log('[ChatManager] Processing message:', {
messageId: message.id,
alreadyAdded: state.addedMessageIds.has(message.id),
currentLastMessageId: state.connectionState.lastMessageId
});
if (!state.addedMessageIds.has(message.id)) {
state.addedMessageIds.add(message.id);
state.connectionState.lastMessageId = Math.max(state.connectionState.lastMessageId || 0, message.id);
console.log('[ChatManager] Triggering new_message event for message:', message.id);
// Trigger the new message event
$(document).trigger('new_message', [message]);
} else {
console.log('[ChatManager] Skipping already added message:', message.id);
}
});
}
function cleanup() {
console.log('Cleaning up socket connection');
if (socket) {
socket.off('new_message');
socket.disconnect();
socket = null;
console.log('[ChatManager] Cleaning up polling');
if (pollInterval) {
clearInterval(pollInterval);
pollInterval = null;
}
instance = null;
}