import { Socket } from "socket.io"; import User from "./User"; import Room, { RoomOptions } from "./Room"; import { getCurrentTime } from "./util"; export default class Service { private roomIdToRooms = new Map(); private socketsToUsers = new Map(); get rooms(): Room[] { const rooms = []; for (const [, room] of this.roomIdToRooms) { rooms.push(room); } return rooms; } onSocketConnect(socket: Socket) { const user = new User(socket); this.socketsToUsers.set(socket.id, user); user.sync(); } async onSocketDisconnect(socket: Socket) { const user = this.getUser(socket); if (user.room != null) { await user.room.leave(user); } this.deleteEmptyRooms(); } onTimeSync(socket: Socket, requestId: number, clientTime: number) { const user = this.getUser(socket); const now = getCurrentTime(); user.emit("time_sync", { requestId: requestId, clientDiff: now - clientTime, serverTime: now, }); } onSetRoomOptions(socket: Socket, options: RoomOptions) { const user = this.getUser(socket); if (user.room?.getLeader() == user) { user.room.setOptions(options); } } onRequestStart(socket: Socket) { const user = this.getUser(socket); if (user.room?.getLeader() === user) { user.room.start(); user.room.sync(); } } async onRequestJoin(socket: Socket, roomId: number) { const user = this.getUser(socket); if (user.room && user.room.id == roomId) return false; if (user.room) { await user.room.leave(user); this.deleteEmptyRooms(); } if (!this.roomIdToRooms.has(roomId)) { this.createRoomWithId(roomId); } const room = this.roomIdToRooms.get(roomId); if (!room) { return false; } await room.join(user); return true; } onRequestSetReady(socket: Socket) { const user = this.getUser(socket); if (!user.room || user.readyToParticipate) return; user.readyToParticipate = true; user.room.sync(); } async onRequestJoinRandom(socket: Socket) { const user = this.getUser(socket); if (user.room) { await user.room.leave(user); this.deleteEmptyRooms(); } const room = this.createRandomRoom(); if (!room) throw Error("Too many rooms active"); await room.join(user); } hasRoomId(roomId: number): boolean { return this.roomIdToRooms.has(roomId); } submitTickerMessage(socket: Socket, message: string) { const user = this.getUser(socket); if (!user.room) { throw new Error("User has no room"); } user.room.submitTickerMessage(user, message); } private getUser(socket: Socket): User { const user = this.socketsToUsers.get(socket.id); if (!user) { throw new Error("User not found"); } return user; } private deleteEmptyRooms() { for (const room of this.roomIdToRooms.values()) { if (room.users.length == 0) { this.deleteRoom(room); } } } private createRandomRoom(): Room | null { let tries = 0; let i = 1; while (tries++ < 1000) { if (this.roomIdToRooms.has(i)) { i++; } else { return this.createRoomWithId(i); } } return null; } private createRoomWithId(roomId: number): Room { if (this.roomIdToRooms.has(roomId)) { throw new Error("A room with the given id already exists"); } const room = new Room(roomId); this.roomIdToRooms.set(roomId, room); return room; } private deleteRoom(room: Room) { this.roomIdToRooms.delete(room.id); } }