From 184aa09fcf218bf2253e2d9321248b6bd63b4314 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sat, 1 Mar 2025 00:42:45 +0100 Subject: [PATCH] Fix socket.io warning --- client/src/common/contexts/SocketContext.jsx | 115 +++++++++++++------ client/src/pages/Game/Game.jsx | 18 ++- client/src/pages/Home/Home.jsx | 8 +- 3 files changed, 104 insertions(+), 37 deletions(-) diff --git a/client/src/common/contexts/SocketContext.jsx b/client/src/common/contexts/SocketContext.jsx index 7e49e8d..75da926 100644 --- a/client/src/common/contexts/SocketContext.jsx +++ b/client/src/common/contexts/SocketContext.jsx @@ -8,13 +8,15 @@ export const SocketProvider = ({ children }) => { const [connected, setConnected] = useState(false); const connectAttempts = useRef(0); const maxAttempts = 3; - const reconnectDelay = 2000; // ms - - // Connect to socket server + const pendingEventHandlers = useRef({}); + const isConnecting = useRef(false); + const connect = useCallback(() => { - if (socket) return; + if (socket || isConnecting.current) return; - // Determine server URL based on environment + isConnecting.current = true; + console.log("Connecting to socket server..."); + const serverUrl = process.env.NODE_ENV === 'production' ? window.location.origin : 'http://localhost:5287'; @@ -23,15 +25,23 @@ export const SocketProvider = ({ children }) => { const newSocket = io(serverUrl, { reconnectionAttempts: 3, timeout: 10000, - reconnectionDelay: 1000 + reconnectionDelay: 1000, + autoConnect: true }); newSocket.on('connect', () => { console.log('Socket connected with ID:', newSocket.id); setConnected(true); connectAttempts.current = 0; - - // Store player ID in localStorage for persistence + isConnecting.current = false; + + Object.entries(pendingEventHandlers.current).forEach(([event, handlers]) => { + handlers.forEach(handler => { + console.log(`Registering pending handler for event: ${event}`); + newSocket.on(event, handler); + }); + }); + localStorage.setItem('playerId', newSocket.id); }); @@ -43,6 +53,7 @@ export const SocketProvider = ({ children }) => { newSocket.on('connect_error', (error) => { console.error('Connection error:', error); connectAttempts.current += 1; + isConnecting.current = false; if (connectAttempts.current >= maxAttempts) { console.error('Max connection attempts reached, giving up'); @@ -53,23 +64,39 @@ export const SocketProvider = ({ children }) => { setSocket(newSocket); } catch (err) { console.error('Error creating socket connection:', err); + isConnecting.current = false; } }, [socket]); - - // Disconnect socket + + useEffect(() => { + if (!socket && !isConnecting.current) { + connect(); + } + + return () => { + pendingEventHandlers.current = {}; + }; + }, [connect, socket]); + const disconnect = useCallback(() => { if (socket) { socket.disconnect(); setSocket(null); setConnected(false); console.log('Socket manually disconnected'); + pendingEventHandlers.current = {}; } }, [socket]); - - // Send event through socket + const send = useCallback((event, data) => { - if (!socket || !connected) { - console.warn(`Cannot send event "${event}": socket not connected`); + if (!socket) { + console.warn(`Cannot send event "${event}": socket not connected. Auto-connecting...`); + connect(); + return false; + } + + if (!connected) { + console.warn(`Socket exists but not connected when sending "${event}". Waiting for connection...`); return false; } @@ -80,20 +107,41 @@ export const SocketProvider = ({ children }) => { console.error(`Error sending event "${event}":`, err); return false; } - }, [socket, connected]); - - // Register event listener + }, [socket, connected, connect]); + const on = useCallback((event, callback) => { if (!socket) { - console.warn(`Cannot listen for event "${event}": socket not initialized`); - return () => {}; + console.log(`Deferring registration for event "${event}" until socket is ready`); + + if (!pendingEventHandlers.current[event]) { + pendingEventHandlers.current[event] = []; + } + + pendingEventHandlers.current[event].push(callback); + + if (!isConnecting.current) { + connect(); + } + + return () => { + if (pendingEventHandlers.current[event]) { + const index = pendingEventHandlers.current[event].indexOf(callback); + if (index > -1) { + pendingEventHandlers.current[event].splice(index, 1); + } + } + }; } - + socket.on(event, callback); - return () => socket.off(event, callback); - }, [socket]); - - // Clean up socket on component unmount + + return () => { + if (socket) { + socket.off(event, callback); + } + }; + }, [socket, connect]); + useEffect(() => { return () => { if (socket) { @@ -101,16 +149,19 @@ export const SocketProvider = ({ children }) => { } }; }, [socket]); + + const contextValue = { + socket, + connected, + connect, + disconnect, + send, + on, + isConnecting: isConnecting.current + }; return ( - + {children} ); diff --git a/client/src/pages/Game/Game.jsx b/client/src/pages/Game/Game.jsx index bbfdc36..86a08d2 100644 --- a/client/src/pages/Game/Game.jsx +++ b/client/src/pages/Game/Game.jsx @@ -6,7 +6,13 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {faMessage, faMusic, faHeadphones, faClock, faCrown} from "@fortawesome/free-solid-svg-icons"; export const Game = () => { - const {send, on, socket} = useContext(SocketContext); + const {send, on, socket, connected, connect} = useContext(SocketContext); + + useEffect(() => { + if (!connected) { + connect(); + } + }, [connected, connect]); const [role, setRole] = useState(null); const [round, setRound] = useState(1); @@ -29,6 +35,8 @@ export const Game = () => { const timerIntervalRef = useRef(null); useEffect(() => { + if (!connected) return; + const eventHandlers = { "roles-assigned": (roles) => { const myRole = roles[socket?.id]; @@ -110,11 +118,13 @@ export const Game = () => { ([event, handler]) => on(event, handler) ); - send("get-room-users"); - send("check-host-status"); + if (connected) { + send("get-room-users"); + send("check-host-status"); + } return () => cleanupFunctions.forEach(cleanup => cleanup()); - }, [socket, on, send, role, currentSong, phase]); + }, [socket, on, send, role, currentSong, phase, connected]); useEffect(() => { if (timerIntervalRef.current) clearInterval(timerIntervalRef.current); diff --git a/client/src/pages/Home/Home.jsx b/client/src/pages/Home/Home.jsx index c792592..c9fc098 100644 --- a/client/src/pages/Home/Home.jsx +++ b/client/src/pages/Home/Home.jsx @@ -9,10 +9,16 @@ import {useContext, useState, useEffect} from "react"; export const Home = () => { const {setCurrentState} = useContext(StateContext); - const {connect, send, on} = useContext(SocketContext); + const {connect, send, on, connected} = useContext(SocketContext); const [homeState, setHomeState] = useState("initial"); // initial, joining, creating const [error, setError] = useState(""); + useEffect(() => { + if (!connected) { + connect(); + } + }, [connected, connect]); + useEffect(() => { connect();