merge
This commit is contained in:
+133
-100
@@ -6,10 +6,10 @@ import gameEvents from "./events/game.js";
|
||||
import matchEvents from "./events/match.js";
|
||||
|
||||
export const server = {
|
||||
io: null,
|
||||
io: null,
|
||||
};
|
||||
|
||||
const API_URL = "http://localhost:8000/api/v1";
|
||||
const API_URL = process.env.API_URL || "http://localhost:8000/api/v1";
|
||||
|
||||
const disconnectTimers = new Map();
|
||||
const RECONNECT_GRACE_PERIOD = 1 * 60 * 1000;
|
||||
@@ -17,114 +17,147 @@ const RECONNECT_GRACE_PERIOD = 1 * 60 * 1000;
|
||||
const userId = (socket) => socket.user && socket.user.id;
|
||||
|
||||
export const serverStart = (port) => {
|
||||
server.io = new Server(port, {
|
||||
cors: {
|
||||
origin: "*",
|
||||
server.io = new Server(port, {
|
||||
cors: {
|
||||
origin: "*",
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`[WebSocket] API_URL is set to ${API_URL}`);
|
||||
|
||||
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.token = token;
|
||||
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);
|
||||
matchEvents(server.io, socket);
|
||||
|
||||
handleConnectionEvents(server.io, socket);
|
||||
|
||||
socket.on("notify_disconnect", () => {
|
||||
socket.isVoluntaryDisconnect = true;
|
||||
});
|
||||
|
||||
server.io.use(async (socket, next) => {
|
||||
let token = socket.handshake.auth.token;
|
||||
socket.on("disconnect", () => {
|
||||
// Remove from active socket list
|
||||
removeUser(socket.id);
|
||||
|
||||
if (!token) {
|
||||
return next(new Error("Authentication error: No token provided"));
|
||||
}
|
||||
if (socket.isVoluntaryDisconnect) {
|
||||
console.log(
|
||||
`[Disconnect] User ${userId} disconnected voluntarily. No surrender needed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!token.startsWith("Bearer ")) {
|
||||
token = "Bearer " + token;
|
||||
}
|
||||
if (userId) {
|
||||
console.log(
|
||||
`[Disconnect] User ${userId} disconnected. Waiting ${
|
||||
RECONNECT_GRACE_PERIOD / 1000
|
||||
}s...`
|
||||
);
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${API_URL}/users/me`, {
|
||||
headers: {
|
||||
Authorization: token,
|
||||
Accept: "application/json"
|
||||
},
|
||||
});
|
||||
// -----------------------------------------------------------
|
||||
// 2. START SURRENDER TIMER
|
||||
// -----------------------------------------------------------
|
||||
const timer = setTimeout(async () => {
|
||||
console.log(
|
||||
`[Timeout] User ${userId} did not return. Forcing surrender.`
|
||||
);
|
||||
|
||||
const user = response.data.data || response.data;
|
||||
// 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 (!user || !user.id) {
|
||||
return next(new Error("Authentication error: User data not found"));
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
socket.user = user;
|
||||
socket.token = token;
|
||||
socket.handshake.auth.token = token;
|
||||
disconnectTimers.delete(userId);
|
||||
}, RECONNECT_GRACE_PERIOD);
|
||||
|
||||
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);
|
||||
matchEvents(server.io, socket);
|
||||
|
||||
handleConnectionEvents(server.io, socket);
|
||||
|
||||
socket.on("notify_disconnect", () => {
|
||||
socket.isVoluntaryDisconnect = true;
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
removeUser(socket.id);
|
||||
|
||||
if (socket.isVoluntaryDisconnect) {
|
||||
console.log(`[Disconnect] User ${userId} disconnected voluntarily. No surrender needed.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
console.log(`[Disconnect] User ${userId} disconnected. Waiting ${RECONNECT_GRACE_PERIOD / 1000}s...`);
|
||||
const timer = setTimeout(async () => {
|
||||
console.log(`[Timeout] User ${userId} did not return. Forcing surrender.`);
|
||||
|
||||
const gameId = socket.activeGameId;
|
||||
|
||||
if (gameId) {
|
||||
try {
|
||||
await axios.post(`${API_URL}/games/${gameId}/resign`, {}, {
|
||||
headers: {
|
||||
Authorization: socket.handshake.auth.token,
|
||||
Accept: "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
disconnectTimers.set(userId, timer);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user