Enhance Socket.IO integration and improve error handling

- Updated CORS configuration for Socket.IO to allow all origins and added specific allowed headers.
- Improved error handling for Socket.IO connections, including detailed logging for connection errors and upgrade attempts.
- Implemented cleanup logic for socket connections during page reloads to prevent stale connections.
- Enhanced reconnection logic with unlimited attempts and improved logging for connection status.
- Updated frontend socket service to manage club room joining and leaving more effectively, with better state handling.
- Configured Vite for improved hot module replacement (HMR) settings to support local development.
This commit is contained in:
Torsten Schulz (local)
2025-11-29 00:52:29 +01:00
parent bf0d5b0935
commit a651113dee
4 changed files with 270 additions and 20 deletions

View File

@@ -2,12 +2,61 @@ import { io } from 'socket.io-client';
import { backendBaseUrl } from '../apiClient.js';
let socket = null;
let isReloading = false;
let suppressLogs = false;
// Cleanup beim Seitenreload
if (typeof window !== 'undefined') {
window.addEventListener('beforeunload', () => {
isReloading = true;
suppressLogs = true;
if (socket) {
// Trenne die Verbindung beim Reload, aber unterdrücke Logs
socket.removeAllListeners();
socket.disconnect();
socket = null;
}
});
// Nach dem Reload Logs wieder erlauben (nach kurzer Verzögerung)
window.addEventListener('load', () => {
setTimeout(() => {
isReloading = false;
suppressLogs = false;
}, 1000);
});
}
export const connectSocket = (clubId) => {
// Beim ersten Connect nach Reload, entferne alte Socket.IO Cookies
if (typeof document !== 'undefined' && !socket) {
// Entferne alte Socket.IO Session-Cookies
document.cookie.split(';').forEach((cookie) => {
const eqPos = cookie.indexOf('=');
const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
if (name === 'io') {
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
}
});
}
// Wenn bereits eine Verbindung existiert, aber nicht verbunden ist, trenne sie
if (socket && !socket.connected) {
socket.removeAllListeners();
socket.disconnect();
socket = null;
}
if (socket && socket.connected) {
// Wenn bereits verbunden, verlasse den alten Club-Raum und trete dem neuen bei
if (socket.currentClubId) {
if (socket.currentClubId && socket.currentClubId !== clubId) {
socket.emit('leave-club', socket.currentClubId);
socket.currentClubId = clubId;
socket.emit('join-club', clubId);
return socket;
} else if (socket.currentClubId === clubId) {
// Bereits im richtigen Club-Raum - keine Aktion nötig
return socket;
}
} else {
// Neue Verbindung erstellen
@@ -33,27 +82,98 @@ export const connectSocket = (clubId) => {
transports: ['polling', 'websocket'], // Polling zuerst für bessere Kompatibilität, dann WebSocket
reconnection: true,
reconnectionDelay: 1000,
reconnectionAttempts: 5,
reconnectionDelayMax: 5000,
reconnectionAttempts: Infinity, // Unbegrenzte Versuche
timeout: 20000,
upgrade: true,
forceNew: false,
secure: isHttps, // Nur für HTTPS
rejectUnauthorized: false // Für selbst-signierte Zertifikate (nur Entwicklung)
rejectUnauthorized: false, // Für selbst-signierte Zertifikate (nur Entwicklung)
// Verbesserte Cookie-Handling
withCredentials: true,
// Auto-Connect
autoConnect: true
});
socket.on('connect', () => {
console.log('✅ Socket.IO verbunden:', socket.id);
console.log(' Transport:', socket.io.engine.transport.name);
// Wenn bereits ein Club ausgewählt war, trete dem Raum bei
if (socket.currentClubId) {
socket.emit('join-club', socket.currentClubId);
}
});
socket.on('disconnect', () => {
// Socket getrennt
socket.on('disconnect', (reason) => {
// Beim Reload oder wenn Logs unterdrückt werden sollen, keine Logs
if (isReloading || suppressLogs) {
return;
}
// "transport error" ist normal beim Reload - unterdrücke diese Logs komplett
if (reason === 'transport error' || reason === 'ping timeout') {
return; // Keine Logs für normale Transport-Fehler
}
// Nur wichtige Disconnects loggen
if (reason !== 'io client disconnect' && reason !== 'transport close') {
console.log('❌ Socket.IO getrennt:', reason);
}
if (reason === 'io server disconnect') {
// Server hat die Verbindung getrennt, neu verbinden
socket.connect();
}
});
socket.on('connect_error', (error) => {
console.error('Socket.IO Verbindungsfehler:', error);
// Beim Reload keine Error-Logs
if (isReloading || suppressLogs) {
return;
}
// "xhr poll error" oder "Session ID unknown" sind normal - unterdrücke diese
if (error.message && (
error.message.includes('Session ID unknown') ||
error.message.includes('xhr poll error') ||
error.type === 'TransportError'
)) {
// Keine Logs für normale Verbindungsfehler
return;
}
// Nur unerwartete Fehler loggen
console.error('❌ Socket.IO Verbindungsfehler:', error.message);
console.error(' Type:', error.type);
console.error(' Description:', error.description);
});
socket.on('reconnect', (attemptNumber) => {
// Beim Reload keine Reconnect-Logs
if (!isReloading && !suppressLogs) {
console.log('✅ Socket.IO wieder verbunden nach', attemptNumber, 'Versuch(en)');
}
});
socket.on('reconnect_attempt', (attemptNumber) => {
// Reconnect-Versuche nicht loggen - zu viele Logs
// if (!isReloading && !suppressLogs) {
// console.log('🔄 Socket.IO Verbindungsversuch', attemptNumber);
// }
});
socket.on('reconnect_error', (error) => {
// Beim Reload keine Error-Logs
if (!isReloading && !suppressLogs) {
console.error('❌ Socket.IO Wiederverbindungsfehler:', error.message);
}
});
socket.on('reconnect_failed', () => {
// Nur kritische Fehler loggen
if (!isReloading && !suppressLogs) {
console.error('❌ Socket.IO Wiederverbindung fehlgeschlagen - alle Versuche aufgebraucht');
}
});
}
@@ -71,6 +191,7 @@ export const disconnectSocket = () => {
if (socket.currentClubId) {
socket.emit('leave-club', socket.currentClubId);
}
socket.removeAllListeners();
socket.disconnect();
socket = null;
}

View File

@@ -13,6 +13,11 @@ export default defineConfig({
port: 5000,
watch: {
usePolling: true,
},
hmr: {
protocol: 'ws',
host: 'localhost',
port: 5000,
}
},
});