From f52bea91ac0790889953e548fdc86bb52c5a4e91 Mon Sep 17 00:00:00 2001 From: Jose Conde Date: Wed, 24 Jul 2024 22:38:34 +0200 Subject: [PATCH] adding asocket.io room management --- .hmrc | 8 +-- CHANGELOG.md | 4 ++ package.json | 6 +- public/CHANGELOG.html | 5 ++ src/game/DominoesGame.ts | 15 +++-- src/game/MatchSession.ts | 4 +- src/game/dto/GameState.ts | 6 +- src/game/dto/GameSummary.ts | 2 + src/game/dto/MatchSessionOptions.ts | 1 + src/game/dto/MatchSessionState.ts | 3 + src/game/dto/PlayerDto.ts | 8 +++ src/game/entities/Board.ts | 2 + src/game/entities/PlayerMove.ts | 11 ++++ src/server/controllers/AuthController.ts | 61 ++++++++++++++----- src/server/controllers/UpdaterController.ts | 10 +-- src/server/db/DbAdapter.ts | 1 + src/server/db/interfaces.ts | 6 ++ .../db/mongo/UserSessionMongoManager.ts | 37 +++++++++++ src/server/managers/SecurityManager.ts | 4 +- src/server/services/InteractionService.ts | 1 - .../services/PlayerNotificationService.ts | 14 +++-- src/server/services/SocketIoService.ts | 11 ++-- 22 files changed, 170 insertions(+), 50 deletions(-) create mode 100644 src/server/db/mongo/UserSessionMongoManager.ts diff --git a/.hmrc b/.hmrc index d4489dd..ccf8ad9 100644 --- a/.hmrc +++ b/.hmrc @@ -2,7 +2,7 @@ "path": "G:\\Other\\Development\\Projects\\[ideas]\\domino", "name": "domino-server", "initialVersion": "0.1.1", - "version": "0.1.4", + "version": "0.1.5", "docker": { "useRegistry": true, "registry": "192.168.1.115:5000", @@ -75,7 +75,7 @@ }, "_backup": { "name": "domino-server", - "version": "0.1.3", + "version": "0.1.4", "description": "", "main": "index.js", "engines": { @@ -88,8 +88,8 @@ "test": "node --env-file=.env -r ts-node/register src/test.ts", "test:watch": "node --env-file=.env --watch -r ts-node/register src/test.ts", "docker-build": "docker build -t 192.168.1.115:5000/arhuako/domino-server:latest .", - "docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-server:latest 192.168.1.115:5000/arhuako/domino-server:0.1.3", - "docker-push": "docker push 192.168.1.115:5000/arhuako/domino-server:latest && docker push 192.168.1.115:5000/arhuako/domino-server:0.1.3", + "docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-server:latest 192.168.1.115:5000/arhuako/domino-server:0.1.4", + "docker-push": "docker push 192.168.1.115:5000/arhuako/domino-server:latest && docker push 192.168.1.115:5000/arhuako/domino-server:0.1.4", "publish": "npm run docker-build && npm run docker-tag && npm run docker-push" }, "keywords": [], diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b0e7f..2d6c944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 0.1.5 - 2024-07-24 +### Added +- socket.io room management + ## 0.1.4 - 2024-07-20 ## 0.1.3 - 2024-07-18 diff --git a/package.json b/package.json index 1961a19..7f4fea9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "domino-server", - "version": "0.1.4", + "version": "0.1.5", "description": "", "main": "index.js", "engines": { @@ -13,8 +13,8 @@ "test": "node --env-file=.env -r ts-node/register src/test.ts", "test:watch": "node --env-file=.env --watch -r ts-node/register src/test.ts", "docker-build": "docker build -t 192.168.1.115:5000/arhuako/domino-server:latest .", - "docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-server:latest 192.168.1.115:5000/arhuako/domino-server:0.1.4", - "docker-push": "docker push 192.168.1.115:5000/arhuako/domino-server:latest && docker push 192.168.1.115:5000/arhuako/domino-server:0.1.4", + "docker-tag": "docker tag 192.168.1.115:5000/arhuako/domino-server:latest 192.168.1.115:5000/arhuako/domino-server:0.1.5", + "docker-push": "docker push 192.168.1.115:5000/arhuako/domino-server:latest && docker push 192.168.1.115:5000/arhuako/domino-server:0.1.5", "publish": "npm run docker-build && npm run docker-tag && npm run docker-push" }, "keywords": [], diff --git a/public/CHANGELOG.html b/public/CHANGELOG.html index c69d4d3..a956f19 100644 --- a/public/CHANGELOG.html +++ b/public/CHANGELOG.html @@ -1,5 +1,10 @@

Changelog

All notable changes to this project will be documented in this file.

+

0.1.5 - 2024-07-24

+

Added

+

0.1.4 - 2024-07-20

0.1.3 - 2024-07-18

Added

diff --git a/src/game/DominoesGame.ts b/src/game/DominoesGame.ts index 76592a8..f409f72 100644 --- a/src/game/DominoesGame.ts +++ b/src/game/DominoesGame.ts @@ -144,7 +144,7 @@ export class DominoesGame extends EventEmitter { playTurn() { try { const player = this.players[this.currentPlayerIndex]; - this.notificationService.sendEventToPlayers('server:next-turn', this.players, this.getGameState()); + this.notificationService.sendEventToPlayers('server:next-turn', this.players, this.getState()); this.logger.debug(`${player.name}'s turn (${player.hand.length} tiles)`); this.printPlayerHand(player); printBoard(this.board) @@ -222,6 +222,7 @@ export class DominoesGame extends EventEmitter { players: this.players.map(player => player.getState(true)), board: this.board.tiles.map(tile => tile.getState(true)), boneyard: this.board.boneyard.map(tile => tile.getState(true)), + movements: this.board.movements } this.emit('game-over', summary); } @@ -264,7 +265,7 @@ export class DominoesGame extends EventEmitter { this.deal(); const extractStates = (p: PlayerInterface) => ({ player: p.getState(true), - gameState: this.getGameState() + gameState: this.getState() }); await this.notificationService.sendEventToPlayers('server:hand-dealt', this.players, extractStates); @@ -325,11 +326,14 @@ export class DominoesGame extends EventEmitter { } } - getGameState(): GameState { + getState(): GameState { const currentPlayer = this.players[this.currentPlayerIndex] + const lastMove = this.lastMove?.getState() || null; + const movements = this.board.movements.map(move => move.getState()); + return { id: uuid(), - lastMove: this.lastMove, + lastMove, gameInProgress: this.gameInProgress, winner: this.winner, tileSelectionPhase: this.tileSelectionPhase, @@ -337,10 +341,11 @@ export class DominoesGame extends EventEmitter { gameTied: this.gameTied, gameId: this.id, boneyard: this.board.boneyard.map(tile => tile.getState(false)), - players: this.players.map(player => player.getState()), + players: this.players.map(player => player.getState(false)), currentPlayer: currentPlayer.getState(), board: this.board.tiles.map(tile => tile.getState(true)), boardFreeEnds: this.board.getFreeEnds(), + movements } } diff --git a/src/game/MatchSession.ts b/src/game/MatchSession.ts index 2f98894..c004ae6 100644 --- a/src/game/MatchSession.ts +++ b/src/game/MatchSession.ts @@ -26,6 +26,7 @@ export class MatchSession { private clientsReady: string[] = []; private gameSummaries: GameSummary[] = []; private sessionService: SessionService = new SessionService(); + private room: string; id: string; matchInProgress: boolean = false; @@ -46,6 +47,7 @@ export class MatchSession { const { sessionName, seed, winType, winTarget } = options; this.seed = seed || getRandomSeed(); this.id = uuid(); + this.room = `room-${this.id}`; this.name = sessionName || `Match ${this.id}`; this.addPlayerToSession(creator); this.creator = creator; @@ -187,7 +189,6 @@ export class MatchSession { }); } else { this.status = 'waiting' - // await this.playerNotificationManager.notifyMatchState(this); this.notificationService.sendEventToPlayers('server:game-finished', this.players, { lastGame: gameSummary, sessionState: this.getState(true) @@ -397,6 +398,7 @@ export class MatchSession { matchInProgress: this.matchInProgress, gameSummaries: this.gameSummaries, options: this.options, + room: this.room, }; } diff --git a/src/game/dto/GameState.ts b/src/game/dto/GameState.ts index fda4a26..5b46892 100644 --- a/src/game/dto/GameState.ts +++ b/src/game/dto/GameState.ts @@ -1,5 +1,4 @@ -import { PlayerMove } from "../entities/PlayerMove"; -import { PlayerDto } from "./PlayerDto"; +import { PlayerDto, PlayerMoveDto } from "./PlayerDto"; export interface GameState { id: string; @@ -14,5 +13,6 @@ export interface GameState { gameId: string; tileSelectionPhase: boolean; boardFreeEnds: number[]; - lastMove: PlayerMove | null; + lastMove: PlayerMoveDto | null; + movements: PlayerMoveDto[]; } \ No newline at end of file diff --git a/src/game/dto/GameSummary.ts b/src/game/dto/GameSummary.ts index 8e7c571..a79a07e 100644 --- a/src/game/dto/GameSummary.ts +++ b/src/game/dto/GameSummary.ts @@ -1,4 +1,5 @@ import { Score } from "../../server/db/interfaces"; +import { PlayerMove } from "../entities/PlayerMove"; import { PlayerDto, TileDto } from "./PlayerDto"; export interface GameSummary { @@ -10,4 +11,5 @@ export interface GameSummary { players?: PlayerDto[]; board: TileDto[] boneyard: TileDto[] + movements: PlayerMove[] } \ No newline at end of file diff --git a/src/game/dto/MatchSessionOptions.ts b/src/game/dto/MatchSessionOptions.ts index 84e62ee..78018c2 100644 --- a/src/game/dto/MatchSessionOptions.ts +++ b/src/game/dto/MatchSessionOptions.ts @@ -10,4 +10,5 @@ export interface MatchSessionOptions { seed: string sessionName: string numPlayers: 1 | 2 | 3 | 4 + turnWaitSeconds: number } \ No newline at end of file diff --git a/src/game/dto/MatchSessionState.ts b/src/game/dto/MatchSessionState.ts index 437ab8c..3d662bd 100644 --- a/src/game/dto/MatchSessionState.ts +++ b/src/game/dto/MatchSessionState.ts @@ -1,4 +1,5 @@ import { Score } from "../../server/db/interfaces"; +import { GameState } from "./GameState"; import { GameSummary } from "./GameSummary"; import { MatchSessionOptions } from "./MatchSessionOptions"; import { PlayerDto } from "./PlayerDto"; @@ -22,4 +23,6 @@ export interface MatchSessionState { playersReady: number, gameSummaries: GameSummary[]; options: MatchSessionOptions + currentGame?: GameState + room: string } \ No newline at end of file diff --git a/src/game/dto/PlayerDto.ts b/src/game/dto/PlayerDto.ts index 4de00e7..844af97 100644 --- a/src/game/dto/PlayerDto.ts +++ b/src/game/dto/PlayerDto.ts @@ -14,4 +14,12 @@ export interface PlayerDto { teamedWith?: string; ready: boolean; isHuman: boolean; +} + +export interface PlayerMoveDto { + id: string; + tile: TileDto + type: string | null; + playerId: string; + direction?: string; } \ No newline at end of file diff --git a/src/game/entities/Board.ts b/src/game/entities/Board.ts index 7d60a41..164317f 100644 --- a/src/game/entities/Board.ts +++ b/src/game/entities/Board.ts @@ -9,6 +9,7 @@ export class Board { tiles: Tile[] = []; boneyard: Tile[] = []; logger = new LoggingService(); + movements: PlayerMove[] = []; constructor(private rng: PRNG) {} @@ -64,6 +65,7 @@ export class Board { this.playTileRight(tile); // printLine(`${tile} -- right`); } + this.movements.push(playerMove); } playTileLeft(tile: Tile) { diff --git a/src/game/entities/PlayerMove.ts b/src/game/entities/PlayerMove.ts index 3f60d02..ee10dfe 100644 --- a/src/game/entities/PlayerMove.ts +++ b/src/game/entities/PlayerMove.ts @@ -1,5 +1,6 @@ import { uuid } from "../../common/utilities"; import { PlayerMoveSideType } from "../constants"; +import { PlayerMoveDto } from "../dto/PlayerDto"; import { Tile } from "./Tile"; export class PlayerMove { @@ -9,4 +10,14 @@ export class PlayerMove { toString() { return `PlayerMove:([${this.tile.pips[0]}|${this.tile.pips[1]}] ${this.type})`; } + + getState(): PlayerMoveDto { + return { + id: this.id, + tile: this.tile.getState(), + type: this.type, + playerId: this.playerId, + direction: this.direction, + }; + } } \ No newline at end of file diff --git a/src/server/controllers/AuthController.ts b/src/server/controllers/AuthController.ts index a5cecc1..b63bbb7 100644 --- a/src/server/controllers/AuthController.ts +++ b/src/server/controllers/AuthController.ts @@ -6,49 +6,72 @@ import { TemporalTokenMongoManager } from '../db/mongo/TemporalTokenMongoManager import { BaseController } from './BaseController'; import { NextFunction, Request, Response } from 'express'; import { AuthenticationOption, Token, User } from '../db/interfaces'; +import { UserSessionMongoManager } from '../db/mongo/UserSessionMongoManager'; export class AuthController extends BaseController { security = new SecurityManager(); usersManager = new UsersMongoManager(); temporalTokenManager = new TemporalTokenMongoManager(); + userSessionManager = new UserSessionMongoManager(); async login(req: Request, res: Response): Promise { const { log } = req; try { - let token = null const { username, password } = req.body; - this.logger.debug('login', username, password); const { valid: isValidPassword, user } = await this._checkPassword(username, password); - this.logger.debug('isValidPassword', isValidPassword); - if (!isValidPassword) { + if (!isValidPassword || user === null) { res.status(401).json({ error: 'Unauthorized' }).end(); log.error('Unauthorized login attempt for user: ', username); return; } - this._jwtSignUser(user, res) + delete user.hash; + let sessionId = await this.userSessionManager.renewSession(user.id); + const token = await this.security.signJwt({ sessionId, user}, false); + if (token === null) { + res.status(401).json({ error: 'Unauthorized' }).end(); + return; + } + const refreshToken = await this.security.signJwt({ sessionId, user}, true); + res.status(200).json({ token, refreshToken }).end(); } catch (error) { this.handleError(res, error); } } async refresh(req: Request, res: Response): Promise { - const { log } = req; try { - const { token } = req.body; - const user = await this.security.verifyJwt(token); - this._jwtSignUser(user, res, true); + const { refreshToken } = req.body; + if (!refreshToken) { + res.status(401).json({ error: 'Unauthorized' }).end(); + return; + } + const data = await this.security.verifyJwt(refreshToken); + const { uuid: sessionId } = await this.userSessionManager.getByUuid(data.sessionId) || { uuid: undefined }; + if (!data.sessionId || !data.user || data.sessionId !== sessionId) { + res.status(401).json({ error: 'Unauthorized' }).end(); + return; + } + const newToken = await this.security.signJwt(data, false); + res.status(200).json({ token: newToken }).end(); } catch (error) { - this.handleError(res, error); + res.status(401).json({ error: 'Unauthorized' }).end(); } } - _jwtSignUser(user: User | null, res: Response, isRefresh: boolean = false) { + async _jwtSignUser(user: User | null, res: Response, isFromRefresh: boolean = false) { if (user === null) { res.status(401).json({ error: 'Unauthorized' }).end(); return; } delete user.hash; - const token = this.security.signJwt(user, false); + let uuid; + if (!isFromRefresh) { + uuid = await this.userSessionManager.renewSession(user.id); + } else { + const userSession = await this.userSessionManager.getUserSession(user.id); + uuid = userSession?.uuid; + } + const token = this.security.signJwt({ sessionId: uuid, user}, false); if (token === null) { res.status(401).json({ error: 'Unauthorized' }).end(); } else { @@ -56,8 +79,8 @@ export class AuthController extends BaseController { token: string, refreshToken?: string } = { token }; - if (!isRefresh) { - data.refreshToken = this.security.signJwt(user, true); + if (!isFromRefresh) { + data.refreshToken = this.security.signJwt({ sessionId: uuid, user}, true); } res.status(200).json(data).end(); } @@ -177,21 +200,27 @@ export class AuthController extends BaseController { static authenticate(options: AuthenticationOption = {}) { return async function(req: Request, res: Response, next: NextFunction) { const security = new SecurityManager(); + const userSessionManager = new UserSessionMongoManager(); const token = req.headers.authorization; const { roles = [] } = options; if (!token) { return res.status(401).json({ error: 'Unauthorized' }); } try { - const user: User = await security.verifyJwt(token); + const parsed = await security.verifyJwt(token); + const user: User = parsed.user; + const userSession = await userSessionManager.getUserSession(user.id); const validRoles = await AuthController.checkRoles(user, roles); if (!validRoles) { return res.status(403).json({ error: 'Forbidden' }); } + if (userSession?.uuid !== parsed.sessionId) { + return res.status(401).json({ error: 'Unauthorized' }); + } req.user = user; next(); } catch (error) { - return res.status(401).json({ error: 'Unauthorized' }); + return res.status(401).json({ error: 'Token expired' }); } } } diff --git a/src/server/controllers/UpdaterController.ts b/src/server/controllers/UpdaterController.ts index 9735388..d144ef2 100644 --- a/src/server/controllers/UpdaterController.ts +++ b/src/server/controllers/UpdaterController.ts @@ -2,13 +2,13 @@ import { Request, Response } from "express"; import { BaseController } from "./BaseController"; const json = { - "version": "0.1.10", - "notes": "ADDEDD\n======\n- Updater\n- Refresh authentication when expires\n- Match summary page phase 1", + "version": "0.1.12", + "notes": "- v0.1.12\nAdded: I18n translations\nAdded: Win conditions\nFixed: Multiplayer join button not accessible\n- v0.1.8\nAdded: Updater\nAdded: Refresh authentication when expires\nAdded: Match summary page phase 1", "pub_date": "2024-07-20T10:25:57Z", "platforms": { "windows-x86_64": { - "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVTdDh5VEM1Y1hnUUF0N0lJVEl0SDM0QnAvRCs0OXpzMUhyQ3A3UHNxbUsrSWFMOWFDTkJqVVZBRXdNWmR3ME5hUU8wUEh4ajhaUktoZGEycFhoaFpwTno2WlZBRlhaRHdrPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzIxNDgwMDM3CWZpbGU6ZG9taW5vLWNsaWVudF8wLjEuMTBfeDY0LXNldHVwLm5zaXMuemlwCk0rTDNUR3N6WHY5VnRRQU9hRnVFQnQybStFcndYRDRQY0hQNng1eFFDKzFvVngzaXhOaGZRRjBndkhxYXQxUkNrT1RNcHo2enM0VXh0eUJITHlveENnPT0K", - "url": "https://test.xintanalabs.net/updates/domino-client_0.1.10_x64-setup.nsis.zip" + "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVTdDh5VEM1Y1hnUUVXbkxjSWVCTHE1cGhmd291QWFaODdFTGJINlhHNzhkU0lOZjRETERYZFZsUkpySmZONXpSdnBvMHFjOFd6UEpFVGxyRjNPRlpRVGkvTytqeU9KK1FnPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzIxNjY1NTU5CWZpbGU6ZG9taW5vLWNsaWVudF8wLjEuMTJfeDY0LXNldHVwLm5zaXMuemlwClcxVXJOMmx2T3pGUlpqUTJXTWpNeHAveGR5ZkUxQVFQOVc4MjhuQVVJSkJ2bUw0eS8vZWtwR0dmWWhkd2t5RGNCVGQ5V09ORGp0VENUTGFBbkFBK0J3PT0K", + "url": "https://domserv.xintanalabs.net/updates/domino-client_0.1.12_x64-setup.nsis.zip" } } } @@ -18,7 +18,7 @@ export class UpdaterController extends BaseController { this.logger.info('Checking for updates'); return res.json(json).status(200).end(); - return res.status(204).end(); + // return res.status(204).end(); } // async startMatchSession(data: any): Promise { diff --git a/src/server/db/DbAdapter.ts b/src/server/db/DbAdapter.ts index 0adcd24..182bb76 100644 --- a/src/server/db/DbAdapter.ts +++ b/src/server/db/DbAdapter.ts @@ -18,6 +18,7 @@ export function matchSessionAdapter(session: MatchSession, showPips: boolean = f status: state.status, matchInProgress: state.matchInProgress, gameSummaries: state.gameSummaries, + room: state.room } } \ No newline at end of file diff --git a/src/server/db/interfaces.ts b/src/server/db/interfaces.ts index a4ad7c6..b1557eb 100644 --- a/src/server/db/interfaces.ts +++ b/src/server/db/interfaces.ts @@ -61,6 +61,7 @@ export interface DbMatchSession extends EntityMongo { status: string; matchInProgress: boolean; gameSummaries: GameSummary[]; + room: string; } export interface DbUser extends EntityMongo { @@ -115,4 +116,9 @@ export interface DbListResponse{ } sort?: any; data: EntityMongo[]; +} + +export interface UserSession extends EntityMongo { + userId: string; + uuid: string; } \ No newline at end of file diff --git a/src/server/db/mongo/UserSessionMongoManager.ts b/src/server/db/mongo/UserSessionMongoManager.ts new file mode 100644 index 0000000..7992041 --- /dev/null +++ b/src/server/db/mongo/UserSessionMongoManager.ts @@ -0,0 +1,37 @@ +import { uuid } from "../../../common/utilities"; +import { UserSession } from "../interfaces"; +import { BaseMongoManager } from "./common/BaseMongoManager"; + +export class UserSessionMongoManager extends BaseMongoManager { + collection = 'userSessions'; + constructor() { + super(); + } + + async createSession(userId: string): Promise { + const uid: string = uuid(); + const userSession: UserSession = { + userId, + uuid: uid + } + await this.create(userSession); + return uid; + } + + async removeSession(userId: string): Promise { + return this.deleteByFilter({ userId }); + } + + async renewSession(userId: string): Promise { + await this.removeSession(userId); + return this.createSession(userId); + } + + async getUserSession(userId: string): Promise { + return this.getByFilter({ userId }) as Promise; + } + + async getByUuid(uuid: string): Promise { + return this.getByFilter({ uuid }) as Promise; + } +} diff --git a/src/server/managers/SecurityManager.ts b/src/server/managers/SecurityManager.ts index 83b1ecb..22dcaf3 100644 --- a/src/server/managers/SecurityManager.ts +++ b/src/server/managers/SecurityManager.ts @@ -29,13 +29,13 @@ export class SecurityManager extends ManagerBase { } // TODO: verificar esto - async verifyJwt(token: string): Promise { + async verifyJwt(token: string): Promise { return new Promise((resolve, reject) => { jwt.verify(token, this.jwtSecretKey, (err, decoded) => { if (err) { reject(err); } else { - resolve(decoded as User); + resolve(decoded); } }); }); diff --git a/src/server/services/InteractionService.ts b/src/server/services/InteractionService.ts index 9be5bb0..3277fef 100644 --- a/src/server/services/InteractionService.ts +++ b/src/server/services/InteractionService.ts @@ -97,7 +97,6 @@ export class InteractionService extends ServiceBase{ }; } } - private onPlayerReady(data: any): any { const { userId, sessionId } = data; const session: MatchSession | undefined = this.sessionManager.getSession(sessionId); diff --git a/src/server/services/PlayerNotificationService.ts b/src/server/services/PlayerNotificationService.ts index 643a5a7..71edf76 100644 --- a/src/server/services/PlayerNotificationService.ts +++ b/src/server/services/PlayerNotificationService.ts @@ -10,23 +10,23 @@ export class PlayerNotificationService extends ServiceBase { clientNotifier: NetworkClientNotifier = new NetworkClientNotifier(); notifyGameState(game: DominoesGame) { - const gameState: GameState = game.getGameState(); + const gameState: GameState = game.getState(); const { players } = game; - players.map(player => player.sendEvent('update-game-state', gameState)); + players.filter(p => p instanceof NetworkPlayer).map(player => player.sendEvent('update-game-state', gameState)); } notifyPlayersState(players: PlayerInterface[]) { - players.map(player => player.sendEvent('update-player-state', player.getState())); + players.filter(p => p instanceof NetworkPlayer).map(player => player.sendEvent('update-player-state', player.getState())); } notifyMatchState(session: MatchSession) { const { players } = session; - players.map(player => player.sendEvent('update-match-session-state', session.getState())); + players.filter(p => p instanceof NetworkPlayer).forEach(player => player.sendEvent('update-match-session-state', session.getState())); } async sendEventToPlayers(event: string, players: PlayerInterface[], data: Function | any = {}) { - players.forEach((player) => { + players.filter(p => p instanceof NetworkPlayer).forEach((player) => { let dataTosend = data; if (typeof data === 'function') { dataTosend = data(player); @@ -37,6 +37,8 @@ export class PlayerNotificationService extends ServiceBase { sendEvent(event: string, player: PlayerInterface, data: any = {}) { this.logger.debug(`Sending event '${event}' to player ${player.id}`); - this.clientNotifier.sendEvent(player as NetworkPlayer, event, data); + if (player instanceof NetworkPlayer) { + this.clientNotifier.sendEvent(player as NetworkPlayer, event, data); + } } } \ No newline at end of file diff --git a/src/server/services/SocketIoService.ts b/src/server/services/SocketIoService.ts index 5ceee90..f8fa410 100644 --- a/src/server/services/SocketIoService.ts +++ b/src/server/services/SocketIoService.ts @@ -2,7 +2,6 @@ import { Server as HttpServer } from "http"; import { ServiceBase } from "./ServiceBase"; import { Server } from "socket.io"; import { SecurityManager } from "../managers/SecurityManager"; -import { User } from "../db/interfaces"; import { Socket } from "socket.io"; import { InteractionService } from "./InteractionService"; import { ClientEvents } from "../../game/constants"; @@ -24,7 +23,7 @@ export class SocketIoService extends ServiceBase { if (socket.handshake.auth && socket.handshake.auth.token) { const token = socket.handshake.auth.token; try { - const user: User = await this.security.verifyJwt(token); + const { user } = await this.security.verifyJwt(token); socket.user = user; next(); } catch (err) { @@ -61,8 +60,7 @@ export class SocketIoService extends ServiceBase { if (user !== undefined && user._id !== undefined) { const userId = user._id.toString(); if (!SocketIoService.clients.has(userId)) { - SocketIoService.clients.set(userId, { socketId, alive: true, user: socket.user }); - socket.join('room-general') + SocketIoService.clients.set(userId, { socketId, alive: true, user: socket.user }); } else { const client = SocketIoService.clients.get(userId); this.interactionService.updateSocketId(client.sessionId, userId, socketId); @@ -83,6 +81,11 @@ export class SocketIoService extends ServiceBase { } }); + socket.on('client:join-room', (room) => { + socket.join(room); + this.logger.debug(`User ${socket.user?.username} joined room ${room}`); + }); + socket.on(ClientEvents.CLIENT_EVENT, (data) => { this.interactionService.handleClientEvent(data); });