feat(timeout): sostituisci toggleTimeout con startTimeout/stopTimeout e auto-chiusura a 30s
Serve una squadra richiedente e un video selezionabile, non più un semplice flag. Il timer dei 30s è armato lato server (non nel controller) così sopravvive a refresh/disconnessione/standby del tablet che pilota il gioco.
This commit is contained in:
+18
-2
@@ -22,6 +22,9 @@ export function createInitialState() {
|
||||
visuForm: false,
|
||||
visuStriscia: true,
|
||||
timeout: false,
|
||||
timeoutTeam: null,
|
||||
timeoutVideo: null,
|
||||
timeoutStartedAt: null,
|
||||
modalitaPartita: "3/5",
|
||||
sp: {
|
||||
striscia: [{ serv: 'h', ris: '', vinc: null }],
|
||||
@@ -165,8 +168,21 @@ export function applyAction(state, action) {
|
||||
break
|
||||
}
|
||||
|
||||
case "toggleTimeout": {
|
||||
s.timeout = !s.timeout
|
||||
case "startTimeout": {
|
||||
const team = action.team
|
||||
if (team !== 'home' && team !== 'guest') break
|
||||
s.timeout = true
|
||||
s.timeoutTeam = team
|
||||
s.timeoutVideo = action.video ?? null
|
||||
s.timeoutStartedAt = action.startedAt ?? null
|
||||
break
|
||||
}
|
||||
|
||||
case "stopTimeout": {
|
||||
s.timeout = false
|
||||
s.timeoutTeam = null
|
||||
s.timeoutVideo = null
|
||||
s.timeoutStartedAt = null
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import { createInitialState, applyAction } from './gameState.js'
|
||||
* @param {WebSocketServer} wss - Istanza del server WebSocket.
|
||||
* @returns {Object} Oggetto con metodi di gestione dello stato.
|
||||
*/
|
||||
const DURATA_TIMEOUT_MS = 30000
|
||||
|
||||
export function setupWebSocketHandler(wss, options = {}) {
|
||||
// Stato globale della partita.
|
||||
let gameState = options.initialState ?? createInitialState()
|
||||
@@ -12,6 +14,17 @@ export function setupWebSocketHandler(wss, options = {}) {
|
||||
// Mappa dei ruoli associati ai client connessi.
|
||||
const clients = new Map() // ws -> { role: 'display' | 'controller' }
|
||||
|
||||
// Timer che chiude automaticamente il time out dopo 30s, indipendentemente
|
||||
// dal controller (sopravvive a refresh/disconnessione/standby del tablet).
|
||||
let timeoutTimer = null
|
||||
|
||||
function annullaTimerTimeout() {
|
||||
if (timeoutTimer) {
|
||||
clearTimeout(timeoutTimer)
|
||||
timeoutTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestisce i messaggi in arrivo dal client
|
||||
*/
|
||||
@@ -87,10 +100,16 @@ export function setupWebSocketHandler(wss, options = {}) {
|
||||
return
|
||||
}
|
||||
|
||||
// Il momento di inizio del time out lo decide il server (non il client),
|
||||
// cosi' gameState.js resta puro/deterministico e testabile.
|
||||
const action = msg.action.type === 'startTimeout'
|
||||
? { ...msg.action, startedAt: Date.now() }
|
||||
: msg.action
|
||||
|
||||
// Applica l'azione allo stato della partita.
|
||||
const previousState = gameState
|
||||
try {
|
||||
gameState = applyAction(gameState, msg.action)
|
||||
gameState = applyAction(gameState, action)
|
||||
} catch (err) {
|
||||
console.error('Error applying action:', err)
|
||||
sendError(ws, 'Failed to apply action')
|
||||
@@ -98,6 +117,20 @@ export function setupWebSocketHandler(wss, options = {}) {
|
||||
return
|
||||
}
|
||||
|
||||
// Qualsiasi azione che tocca il time out invalida il timer di auto-chiusura
|
||||
// pendente; se il time out e' (ri)partito, ne arma uno nuovo.
|
||||
if (action.type === 'startTimeout' || action.type === 'stopTimeout') {
|
||||
annullaTimerTimeout()
|
||||
}
|
||||
if (action.type === 'startTimeout' && gameState.timeout) {
|
||||
timeoutTimer = setTimeout(() => {
|
||||
timeoutTimer = null
|
||||
gameState = applyAction(gameState, { type: 'stopTimeout' })
|
||||
broadcastState()
|
||||
options.onStateChange?.(gameState)
|
||||
}, DURATA_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
// Propaga il nuovo stato a tutti i client connessi.
|
||||
broadcastState()
|
||||
options.onStateChange?.(gameState)
|
||||
|
||||
Reference in New Issue
Block a user