Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions backend/src/config/handlers/disconnect-events.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,37 @@ import { Server, Socket } from "socket.io";
import { RoomManager } from "@/utils/room-manager";
import logger from "@/utils/logger";

export function registerDisconnectEvents(io: Server, socket: Socket, roomManager: RoomManager) {
socket.on("disconnect", (reason) => {
logger.info(`User ${socket.id} disconnected`, { reason });
export function registerDisconnectEvents(
io: Server,
socket: Socket,
roomManager: RoomManager,
) {
socket.on("disconnect", (reason) => {
logger.info(`User ${socket.id} disconnected`, { reason });

// Find and leave any room the player was in
const playerRoom = roomManager.getPlayerRoom(socket.id);
if (playerRoom) {
roomManager.leaveRoom(playerRoom.id, socket.id);
// Find and leave any room the player was in
const playerRoom = roomManager.getPlayerRoom(socket.id);
if (playerRoom) {
roomManager.leaveRoom(playerRoom.id, socket.id);

// Notify others in the room
socket.to(playerRoom.id).emit("player:left", {
playerId: socket.id,
room: roomManager.getRoomInfo(playerRoom.id),
});
// Notify others in the room
socket.to(playerRoom.id).emit("player:left", {
playerId: socket.id,
room: roomManager.getRoomInfo(playerRoom.id),
});

// Broadcast updated room list
io.emit("rooms:list", roomManager.listRooms());
}
});
// Broadcast updated room list filtered by game type
const filteredRooms = roomManager
.listRooms()
.filter((r) => r.gameType === playerRoom.gameType);
io.emit("rooms:list", {
gameType: playerRoom.gameType,
rooms: filteredRooms,
});
}
});

socket.on("error", (err) => {
logger.error("Socket Error", { error: err });
});
socket.on("error", (err) => {
logger.error("Socket Error", { error: err });
});
}
48 changes: 40 additions & 8 deletions backend/src/config/handlers/room-events.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ export function registerRoomEvents(
});

