refactor: prevent overwriting existing session on reconnect and improve player identity handling
All checks were successful
Build and Push Docker Image / docker (push) Successful in 9s
All checks were successful
Build and Push Docker Image / docker (push) Successful in 9s
This commit is contained in:
@@ -19,7 +19,11 @@ function showToast(msg) {
|
||||
function handleConnected(msg) {
|
||||
state.playerId = msg.playerId;
|
||||
if (msg.sessionId) {
|
||||
cacheSessionId(msg.sessionId);
|
||||
// Don't clobber an existing session on reconnect; only set if none exists yet.
|
||||
const existing = localStorage.getItem('sessionId');
|
||||
if (!existing) {
|
||||
cacheSessionId(msg.sessionId);
|
||||
}
|
||||
}
|
||||
const stored = localStorage.getItem('playerName');
|
||||
if (stored) {
|
||||
|
||||
@@ -20,11 +20,24 @@ function drawNextTrack(room) {
|
||||
export function setupWebSocket(server) {
|
||||
const wss = new WebSocketServer({ server });
|
||||
wss.on('connection', (ws) => {
|
||||
const id = uuidv4();
|
||||
const sessionId = uuidv4();
|
||||
let player = { id, sessionId, name: `Player-${id.slice(0, 4)}`, ws, connected: true, roomId: null };
|
||||
// Create a tentative player identity, but don't immediately commit or send it.
|
||||
const newId = uuidv4();
|
||||
const newSessionId = uuidv4();
|
||||
let player = { id: newId, sessionId: newSessionId, name: `Player-${newId.slice(0, 4)}`, ws, connected: true, roomId: null };
|
||||
const send = (type, payload) => { try { ws.send(JSON.stringify({ type, ...payload })); } catch {} };
|
||||
send('connected', { playerId: id, sessionId });
|
||||
|
||||
// To avoid overwriting an existing session on reconnect, delay the initial
|
||||
// welcome until we see if the client sends a resume message.
|
||||
let helloSent = false;
|
||||
const sendHello = (p) => {
|
||||
if (helloSent) return;
|
||||
helloSent = true;
|
||||
send('connected', { playerId: p.id, sessionId: p.sessionId });
|
||||
};
|
||||
// Fallback: if no resume arrives shortly, treat as a fresh connection.
|
||||
const helloTimer = setTimeout(() => {
|
||||
sendHello(player);
|
||||
}, 400);
|
||||
|
||||
function isParticipant(room, pid) {
|
||||
if (!room) return false;
|
||||
@@ -39,6 +52,7 @@ export function setupWebSocket(server) {
|
||||
|
||||
// Allow client to resume by session token
|
||||
if (msg.type === 'resume') {
|
||||
clearTimeout(helloTimer);
|
||||
const reqSession = String(msg.sessionId || '');
|
||||
if (!reqSession) { send('resume_result', { ok: false, reason: 'no_session' }); return; }
|
||||
let found = null; let foundRoom = null;
|
||||
@@ -61,7 +75,10 @@ export function setupWebSocket(server) {
|
||||
// Notify room
|
||||
broadcast(foundRoom, 'room_update', { room: roomSummary(foundRoom) });
|
||||
}
|
||||
send('resume_result', { ok: true, playerId: found.id, roomId: foundRoom?.id });
|
||||
// Send resume result and an explicit connected that preserves their original session.
|
||||
send('resume_result', { ok: true, playerId: found.id, roomId: foundRoom?.id });
|
||||
helloSent = true;
|
||||
send('connected', { playerId: found.id, sessionId: found.sessionId });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,6 +126,13 @@ export function setupWebSocket(server) {
|
||||
if (msg.type === 'create_room') { const room = createRoom(msg.name, player); player.roomId = room.id; broadcast(room, 'room_update', { room: roomSummary(room) }); return; }
|
||||
if (msg.type === 'join_room') {
|
||||
const code = String(msg.code || '').toUpperCase(); const room = rooms.get(code); if (!room) return send('error', { message: 'Room not found' });
|
||||
// If there's an existing player in this room with the same session, merge to avoid duplicates.
|
||||
let existing = null;
|
||||
for (const p of room.players.values()) { if (p.sessionId && p.sessionId === player.sessionId && p.id !== player.id) { existing = p; break; } }
|
||||
if (existing) {
|
||||
try { if (existing.ws && existing.ws !== ws) { try { existing.ws.terminate(); } catch {} } } catch {}
|
||||
existing.ws = ws; existing.connected = true; existing.roomId = room.id; player = existing;
|
||||
}
|
||||
room.players.set(player.id, player); player.roomId = room.id; if (!room.state.ready) room.state.ready = {}; if (room.state.ready[player.id] == null) room.state.ready[player.id] = false;
|
||||
const inProgress = room.state.status === 'playing' || room.state.status === 'ended';
|
||||
const wasParticipant = isParticipant(room, player.id);
|
||||
@@ -161,6 +185,7 @@ export function setupWebSocket(server) {
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
clearTimeout(helloTimer);
|
||||
// Mark player disconnected but keep them in the room for resume
|
||||
try {
|
||||
if (player) {
|
||||
@@ -172,7 +197,5 @@ export function setupWebSocket(server) {
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
|
||||
ws.on('close', () => { player.connected = false; if (player.roomId && rooms.has(player.roomId)) { const room = rooms.get(player.roomId); broadcast(room, 'room_update', { room: roomSummary(room) }); } });
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user