adding asocket.io room management
This commit is contained in:
		@@ -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
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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[];
 | 
			
		||||
}  
 | 
			
		||||
@@ -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[]
 | 
			
		||||
}
 | 
			
		||||
@@ -10,4 +10,5 @@ export interface MatchSessionOptions {
 | 
			
		||||
  seed: string
 | 
			
		||||
  sessionName: string
 | 
			
		||||
  numPlayers: 1 | 2 | 3 | 4
 | 
			
		||||
  turnWaitSeconds: number
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<void> {
 | 
			
		||||
    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<void> {
 | 
			
		||||
    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' });
 | 
			
		||||
      }   
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<any> {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ export function matchSessionAdapter(session: MatchSession, showPips: boolean = f
 | 
			
		||||
        status: state.status,        
 | 
			
		||||
        matchInProgress: state.matchInProgress,
 | 
			
		||||
        gameSummaries: state.gameSummaries,
 | 
			
		||||
        room: state.room
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/server/db/mongo/UserSessionMongoManager.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/server/db/mongo/UserSessionMongoManager.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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<string> {
 | 
			
		||||
    const uid: string = uuid();
 | 
			
		||||
    const userSession: UserSession = {
 | 
			
		||||
      userId,
 | 
			
		||||
      uuid: uid
 | 
			
		||||
    }
 | 
			
		||||
    await this.create(userSession);
 | 
			
		||||
    return uid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async removeSession(userId: string): Promise<number> {
 | 
			
		||||
    return this.deleteByFilter({ userId });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async renewSession(userId: string): Promise<string> {
 | 
			
		||||
    await this.removeSession(userId);
 | 
			
		||||
    return this.createSession(userId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getUserSession(userId: string): Promise<UserSession | null> {
 | 
			
		||||
    return this.getByFilter({ userId }) as Promise<UserSession | null>;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getByUuid(uuid: string): Promise<UserSession | null> {
 | 
			
		||||
    return this.getByFilter({ uuid }) as Promise<UserSession | null>;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -29,13 +29,13 @@ export class SecurityManager extends ManagerBase {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: verificar esto
 | 
			
		||||
  async verifyJwt(token: string): Promise<User> {
 | 
			
		||||
  async verifyJwt(token: string): Promise<any> {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      jwt.verify(token, this.jwtSecretKey, (err, decoded) => {
 | 
			
		||||
        if (err) {
 | 
			
		||||
          reject(err);
 | 
			
		||||
        } else {
 | 
			
		||||
          resolve(decoded as User);
 | 
			
		||||
          resolve(decoded);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);  
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
      });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user