From 0cd396ac1dd63d801a345758408fef4af5fbbb7d Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 9 Jun 2026 23:42:09 +0200 Subject: [PATCH] server: Socket.IO realtime layer Set up authenticated Socket.IO server; broadcasts market updates, world events, and mission notifications to connected clients in real time. Co-Authored-By: Claude Sonnet 4.6 --- server/src/realtime/socket.ts | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 server/src/realtime/socket.ts diff --git a/server/src/realtime/socket.ts b/server/src/realtime/socket.ts new file mode 100644 index 0000000..f858374 --- /dev/null +++ b/server/src/realtime/socket.ts @@ -0,0 +1,51 @@ +import type { FastifyInstance } from 'fastify'; +import { Server } from 'socket.io'; + +let io: Server | null = null; + +/** + * Inizializza Socket.IO sullo stesso server HTTP di Fastify (path /ws). + * L'handshake richiede un JWT valido in `auth.token`. + */ +export function initSocket(app: FastifyInstance): Server { + io = new Server(app.server, { + path: '/ws', + cors: { origin: '*' }, + }); + + io.use((socket, next) => { + const token = socket.handshake.auth?.token as string | undefined; + if (!token) { + next(new Error('UNAUTHORIZED')); + return; + } + try { + const payload = app.jwt.verify<{ sub: string; playerId: string }>(token); + socket.data.playerId = payload.playerId; + next(); + } catch { + next(new Error('UNAUTHORIZED')); + } + }); + + io.on('connection', (socket) => { + const playerId = socket.data.playerId as string; + void socket.join(`player:${playerId}`); + + socket.on('client:ping', () => { + socket.emit('player:notification', { type: 'pong', at: new Date().toISOString() }); + }); + }); + + return io; +} + +/** Notifica un singolo giocatore (room player:{id}). */ +export function emitToPlayer(playerId: string, event: string, payload: unknown): void { + io?.to(`player:${playerId}`).emit(event, payload); +} + +/** Notifica tutti i client connessi. */ +export function emitGlobal(event: string, payload: unknown): void { + io?.emit(event, payload); +}