Remove expired rejoin sessions
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -6,7 +6,7 @@
|
|||||||
- [x] In the admin panel, if a pi-rat doesn't have a name yet, it should show something like 'not chosen yet' rather than the player name
|
- [x] In the admin panel, if a pi-rat doesn't have a name yet, it should show something like 'not chosen yet' rather than the player name
|
||||||
- [x] In the admin panel, the "Open" and "Copy" buttons should be the same size
|
- [x] In the admin panel, the "Open" and "Copy" buttons should be the same size
|
||||||
- [x] Store the player name in local storage and pre-populate it when joining a new game (but don't force it, let the player edit it if they'd prefer a different name)
|
- [x] Store the player name in local storage and pre-populate it when joining a new game (but don't force it, let the player edit it if they'd prefer a different name)
|
||||||
- [ ] If a player tries to rejoin a game that has ended or that they've been kicked from, they should get an error message and it should be removed from the list of re-joinable games
|
- [x] If a player tries to rejoin a game that has ended or that they've been kicked from, they should get an error message and it should be removed from the list of re-joinable games
|
||||||
- [ ] Games should have join codes in addition to join links. Join codes should be a sequence of 5 alphanumeric characters (upper case letters only, no ambiguous letters like 0/O/1/I). Add a panel to the home page for joining a game via code, and display the join code on the admin page
|
- [ ] Games should have join codes in addition to join links. Join codes should be a sequence of 5 alphanumeric characters (upper case letters only, no ambiguous letters like 0/O/1/I). Add a panel to the home page for joining a game via code, and display the join code on the admin page
|
||||||
|
|
||||||
## Words Words Words
|
## Words Words Words
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export async function apiRequest(endpoint, method = 'GET', data = null) {
|
|||||||
if (errBody.error) msg = errBody.error;
|
if (errBody.error) msg = errBody.error;
|
||||||
else if (errBody.detail) msg = errBody.detail;
|
else if (errBody.detail) msg = errBody.detail;
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
throw new Error(msg);
|
const error = new Error(msg);
|
||||||
|
error.status = res.status;
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,17 @@
|
|||||||
// - Add a CHANGELOG entry only when a commit changes something players can
|
// - Add a CHANGELOG entry only when a commit changes something players can
|
||||||
// see. Skip refactors, tests, and tooling. Keep wording player-facing.
|
// see. Skip refactors, tests, and tooling. Keep wording player-facing.
|
||||||
|
|
||||||
export const VERSION = 17;
|
export const VERSION = 18;
|
||||||
|
|
||||||
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
|
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
|
||||||
export const CHANGELOG = [
|
export const CHANGELOG = [
|
||||||
|
{
|
||||||
|
version: 18,
|
||||||
|
date: '2026-07-10',
|
||||||
|
changes: [
|
||||||
|
'Expired rejoin entries are now removed automatically when a game has ended or a player is no longer in the crew, with a clear explanation.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
version: 17,
|
version: 17,
|
||||||
date: '2026-07-10',
|
date: '2026-07-10',
|
||||||
|
|||||||
@@ -31,14 +31,35 @@
|
|||||||
let reconnectTimer = null;
|
let reconnectTimer = null;
|
||||||
let reconnectDelay = 1000;
|
let reconnectDelay = 1000;
|
||||||
let destroyed = false;
|
let destroyed = false;
|
||||||
|
let staleSession = false;
|
||||||
|
|
||||||
|
function discardStaleSession(message) {
|
||||||
|
staleSession = true;
|
||||||
|
removeSession(gameId, playerId);
|
||||||
|
state = null;
|
||||||
|
error = message;
|
||||||
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
||||||
|
if (ws) ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchState() {
|
async function fetchState() {
|
||||||
|
if (staleSession) return;
|
||||||
try {
|
try {
|
||||||
const data = await apiRequest(`/game/${gameId}/player/${playerId}/state`);
|
const data = await apiRequest(`/game/${gameId}/player/${playerId}/state`);
|
||||||
|
// Preserve the Game Over screen for players who were already present
|
||||||
|
// when play ended, but discard stale home-screen rejoin attempts.
|
||||||
|
if (!state && data.game.phase === 'ended') {
|
||||||
|
discardStaleSession('This game has ended and can no longer be rejoined.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
state = data;
|
state = data;
|
||||||
error = '';
|
error = '';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err.message;
|
if (!state && err.status === 404) {
|
||||||
|
discardStaleSession('This saved game can no longer be rejoined. You may have been removed from the crew.');
|
||||||
|
} else {
|
||||||
|
error = err.message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +74,7 @@
|
|||||||
};
|
};
|
||||||
ws.onmessage = () => fetchState();
|
ws.onmessage = () => fetchState();
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
if (destroyed) return;
|
if (destroyed || staleSession) return;
|
||||||
reconnectTimer = setTimeout(connectSocket, reconnectDelay);
|
reconnectTimer = setTimeout(connectSocket, reconnectDelay);
|
||||||
reconnectDelay = Math.min(reconnectDelay * 2, 10000);
|
reconnectDelay = Math.min(reconnectDelay * 2, 10000);
|
||||||
};
|
};
|
||||||
@@ -188,6 +209,11 @@
|
|||||||
{#if error}
|
{#if error}
|
||||||
<div class="alert alert-danger" style="margin: 20px;">
|
<div class="alert alert-danger" style="margin: 20px;">
|
||||||
Error connecting to game: {error}
|
Error connecting to game: {error}
|
||||||
|
{#if staleSession}
|
||||||
|
<div class="mt-4">
|
||||||
|
<a href="#/" class="btn btn-secondary btn-small">Back to Home</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user