From 15dac9f96527c392cc3e05727e85ff9787df1e28 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 12 May 2026 14:08:06 +0200 Subject: [PATCH] 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. --- .gitignore | 1 + server.js | 3 ++- src/persist.js | 26 ++++++++++++++++++++++++++ src/websocket-handler.js | 5 +++-- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/persist.js diff --git a/.gitignore b/.gitignore index d6920b1..738e140 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ node_modules dist dist-ssr dev-dist +.segnapunti *.local # Editor directories and files diff --git a/server.js b/server.js index dc41232..82df178 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import { fileURLToPath } from 'url' import { dirname, join } from 'path' import { setupWebSocketHandler } from './src/websocket-handler.js' import { printServerInfo } from './src/server-utils.js' +import { loadState, saveState } from './src/persist.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -26,7 +27,7 @@ app.get(['/controller', '/controller/*splat'], (_req, res) => { const server = createServer(app) const wss = new WebSocketServer({ noServer: true }) -setupWebSocketHandler(wss) +setupWebSocketHandler(wss, { initialState: loadState(), onStateChange: saveState }) server.on('upgrade', (request, socket, head) => { const pathname = new URL(request.url, `http://${request.headers.host}`).pathname diff --git a/src/persist.js b/src/persist.js new file mode 100644 index 0000000..7afab97 --- /dev/null +++ b/src/persist.js @@ -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) + } +} diff --git a/src/websocket-handler.js b/src/websocket-handler.js index ea2474f..faf7150 100644 --- a/src/websocket-handler.js +++ b/src/websocket-handler.js @@ -5,9 +5,9 @@ import { createInitialState, applyAction } from './gameState.js' * @param {WebSocketServer} wss - Istanza del server WebSocket. * @returns {Object} Oggetto con metodi di gestione dello stato. */ -export function setupWebSocketHandler(wss) { +export function setupWebSocketHandler(wss, options = {}) { // Stato globale della partita. - let gameState = createInitialState() + let gameState = options.initialState ?? createInitialState() // Mappa dei ruoli associati ai client connessi. 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. broadcastState() + options.onStateChange?.(gameState) } /**