diff --git a/controller.html b/controller.html
new file mode 100644
index 0000000..0caf018
--- /dev/null
+++ b/controller.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Segnapunti - Controller
+
+
+
+
+
+
diff --git a/package.json b/package.json
index b8f8ee7..43157ae 100644
--- a/package.json
+++ b/package.json
@@ -4,9 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "concurrently -n vite,server -c cyan,yellow \"npm run dev:vite\" \"npm run dev:server\"",
- "dev:vite": "vite --clearScreen false",
- "dev:server": "PORT=5173 node server.js",
+ "dev": "vite",
"build": "vite build",
"preview": "vite preview",
"start": "node server.js",
@@ -25,4 +23,4 @@
"vite": "^4.3.9",
"vite-plugin-pwa": "^0.16.0"
}
-}
+}
\ No newline at end of file
diff --git a/server.js b/server.js
index 0f8363e..8035738 100644
--- a/server.js
+++ b/server.js
@@ -11,24 +11,72 @@ const __dirname = dirname(__filename)
// --- Configurazione del server ---
-const app = express()
-const PORT = process.env.PORT || 3000
+const DISPLAY_PORT = process.env.PORT || 3000
+const CONTROLLER_PORT = process.env.CONTROLLER_PORT || 3001
+
+// ========================================
+// Server Display (porta principale)
+// ========================================
+
+const displayApp = express()
// Espone i file generati dalla build di Vite.
-app.use(express.static(join(__dirname, 'dist')))
+displayApp.use(express.static(join(__dirname, 'dist')))
-// Fallback per SPA: restituisce `index.html` per tutte le route che non puntano a file statici.
-app.get('/{*splat}', (_req, res) => {
+// Fallback per SPA: restituisce `index.html` per tutte le route.
+displayApp.get('/{*splat}', (_req, res) => {
res.sendFile(join(__dirname, 'dist', 'index.html'))
})
-const server = createServer(app)
+const displayServer = createServer(displayApp)
-// Inizializza il server WebSocket con la logica di gioco.
-const wss = new WebSocketServer({ server })
+// Inizializza il server WebSocket condiviso.
+const wss = new WebSocketServer({ noServer: true })
setupWebSocketHandler(wss)
-// Avvia il server HTTP.
-server.listen(PORT, '0.0.0.0', () => {
- printServerInfo(PORT)
+displayServer.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()
+ }
+})
+
+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.
+controllerApp.use(express.static(join(__dirname, 'dist')))
+
+// Fallback: restituisce `controller.html` per tutte le route.
+controllerApp.get('/{*splat}', (_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)
})
diff --git a/src/components/ControllerPage.vue b/src/components/ControllerPage.vue
index 8188d55..cadc38a 100644
--- a/src/components/ControllerPage.vue
+++ b/src/components/ControllerPage.vue
@@ -308,7 +308,7 @@ export default {
this.isConnecting = true
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
- const wsUrl = `${protocol}//${location.host}`
+ const wsUrl = `${protocol}//${location.host}/ws`
try {
this.ws = new WebSocket(wsUrl)
diff --git a/src/components/DisplayPage.vue b/src/components/DisplayPage.vue
index 98703a8..1476cfc 100644
--- a/src/components/DisplayPage.vue
+++ b/src/components/DisplayPage.vue
@@ -221,7 +221,7 @@ export default {
this.isConnecting = true
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
- const wsUrl = `${protocol}//${location.host}`
+ const wsUrl = `${protocol}//${location.host}/ws`
try {
this.ws = new WebSocket(wsUrl)
diff --git a/src/controller-main.js b/src/controller-main.js
new file mode 100644
index 0000000..ff48a92
--- /dev/null
+++ b/src/controller-main.js
@@ -0,0 +1,9 @@
+import { createApp } from 'vue'
+import './style.css'
+import WaveUI from 'wave-ui'
+import 'wave-ui/dist/wave-ui.css'
+import ControllerPage from './components/ControllerPage.vue'
+
+const app = createApp(ControllerPage)
+app.use(WaveUI)
+app.mount('#app')
diff --git a/src/main.js b/src/main.js
index 4889403..a61ec98 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,21 +1,12 @@
import { createApp } from 'vue'
-import { createRouter, createWebHistory } from 'vue-router'
import './style.css'
import App from './App.vue'
import WaveUI from 'wave-ui'
import 'wave-ui/dist/wave-ui.css'
import DisplayPage from './components/DisplayPage.vue'
-import ControllerPage from './components/ControllerPage.vue'
-const router = createRouter({
- history: createWebHistory(),
- routes: [
- { path: '/', component: DisplayPage },
- { path: '/controller', component: ControllerPage },
- ],
-})
-
-const app = createApp(App)
-app.use(router)
+// In modalità display-only, non serve il router.
+// Il display viene montato direttamente.
+const app = createApp(DisplayPage)
app.use(WaveUI)
app.mount('#app')
diff --git a/src/server-utils.js b/src/server-utils.js
index 356a06f..22ddecf 100644
--- a/src/server-utils.js
+++ b/src/server-utils.js
@@ -12,9 +12,9 @@ export function getNetworkIPs() {
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.') &&
- !net.address.startsWith('172.18.')) {
+ !net.internal &&
+ !net.address.startsWith('172.17.') &&
+ !net.address.startsWith('172.18.')) {
networkIPs.push(net.address)
}
}
@@ -25,19 +25,20 @@ export function getNetworkIPs() {
/**
* Stampa il riepilogo di avvio del server con gli URL di accesso.
- * @param {number} port - Porta sulla quale il server e in ascolto.
+ * @param {number} displayPort - Porta del display.
+ * @param {number} controllerPort - Porta del controller.
*/
-export function printServerInfo(port = 5173) {
+export function printServerInfo(displayPort = 5173, controllerPort = 3001) {
const networkIPs = getNetworkIPs()
console.log(`\nSegnapunti Server`)
- console.log(` Display: http://localhost:${port}/`)
- console.log(` Controller: http://localhost:${port}/controller`)
+ console.log(` Display: http://localhost:${displayPort}/`)
+ console.log(` Controller: http://localhost:${controllerPort}/`)
if (networkIPs.length > 0) {
- console.log(`\n Da dispositivi remoti:`)
+ console.log(`\n Controller da dispositivi remoti:`)
networkIPs.forEach(ip => {
- console.log(` http://${ip}:${port}/controller`)
+ console.log(` http://${ip}:${controllerPort}/`)
})
}
diff --git a/vite-plugin-websocket.js b/vite-plugin-websocket.js
index a87bc70..6a60176 100644
--- a/vite-plugin-websocket.js
+++ b/vite-plugin-websocket.js
@@ -1,9 +1,13 @@
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
+
/**
- * Plugin Vite che integra un server WebSocket per la gestione dello stato di gioco.
+ * 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() {
@@ -11,29 +15,116 @@ export default function websocketPlugin() {
name: 'vite-plugin-websocket',
configureServer(server) {
// Inizializza un server WebSocket collegato al server HTTP di Vite.
- // Importante: usa `noServer: true` per evitare conflitti con l'HMR 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.
+ // Intercetta le richieste di upgrade WebSocket solo sul path /ws.
server.httpServer.on('upgrade', (request, socket, head) => {
- // Se la richiesta non riguarda l'HMR di Vite (es. /@vite/client),
- // la gestisce il server WebSocket dell'applicazione.
const pathname = new URL(request.url, `http://${request.headers.host}`).pathname
- if (!pathname.startsWith('/@vite') && !pathname.startsWith('/@fs')) {
+ if (pathname === '/ws') {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request)
})
}
})
- // Stampa le informazioni di accesso dopo l'avvio del server Vite.
+ // Avvia un server separato per il controller sulla porta 3001.
server.httpServer.once('listening', () => {
- setTimeout(() => printServerInfo(5173), 100)
+ const viteAddr = server.httpServer.address()
+ const vitePort = viteAddr.port
+
+ startControllerDevServer(vitePort, wss)
+
+ setTimeout(() => printServerInfo(vitePort, CONTROLLER_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: 'localhost',
+ port: vitePort,
+ path: targetPath,
+ method: req.method,
+ headers: {
+ ...req.headers,
+ host: `localhost:${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: 'localhost',
+ 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}`)
+ })
+}
diff --git a/vite.config.js b/vite.config.js
index a1b88ff..2e94043 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,12 +1,26 @@
import { defineConfig } from 'vite'
+import { resolve, dirname } from 'path'
+import { fileURLToPath } from 'url'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'
+import websocketPlugin from './vite-plugin-websocket.js'
+
+const __dirname = dirname(fileURLToPath(import.meta.url))
// Configurazione principale di Vite
export default defineConfig({
base: '/',
+ build: {
+ rollupOptions: {
+ input: {
+ main: resolve(__dirname, 'index.html'),
+ controller: resolve(__dirname, 'controller.html'),
+ },
+ },
+ },
plugins: [
vue(),
+ websocketPlugin(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
@@ -35,12 +49,5 @@ export default defineConfig({
server: {
host: '0.0.0.0',
port: 5173,
- proxy: {
- '/': {
- target: 'http://127.0.0.1:5174',
- ws: true,
- changeOrigin: true,
- },
- },
},
})