diff --git a/server.js b/server.js index c3a8285..dc41232 100644 --- a/server.js +++ b/server.js @@ -9,32 +9,26 @@ import { printServerInfo } from './src/server-utils.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) -// --- Configurazione del server --- +const PORT = process.env.PORT || 3000 +const distDir = join(__dirname, 'dist') -const DISPLAY_PORT = process.env.PORT || 3000 -const CONTROLLER_PORT = process.env.CONTROLLER_PORT || 3001 +const app = express() -// ======================================== -// Server Display (porta principale) -// ======================================== +app.use(express.static(distDir, { index: false })) -const displayApp = express() - -// Espone i file generati dalla build di Vite. -displayApp.use(express.static(join(__dirname, 'dist'))) - -// Fallback per SPA: restituisce `index.html` per tutte le route. -displayApp.get(/.*/, (_req, res) => { - res.sendFile(join(__dirname, 'dist', 'index.html')) +app.get(['/', '/display', '/display/*splat'], (_req, res) => { + res.sendFile(join(distDir, 'index.html')) }) -const displayServer = createServer(displayApp) +app.get(['/controller', '/controller/*splat'], (_req, res) => { + res.sendFile(join(distDir, 'controller.html')) +}) -// Inizializza il server WebSocket condiviso. +const server = createServer(app) const wss = new WebSocketServer({ noServer: true }) setupWebSocketHandler(wss) -displayServer.on('upgrade', (request, socket, head) => { +server.on('upgrade', (request, socket, head) => { const pathname = new URL(request.url, `http://${request.headers.host}`).pathname if (pathname === '/ws') { wss.handleUpgrade(request, socket, head, (ws) => { @@ -45,39 +39,6 @@ displayServer.on('upgrade', (request, socket, head) => { } }) -displayServer.listen(DISPLAY_PORT, '0.0.0.0', () => { - console.log(`[Display] Server running on port ${DISPLAY_PORT}`) -}) - -// ======================================== -// Server Controller (porta separata) -// ======================================== - -const controllerApp = express() - -// Espone gli stessi file statici della build. -// IMPORTANTE: { index: false } impedisce di servire index.html (il display) sulla root. -controllerApp.use(express.static(join(__dirname, 'dist'), { index: false })) - -// Fallback: restituisce `controller.html` per tutte le route. -controllerApp.get(/.*/, (_req, res) => { - res.sendFile(join(__dirname, 'dist', 'controller.html')) -}) - -const controllerServer = createServer(controllerApp) - -// Gestisce l'upgrade WebSocket anche sulla porta del controller. -controllerServer.on('upgrade', (request, socket, head) => { - const pathname = new URL(request.url, `http://${request.headers.host}`).pathname - if (pathname === '/ws') { - wss.handleUpgrade(request, socket, head, (ws) => { - wss.emit('connection', ws, request) - }) - } else { - socket.destroy() - } -}) - -controllerServer.listen(CONTROLLER_PORT, '0.0.0.0', () => { - printServerInfo(DISPLAY_PORT, CONTROLLER_PORT) +server.listen(PORT, '0.0.0.0', () => { + printServerInfo(PORT) }) diff --git a/src/server-utils.js b/src/server-utils.js index 70b346a..06f5867 100644 --- a/src/server-utils.js +++ b/src/server-utils.js @@ -1,16 +1,11 @@ import { networkInterfaces } from 'os' -/** - * Restituisce gli indirizzi IP di rete del sistema, escludendo loopback e bridge Docker. - * @returns {string[]} Elenco degli indirizzi IP disponibili. - */ export function getNetworkIPs() { const nets = networkInterfaces() const networkIPs = [] for (const name of Object.keys(nets)) { for (const net of nets[name]) { - // Esclude loopback (127.0.0.1), indirizzi non IPv4 e bridge Docker (172.17.x.x, 172.18.x.x). if (net.family === 'IPv4' && !net.internal && !net.address.startsWith('172.17.') && @@ -23,22 +18,17 @@ export function getNetworkIPs() { return networkIPs } -/** - * Stampa il riepilogo di avvio del server con gli URL di accesso. - * @param {number} displayPort - Porta del display. - * @param {number} controllerPort - Porta del controller. - */ -export function printServerInfo(displayPort = 5173, controllerPort = 3001) { +export function printServerInfo(port = 3000) { const networkIPs = getNetworkIPs() console.log(`\nSegnapunti Server`) - console.log(` Display: http://127.0.0.1:${displayPort}/`) - console.log(` Controller: http://127.0.0.1:${controllerPort}/`) + console.log(` Display: http://127.0.0.1:${port}/display`) + console.log(` Controller: http://127.0.0.1:${port}/controller`) if (networkIPs.length > 0) { console.log(`\n Controller da dispositivi remoti:`) networkIPs.forEach(ip => { - console.log(` http://${ip}:${controllerPort}/`) + console.log(` http://${ip}:${port}/controller`) }) } diff --git a/tests/unit/server-utils.test.js b/tests/unit/server-utils.test.js index 119bb68..179dd89 100644 --- a/tests/unit/server-utils.test.js +++ b/tests/unit/server-utils.test.js @@ -102,23 +102,23 @@ describe('Server Utils', () => { // printServerInfo // ============================================= describe('printServerInfo', () => { - it('dovrebbe stampare le porte corrette (default)', () => { + it('dovrebbe stampare la porta di default (3000)', () => { os.networkInterfaces.mockReturnValue({}) const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) printServerInfo() const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') - expect(allLogs).toContain('5173') - expect(allLogs).toContain('3001') + expect(allLogs).toContain('3000') + expect(allLogs).toContain('/display') + expect(allLogs).toContain('/controller') consoleSpy.mockRestore() }) - it('dovrebbe stampare le porte personalizzate', () => { + it('dovrebbe stampare la porta personalizzata', () => { os.networkInterfaces.mockReturnValue({}) const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) - printServerInfo(3000, 4000) + printServerInfo(8080) const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') - expect(allLogs).toContain('3000') - expect(allLogs).toContain('4000') + expect(allLogs).toContain('8080') consoleSpy.mockRestore() }) @@ -129,7 +129,7 @@ describe('Server Utils', () => { ] }) const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) - printServerInfo(3000, 3001) + printServerInfo(3000) const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') expect(allLogs).toContain('192.168.1.50') expect(allLogs).toContain('remoti') @@ -139,7 +139,7 @@ describe('Server Utils', () => { it('non dovrebbe mostrare sezione remoti se nessun IP di rete', () => { os.networkInterfaces.mockReturnValue({}) const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) - printServerInfo(3000, 3001) + printServerInfo(3000) const allLogs = consoleSpy.mock.calls.map(c => c[0]).join('\n') expect(allLogs).not.toContain('remoti') consoleSpy.mockRestore() diff --git a/vite-plugin-websocket.js b/vite-plugin-websocket.js index 9ba79aa..39ac0a4 100644 --- a/vite-plugin-websocket.js +++ b/vite-plugin-websocket.js @@ -1,30 +1,23 @@ import { WebSocketServer } from 'ws' -import { createServer as createHttpServer, request as httpRequest } from 'http' import { setupWebSocketHandler } from './src/websocket-handler.js' import { printServerInfo } from './src/server-utils.js' -const CONTROLLER_PORT = 3001 -const DEV_PROXY_HOST = process.env.DEV_PROXY_HOST || '127.0.0.1' - -/** - * Plugin Vite che integra un server WebSocket per la gestione dello stato di gioco - * e un server separato sulla porta 3001 per il controller. - * @returns {import('vite').Plugin} - */ export default function websocketPlugin() { return { name: 'vite-plugin-websocket', configureServer(server) { - // Inizializza un server WebSocket collegato al server HTTP di Vite. const wss = new WebSocketServer({ noServer: true }) - - // Registra i gestori WebSocket con la logica di gioco. setupWebSocketHandler(wss) - // Intercetta le richieste di upgrade WebSocket solo sul path /ws. + // Rewrite /display → / (index.html) e /controller → /controller.html + server.middlewares.use((req, _res, next) => { + if (req.url === '/display' || req.url === '/display/') req.url = '/' + else if (req.url === '/controller' || req.url === '/controller/') req.url = '/controller.html' + next() + }) + server.httpServer.on('upgrade', (request, socket, head) => { const pathname = new URL(request.url, `http://${request.headers.host}`).pathname - if (pathname === '/ws') { wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request) @@ -32,100 +25,10 @@ export default function websocketPlugin() { } }) - // Avvia un server separato per il controller sulla porta 3001. server.httpServer.once('listening', () => { - const viteAddr = server.httpServer.address() - const vitePort = viteAddr.port - - startControllerDevServer(vitePort, wss) - - setTimeout(() => printServerInfo(vitePort, CONTROLLER_PORT), 100) + const { port } = server.httpServer.address() + setTimeout(() => printServerInfo(port), 100) }) } } } - -/** - * Avvia il server di sviluppo per il controller. - * Fa da proxy verso il dev server di Vite per moduli ES, HMR, e asset. - */ -function startControllerDevServer(vitePort, wss) { - const controllerServer = createHttpServer((req, res) => { - // Se richiesta alla root, riscrive verso controller.html - let targetPath = req.url - if (targetPath === '/' || targetPath === '') { - targetPath = '/controller.html' - } - - // Proxy verso il dev server di Vite - const proxyReq = httpRequest( - { - hostname: DEV_PROXY_HOST, - port: vitePort, - path: targetPath, - method: req.method, - headers: { - ...req.headers, - host: `${DEV_PROXY_HOST}:${vitePort}`, - }, - }, - (proxyRes) => { - res.writeHead(proxyRes.statusCode, proxyRes.headers) - proxyRes.pipe(res, { end: true }) - } - ) - - proxyReq.on('error', (err) => { - console.error('[Controller Proxy] Error:', err.message) - if (!res.headersSent) { - res.writeHead(502) - res.end('Proxy error') - } - }) - - req.pipe(proxyReq, { end: true }) - }) - - // Gestisce l'upgrade WebSocket anche sulla porta del controller - controllerServer.on('upgrade', (request, socket, head) => { - const pathname = new URL(request.url, `http://${request.headers.host}`).pathname - - if (pathname === '/ws') { - wss.handleUpgrade(request, socket, head, (ws) => { - wss.emit('connection', ws, request) - }) - } else { - // Per l'HMR di Vite, proxare l'upgrade WebSocket verso Vite - const proxyReq = httpRequest({ - hostname: DEV_PROXY_HOST, - port: vitePort, - path: request.url, - method: 'GET', - headers: request.headers, - }) - - proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => { - socket.write( - `HTTP/1.1 101 Switching Protocols\r\n` + - Object.entries(proxyRes.headers) - .map(([k, v]) => `${k}: ${v}`) - .join('\r\n') + - '\r\n\r\n' - ) - proxySocket.pipe(socket) - socket.pipe(proxySocket) - }) - - proxyReq.on('error', (err) => { - console.error('[Controller Proxy] WS upgrade error:', err.message) - socket.destroy() - }) - - proxyReq.end() - } - }) - - controllerServer.listen(CONTROLLER_PORT, '0.0.0.0', () => { - console.log(`[Controller] Dev server running on port ${CONTROLLER_PORT}`) - }) -}