import { Server } from "socket.io"; import axios from "axios"; import { handleConnectionEvents } from "./events/connection.js"; import { addUser, removeUser } from "./state/connection.js"; import gameEvents from "./events/game.js"; export const server = { io: null, }; const API_URL = "http://localhost:8000/api/v1"; const disconnectTimers = new Map(); const DISCONNECT_TIMEOUT = 1 * 60 * 1000; // 1 minutes export const serverStart = (port) => { server.io = new Server(port, { cors: { origin: "*", }, }); server.io.use(async (socket, next) => { let token = socket.handshake.auth.token; if (!token) { return next(new Error("Authentication error: No token provided")); } if (!token.startsWith("Bearer ")) { token = "Bearer " + token; } try { const response = await axios.get(`${API_URL}/users/me`, { headers: { Authorization: token, Accept: "application/json" }, }); const user = response.data.data || response.data; if (!user || !user.id) { return next(new Error("Authentication error: User data not found")); } socket.user = user; socket.handshake.auth.token = token; if (disconnectTimers.has(user.id)) { console.log(`[Connection] User ${user.id} reconnected! Cancelling surrender timer.`); clearTimeout(disconnectTimers.get(user.id)); disconnectTimers.delete(user.id); } addUser(socket.id, user); next(); } catch (error) { if (error.response) { console.error( "❌ Erro Laravel:", error.response.status, error.response.data ); } else { console.error("❌ Erro Rede:", error.message); } next(new Error("Authentication error: Invalid token")); } }); server.io.on("connection", (socket) => { gameEvents(server.io, socket); console.log(`[Connection] User ${userId} connected. Socket ID: ${socket.id}`); handleConnectionEvents(socket); socket.on("disconnect", () => { // Remove from active socket list removeUser(socket.id); if (userId) { console.log(`[Disconnect] User ${userId} disconnected. Waiting ${RECONNECT_GRACE_PERIOD/1000}s...`); // ----------------------------------------------------------- // 2. START SURRENDER TIMER // ----------------------------------------------------------- const timer = setTimeout(async () => { console.log(`[Timeout] User ${userId} did not return. Forcing surrender.`); // A. Find the Game ID this user is playing (You need a way to look this up) // Ideally, your 'socket' object or a global map knows which gameID the user is in. // For this example, let's assume you stored `socket.activeGameId` when they joined. const gameId = socket.activeGameId; if (gameId) { try { // B. Call Laravel API to resign on their behalf // We use the token we saved during the handshake await axios.post(`${API_URL}/games/${gameId}/resign`, {}, { headers: { Authorization: socket.handshake.auth.token, Accept: "application/json" } }); // C. Notify the room (The API likely triggers a Pusher/Socket event, // but we can also emit locally if needed) server.io.to(gameId).emit("game_over", { winner: "opponent", reason: "disconnect" }); console.log(`[Timeout] Successfully resigned game ${gameId} for user ${userId}`); } catch (err) { console.error(`[Timeout] Failed to resign game for user ${userId}:`, err.message); } } disconnectTimers.delete(userId); }, RECONNECT_GRACE_PERIOD); disconnectTimers.set(userId, timer); } }); }); };