Fix Mercure reload spam on waiting page in Chrome
When the last player clicked ready, toggleReady() published a redundant 'player_ready' event on top of checkAllPlayersReady()'s 'all_ready', and the client reloaded on every message with no guard and without closing the EventSource. Chrome kept the old page's script (and its EventSource) alive across the overlapping reload calls, causing repeated reconnects to the Mercure hub; Firefox apparently tore the page down fast enough to mask it. Skip the redundant publish server-side, and make the client reload idempotent by tracking whether it already fired and closing the EventSource before reloading. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -326,11 +326,16 @@ final class GameDashboardService
|
|||||||
$this->checkAllPlayersReady($session);
|
$this->checkAllPlayersReady($session);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
try {
|
// If this toggle just made everyone ready, checkAllPlayersReady() already
|
||||||
$topic = '/game/hub/' . $session->getId();
|
// transitioned the session out of READY and published 'all_ready' —
|
||||||
$this->hub->publish(new Update($topic, json_encode(['type' => 'player_ready', 'player' => $player->getScreen(), 'ready' => !$setting])));
|
// don't also publish a redundant 'player_ready'.
|
||||||
} catch (\Exception $e) {
|
if ($session->getStatus() === SessionStatus::READY) {
|
||||||
// Mercure might be down, but we don't want to crash the game
|
try {
|
||||||
|
$topic = '/game/hub/' . $session->getId();
|
||||||
|
$this->hub->publish(new Update($topic, json_encode(['type' => 'player_ready', 'player' => $player->getScreen(), 'ready' => !$setting])));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Mercure might be down, but we don't want to crash the game
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -91,6 +91,18 @@
|
|||||||
const topic = config.dataset.topic;
|
const topic = config.dataset.topic;
|
||||||
const readyAt = config.dataset.readyAt;
|
const readyAt = config.dataset.readyAt;
|
||||||
|
|
||||||
|
let reloading = false;
|
||||||
|
const reloadOnce = (eventSource) => {
|
||||||
|
if (reloading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reloading = true;
|
||||||
|
if (eventSource) {
|
||||||
|
eventSource.close();
|
||||||
|
}
|
||||||
|
window.location.reload();
|
||||||
|
};
|
||||||
|
|
||||||
if (publicUrl && topic) {
|
if (publicUrl && topic) {
|
||||||
const url = new URL(publicUrl);
|
const url = new URL(publicUrl);
|
||||||
url.searchParams.append('topic', topic);
|
url.searchParams.append('topic', topic);
|
||||||
@@ -99,7 +111,7 @@
|
|||||||
eventSource.onmessage = event => {
|
eventSource.onmessage = event => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (data.type === 'all_ready' || data.type === 'player_ready') {
|
if (data.type === 'all_ready' || data.type === 'player_ready') {
|
||||||
window.location.reload();
|
reloadOnce(eventSource);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -113,12 +125,10 @@
|
|||||||
const timeLeft = timeoutMs - timeElapsed;
|
const timeLeft = timeoutMs - timeElapsed;
|
||||||
|
|
||||||
if (timeLeft > 0) {
|
if (timeLeft > 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => reloadOnce(), timeLeft);
|
||||||
window.location.reload();
|
|
||||||
}, timeLeft);
|
|
||||||
} else {
|
} else {
|
||||||
// Already timed out, reload to sync with server
|
// Already timed out, reload to sync with server
|
||||||
window.location.reload();
|
reloadOnce();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user