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,
|
visuForm: false,
|
||||||
visuStriscia: true,
|
visuStriscia: true,
|
||||||
timeout: false,
|
timeout: false,
|
||||||
|
timeoutTeam: null,
|
||||||
|
timeoutVideo: null,
|
||||||
|
timeoutStartedAt: null,
|
||||||
modalitaPartita: "3/5",
|
modalitaPartita: "3/5",
|
||||||
sp: {
|
sp: {
|
||||||
striscia: [{ serv: 'h', ris: '', vinc: null }],
|
striscia: [{ serv: 'h', ris: '', vinc: null }],
|
||||||
@@ -165,8 +168,21 @@ export function applyAction(state, action) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "toggleTimeout": {
|
case "startTimeout": {
|
||||||
s.timeout = !s.timeout
|
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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { createInitialState, applyAction } from './gameState.js'
|
|||||||
* @param {WebSocketServer} wss - Istanza del server WebSocket.
|
* @param {WebSocketServer} wss - Istanza del server WebSocket.
|
||||||
* @returns {Object} Oggetto con metodi di gestione dello stato.
|
* @returns {Object} Oggetto con metodi di gestione dello stato.
|
||||||
*/
|
*/
|
||||||
|
const DURATA_TIMEOUT_MS = 30000
|
||||||
|
|
||||||
export function setupWebSocketHandler(wss, options = {}) {
|
export function setupWebSocketHandler(wss, options = {}) {
|
||||||
// Stato globale della partita.
|
// Stato globale della partita.
|
||||||
let gameState = options.initialState ?? createInitialState()
|
let gameState = options.initialState ?? createInitialState()
|
||||||
@@ -12,6 +14,17 @@ export function setupWebSocketHandler(wss, options = {}) {
|
|||||||
// Mappa dei ruoli associati ai client connessi.
|
// Mappa dei ruoli associati ai client connessi.
|
||||||
const clients = new Map() // ws -> { role: 'display' | 'controller' }
|
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
|
* Gestisce i messaggi in arrivo dal client
|
||||||
*/
|
*/
|
||||||
@@ -87,10 +100,16 @@ export function setupWebSocketHandler(wss, options = {}) {
|
|||||||
return
|
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.
|
// Applica l'azione allo stato della partita.
|
||||||
const previousState = gameState
|
const previousState = gameState
|
||||||
try {
|
try {
|
||||||
gameState = applyAction(gameState, msg.action)
|
gameState = applyAction(gameState, action)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error applying action:', err)
|
console.error('Error applying action:', err)
|
||||||
sendError(ws, 'Failed to apply action')
|
sendError(ws, 'Failed to apply action')
|
||||||
@@ -98,6 +117,20 @@ export function setupWebSocketHandler(wss, options = {}) {
|
|||||||
return
|
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.
|
// Propaga il nuovo stato a tutti i client connessi.
|
||||||
broadcastState()
|
broadcastState()
|
||||||
options.onStateChange?.(gameState)
|
options.onStateChange?.(gameState)
|
||||||
|
|||||||
Reference in New Issue
Block a user