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 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user