feat(persist): salva stato su .segnapunti/state.json ad ogni azione

All'avvio il server carica lo stato dal file se esiste; ad ogni azione
lo riscrive. Il riavvio del server riprende dall'ultimo punto salvato.
This commit is contained in:
2026-05-12 14:08:06 +02:00
parent 0ba49ead5d
commit 15dac9f965
4 changed files with 32 additions and 3 deletions
+1
View File
@@ -14,6 +14,7 @@ node_modules
dist dist
dist-ssr dist-ssr
dev-dist dev-dist
.segnapunti
*.local *.local
# Editor directories and files # Editor directories and files
+2 -1
View File
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url'
import { dirname, join } from 'path' import { dirname, join } from 'path'
import { setupWebSocketHandler } from './src/websocket-handler.js' import { setupWebSocketHandler } from './src/websocket-handler.js'
import { printServerInfo } from './src/server-utils.js' import { printServerInfo } from './src/server-utils.js'
import { loadState, saveState } from './src/persist.js'
const __filename = fileURLToPath(import.meta.url) const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename) const __dirname = dirname(__filename)
@@ -26,7 +27,7 @@ app.get(['/controller', '/controller/*splat'], (_req, res) => {
const server = createServer(app) const server = createServer(app)
const wss = new WebSocketServer({ noServer: true }) const wss = new WebSocketServer({ noServer: true })
setupWebSocketHandler(wss) setupWebSocketHandler(wss, { initialState: loadState(), onStateChange: saveState })
server.on('upgrade', (request, socket, head) => { server.on('upgrade', (request, socket, head) => {
const pathname = new URL(request.url, `http://${request.headers.host}`).pathname const pathname = new URL(request.url, `http://${request.headers.host}`).pathname
+26
View File
@@ -0,0 +1,26 @@
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import { createInitialState } from './gameState.js'
const STATE_PATH = join(dirname(fileURLToPath(import.meta.url)), '..', '.segnapunti', 'state.json')
export function loadState() {
try {
if (existsSync(STATE_PATH)) {
return JSON.parse(readFileSync(STATE_PATH, 'utf8'))
}
} catch (err) {
console.warn('[Persist] Stato non leggibile, si riparte da zero:', err.message)
}
return createInitialState()
}
export function saveState(state) {
try {
mkdirSync(dirname(STATE_PATH), { recursive: true })
writeFileSync(STATE_PATH, JSON.stringify(state), 'utf8')
} catch (err) {
console.error('[Persist] Salvataggio fallito:', err.message)
}
}
+3 -2
View File
@@ -5,9 +5,9 @@ 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.
*/ */
export function setupWebSocketHandler(wss) { export function setupWebSocketHandler(wss, options = {}) {
// Stato globale della partita. // Stato globale della partita.
let gameState = createInitialState() let gameState = options.initialState ?? createInitialState()
// 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' }
@@ -100,6 +100,7 @@ export function setupWebSocketHandler(wss) {
// Propaga il nuovo stato a tutti i client connessi. // Propaga il nuovo stato a tutti i client connessi.
broadcastState() broadcastState()
options.onStateChange?.(gameState)
} }
/** /**