logger.info(`Created room ${room.id} for user ${socket.id}`);
io.emit("rooms:list", roomManager.listRooms());
// Broadcast only to clients interested in this game type
const filteredRooms = roomManager
.listRooms()
.filter((room) => room.gameType === data?.gameType);
io.emit("rooms:list", {
gameType: data?.gameType,
rooms: filteredRooms,
});
} catch (err) {
logger.error("Error creating room", { error: err });
socket.emit("room:error", { message: "Failed to create room" });
Expand All @@ -47,6 +54,7 @@ export function registerRoomEvents(

socket.join(data.roomId);

const room = roomManager.getRoom(data.roomId);
socket.emit("room:joined", {
success: true,
room: roomManager.getRoomInfo(data.roomId),
Expand All @@ -58,8 +66,14 @@ export function registerRoomEvents(
room: roomManager.getRoomInfo(data.roomId),
});

// Broadcast updated room list
io.emit("rooms:list", roomManager.listRooms());
// Broadcast updated room list to only this game type
const filteredRooms = roomManager
.listRooms()
.filter((r) => r.gameType === room?.gameType);
io.emit("rooms:list", {
gameType: room?.gameType,
rooms: filteredRooms,
});
} catch (err) {
logger.error("Error joining room", { error: err });
socket.emit("room:error", { message: "Failed to join room" });
Expand All @@ -68,6 +82,7 @@ export function registerRoomEvents(

socket.on("room:leave", (data: { roomId: string }) => {
try {
const room = roomManager.getRoom(data.roomId);
roomManager.leaveRoom(data.roomId, socket.id);
socket.leave(data.roomId);

Expand All @@ -79,8 +94,14 @@ export function registerRoomEvents(
room: roomManager.getRoomInfo(data.roomId),
});

// Broadcast updated room list
io.emit("rooms:list", roomManager.listRooms());
// Broadcast updated room list to only this game type
const filteredRooms = roomManager
.listRooms()
.filter((r) => r.gameType === room?.gameType);
io.emit("rooms:list", {
gameType: room?.gameType,
rooms: filteredRooms,
});
} catch (err) {
logger.error("Error leaving room", { error: err });
socket.emit("room:error", { message: "Failed to leave room" });
Expand All @@ -104,9 +125,20 @@ export function registerRoomEvents(
}
});

socket.on("rooms:get", () => {
socket.emit("rooms:list", roomManager.listRooms());
});
socket.on(
"rooms:get",
(data?: { gameType?: "tictactoe" | "snake" | "rps" }) => {
const filteredRooms = roomManager
.listRooms()
.filter((room) =>
data?.gameType ? room.gameType === data.gameType : true,
);
socket.emit("rooms:list", {
gameType: data?.gameType,
rooms: filteredRooms,
});
},
);

socket.on("room:get", (data: { roomId: string }) => {
const roomInfo = roomManager.getRoomInfo(data.roomId);
Expand Down
82 changes: 44 additions & 38 deletions backend/src/config/socket-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,63 @@ import { Server as HTTPServer } from "http";
import { RoomManager } from "@/utils/room-manager";
import logger from "@/utils/logger";
import {
registerRoomEvents,
registerGameEvents,
registerChatEvents,
registerDisconnectEvents,
registerRoomEvents,
registerGameEvents,
registerChatEvents,
registerDisconnectEvents,
} from "./handlers";

export const userSocketMap = new Map<string, string>();
let ioServer: Server | undefined;
export const roomManager = new RoomManager();

export function initializeSocket(server: HTTPServer) {
const io = new Server(server, {
cors: {
origin: process.env.CORS_ORIGIN || "*",
methods: ["GET", "POST"],
},
});

ioServer = io;

io.on("connection", (socket) => {
const userId =
(socket.handshake.query.userId as string) ||
(socket.handshake.headers["user-id"] as string);

if (userId) {
userSocketMap.set(userId, socket.id);
}
const io = new Server(server, {
cors: {
origin: process.env.CORS_ORIGIN || "*",
methods: ["GET", "POST"],
},
});

ioServer = io;

io.on("connection", (socket) => {
const userId =
(socket.handshake.query.userId as string) ||
(socket.handshake.headers["user-id"] as string);
const gameType =
(socket.handshake.query.gameType as string) ||
(socket.handshake.headers["game-type"] as string);

console.log("A user connected", socket.id, userSocketMap);
if (userId) {
userSocketMap.set(userId, socket.id);
}

// Send initial rooms list
socket.emit("rooms:list", roomManager.listRooms());
console.log("A user connected", socket.id, userSocketMap);

// Register all event handlers
registerRoomEvents(io, socket, roomManager);
registerGameEvents(io, socket, roomManager, userSocketMap);
registerChatEvents(io, socket);
registerDisconnectEvents(io, socket, roomManager);
});
// Send initial rooms list filtered by game type
const filteredRooms = roomManager
.listRooms()
.filter((room) => (gameType ? room.gameType === gameType : true));
socket.emit("rooms:list", { gameType, rooms: filteredRooms });

io.on("connect_error", (err) => {
logger.error("Global socket connection error", { error: err });
});
// Register all event handlers
registerRoomEvents(io, socket, roomManager);
registerGameEvents(io, socket, roomManager, userSocketMap);
registerChatEvents(io, socket);
registerDisconnectEvents(io, socket, roomManager);
});

return io;
io.on("connect_error", (err) => {
logger.error("Global socket connection error", { error: err });
});

return io;
}

export const getIO = (): Server => {
if (!ioServer) {
throw new Error("Socket.io not initialized! Call initSocket first.");
}
return ioServer;
if (!ioServer) {
throw new Error("Socket.io not initialized! Call initSocket first.");
}
return ioServer;
};
30 changes: 16 additions & 14 deletions backend/src/types/room.type.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
export interface Room {
id: string;
name: string;
players: Set<string>;
createdAt: Date;
gameType?: "tictactoe" | "snake" | "rps";
gameState?: any;
gameId?: string;
id: string;
name: string;
hostId: string;
players: Set<string>;
createdAt: Date;
gameType?: "tictactoe" | "snake" | "rps";
gameState?: any;
gameId?: string;
}

export interface RoomInfo {
id: string;
name: string;
playerCount: number;
players: string[];
createdAt: Date;
gameType?: string;
gameId?: string;
id: string;
name: string;
hostId: string;
playerCount: number;
players: string[];
createdAt: Date;
gameType?: string;
gameId?: string;
}
Loading