import {Socket} from "socket.io"; import User from './User' import Room from './Room' import {getCurrentTime, randomInt} from "./util"; export default class Service { private roomIdToRooms = new Map(); private socketsToUsers = new Map(); onSocketConnect(socket: Socket) { let user = new User(socket); this.socketsToUsers.set(socket.id, user); } onSocketDisconnect(socket: Socket) { let user = this.getUser(socket); if (user.room != null) { user.room.leave(user); } this.deleteEmptyRooms(); user.onDisconnect(); } onTimeSync(socket: Socket, requestId: number, clientTime: number) { let user = this.getUser(socket); let now = getCurrentTime(); user.emit('time_sync', { 'requestId': requestId, 'clientDiff': now - clientTime, 'serverTime': now }) } onRequestStart(socket: Socket) { let user = this.getUser(socket); if (user.room?.getLeader() == user) { user.room!!.start(); } } onRequestJoin(socket: Socket, roomId: number): boolean { let user = this.getUser(socket); if (!this.roomIdToRooms.has(roomId)) return false; if (user.room && user.room.id == roomId) return false; if (user.room) { user.room.leave(user); this.deleteEmptyRooms(); } let room = this.roomIdToRooms.get(roomId)!!; room.join(user); return true; } onRequestJoinRandom(socket: Socket) { let user = this.getUser(socket); if (user.room) { user.room.leave(user); this.deleteEmptyRooms(); } const room = this.createRandomRoom(); if (!room) throw Error('Too many rooms active'); room.join(user); } hasRoomId(roomId: number): boolean { return this.roomIdToRooms.has(roomId); } private getUser(socket: Socket): User { let user = this.socketsToUsers.get(socket.id); if (!user) { throw new Error('User not found'); } return user; } private deleteEmptyRooms() { for (let room of this.roomIdToRooms.values()) { if (room.users.length == 0) { this.deleteRoom(room); } } } private createRandomRoom(): Room | null { let tries = 0; while (tries++ < 1000) { const randomId = randomInt(100, Math.max(1000, this.roomIdToRooms.size * 2)); if (this.roomIdToRooms.has(randomId)) continue; return this.createRoomWithId(randomId); } return null; } private createRoomWithId(roomId: number): Room { if (this.roomIdToRooms.has(roomId)) { throw new Error('A room with the given id already exists'); } let room = new Room(roomId); this.roomIdToRooms.set(roomId, room); return room; } private deleteRoom(room: Room) { this.roomIdToRooms.get(room.id)!!.onBeforeDelete(); this.roomIdToRooms.delete(room.id) } }