Wire up the SSE push channel in both frontend dashboards
app/static/index.html: opens an EventSource against /rounds/stream (no auth needed, see the previous commit) alongside the existing polling loops. On an "update" notification, immediately re-runs the same refreshes polling would eventually do (refreshRound/refreshMe/checkLastRoundResult when logged in, refreshChainStatusOnly when logged out). Also reacts to the browser's "open" event, which fires on the initial connection and on every automatic reconnect — this re-syncs right away instead of leaving the page on stale state until the next event or poll tick, which matters most right after a dropped connection comes back. app/static/admin.html: same channel, refreshing the chain-status bar and whichever admin section is currently open (Utenti/Round/Transazioni pendenti/Audit log) instead of requiring a manual tab switch to see new data. Polling intervals are untouched in both pages — this is purely additive, so a blocked/dropped SSE connection just degrades to the pre-existing behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+40
-1
@@ -682,8 +682,14 @@ async function showDashboard() {
|
||||
// data.winner_user_id === myUserId — otherwise that comparison could race
|
||||
// against an unset myUserId right after a reload.
|
||||
await refreshMe();
|
||||
// Awaited too, and before refreshRound(): on a brand-new browser/device that
|
||||
// never saw this round live (nothing in localStorage), this is the only
|
||||
// thing that knows the outcome once the round has fully closed. Resolving
|
||||
// it first means refreshRound() finds the answer already in place instead
|
||||
// of momentarily rendering "no result" and then flipping to the win/lose
|
||||
// box a moment later once this backstop catches up.
|
||||
await checkLastRoundResult();
|
||||
refreshRound();
|
||||
checkLastRoundResult();
|
||||
clearInterval(lastResultInterval);
|
||||
lastResultInterval = setInterval(checkLastRoundResult, 20000);
|
||||
clearInterval(roundTimerInterval);
|
||||
@@ -906,6 +912,39 @@ async function withdraw() {
|
||||
refreshMe();
|
||||
}
|
||||
|
||||
// Server push: an SSE channel that notifies the instant round/bet/balance
|
||||
// state changes anywhere (see app/rounds/events.py), instead of everyone
|
||||
// waiting for their next poll tick. The message carries no payload — it just
|
||||
// means "something changed", so we react by immediately re-running the same
|
||||
// refreshes the polling loop would eventually do on its own. Polling is left
|
||||
// completely in place as a fallback: if this connection is blocked/dropped
|
||||
// (proxy, browser setting, flaky network), the page keeps working exactly as
|
||||
// before, just without the instant nudge.
|
||||
let roundEventSource = null;
|
||||
|
||||
function onRoundServerEvent() {
|
||||
if (token) {
|
||||
refreshRound();
|
||||
refreshMe();
|
||||
checkLastRoundResult();
|
||||
} else {
|
||||
refreshChainStatusOnly();
|
||||
}
|
||||
}
|
||||
|
||||
function connectRoundEvents() {
|
||||
if (roundEventSource) return;
|
||||
roundEventSource = new EventSource('/rounds/stream');
|
||||
roundEventSource.addEventListener('update', onRoundServerEvent);
|
||||
// Fires on the initial connection AND every successful auto-reconnect (the
|
||||
// browser retries this on its own after a drop) — re-syncs immediately
|
||||
// instead of leaving the page on whatever it last knew until the next event
|
||||
// or poll tick, which would otherwise widen the "missed while disconnected"
|
||||
// window to the full reconnect gap.
|
||||
roundEventSource.addEventListener('open', onRoundServerEvent);
|
||||
}
|
||||
|
||||
connectRoundEvents();
|
||||
initAuthState();
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user