Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2346acc096 | ||
|
8fb6fac75d | ||
|
f52bea91ac | ||
|
0329e84548 |
8
.hmrc
8
.hmrc
@ -2,7 +2,7 @@
|
|||||||
"path": "G:\\Other\\Development\\Projects\\[ideas]\\domino",
|
"path": "G:\\Other\\Development\\Projects\\[ideas]\\domino",
|
||||||
"name": "domino-server",
|
"name": "domino-server",
|
||||||
"initialVersion": "0.1.1",
|
"initialVersion": "0.1.1",
|
||||||
"version": "0.1.3",
|
"version": "0.1.5",
|
||||||
"docker": {
|
"docker": {
|
||||||
"useRegistry": true,
|
"useRegistry": true,
|
||||||
"registry": "192.168.1.115:5000",
|
"registry": "192.168.1.115:5000",
|
||||||
@ -75,7 +75,7 @@
|
|||||||
},
|
},
|
||||||
"_backup": {
|
"_backup": {
|
||||||
"name": "domino-server",
|
"name": "domino-server",
|
||||||
"version": "0.1.2",
|
"version": "0.1.4",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -88,8 +88,8 @@
|
|||||||
"test": "node --env-file=.env -r ts-node/register src/test.ts",
|
"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",
|
"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-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.2",
|
"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.2",
|
"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"
|
"publish": "npm run docker-build && npm run docker-tag && npm run docker-push"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.1.5 - 2024-07-25
|
||||||
|
### Added
|
||||||
|
- socket.io room management
|
||||||
|
### Fixed
|
||||||
|
- Blocked game not waiting for all turns to complete
|
||||||
|
|
||||||
|
## 0.1.4 - 2024-07-20
|
||||||
|
|
||||||
## 0.1.3 - 2024-07-18
|
## 0.1.3 - 2024-07-18
|
||||||
### Added
|
### Added
|
||||||
- game by rounds
|
- game by rounds
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "domino-server",
|
"name": "domino-server",
|
||||||
"version": "0.1.3",
|
"version": "0.1.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -13,8 +13,8 @@
|
|||||||
"test": "node --env-file=.env -r ts-node/register src/test.ts",
|
"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",
|
"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-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-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.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.5",
|
||||||
"publish": "npm run docker-build && npm run docker-tag && npm run docker-push"
|
"publish": "npm run docker-build && npm run docker-tag && npm run docker-push"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<h1>Changelog</h1>
|
<h1>Changelog</h1>
|
||||||
<p>All notable changes to this project will be documented in this file.</p>
|
<p>All notable changes to this project will be documented in this file.</p>
|
||||||
|
<h2>0.1.5 - 2024-07-24</h2>
|
||||||
|
<h3>Added</h3>
|
||||||
|
<ul>
|
||||||
|
<li>socket.io room management</li>
|
||||||
|
</ul>
|
||||||
|
<h2>0.1.4 - 2024-07-20</h2>
|
||||||
<h2>0.1.3 - 2024-07-18</h2>
|
<h2>0.1.3 - 2024-07-18</h2>
|
||||||
<h3>Added</h3>
|
<h3>Added</h3>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Domino Tiles</title>
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="domino" data-top="1" data-bottom="5">
|
|
||||||
<div class="half top"></div>
|
|
||||||
<div class="half bottom"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="domino" data-top="1" data-bottom="5">
|
|
||||||
<div class="half top"></div>
|
|
||||||
<div class="half bottom"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="script.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||||||
document.querySelectorAll('.domino').forEach(domino => {
|
|
||||||
const topValue = domino.getAttribute('data-top');
|
|
||||||
const bottomValue = domino.getAttribute('data-bottom');
|
|
||||||
|
|
||||||
addPips(domino.querySelector('.top'), topValue);
|
|
||||||
addPips(domino.querySelector('.bottom'), bottomValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
function addPips(half, value) {
|
|
||||||
const pipPositions = getPipPositions(value);
|
|
||||||
pipPositions.forEach(pos => {
|
|
||||||
const pip = document.createElement('div');
|
|
||||||
pip.className = 'pip';
|
|
||||||
pip.style.left = pos[0];
|
|
||||||
pip.style.top = pos[1];
|
|
||||||
half.appendChild(pip);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPipPositions(value) {
|
|
||||||
const p1 = '17%';
|
|
||||||
const p2 = '42%';
|
|
||||||
const p3 = '67%';
|
|
||||||
|
|
||||||
const positions = {
|
|
||||||
0: [],
|
|
||||||
1: [[p2, p2]],
|
|
||||||
2: [[p1, p1], [p3, p3]],
|
|
||||||
3: [[p1, p1], [p2, p2], [p3, p3]],
|
|
||||||
4: [[p1, p1], [p1, p3], [p3, p1], [p3, p3]],
|
|
||||||
5: [[p1, p1], [p1, p3], [p2, p2], [p3, p1], [p3, p3]],
|
|
||||||
6: [[p1, p1], [p1, p3], [p2, p1], [p2, p3], [p3, p1], [p3, p3]],
|
|
||||||
};
|
|
||||||
return positions[value];
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
body {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
background: #f0f0f0;
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.domino {
|
|
||||||
width: 100px;
|
|
||||||
height: 200px;
|
|
||||||
background: white;
|
|
||||||
border: 2px solid black;
|
|
||||||
border-radius: 10px;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.half {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top {
|
|
||||||
border-bottom: 2px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
background: black;
|
|
||||||
border-radius: 50%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="1"] {
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="2"] {
|
|
||||||
left: 25%;
|
|
||||||
top: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="3"] {
|
|
||||||
right: 25%;
|
|
||||||
top: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="4"] {
|
|
||||||
left: 25%;
|
|
||||||
bottom: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="5"] {
|
|
||||||
right: 25%;
|
|
||||||
bottom: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="6"] {
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pip[data-number="7"] {
|
|
||||||
right: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(50%, -50%);
|
|
||||||
}
|
|
@ -97,7 +97,7 @@ export class DominoesGame extends EventEmitter {
|
|||||||
tiles.push(...player.hand);
|
tiles.push(...player.hand);
|
||||||
}
|
}
|
||||||
const canPlay = tiles.some(tile => tile.pips[0] === freeEnds[0] || tile.pips[1] === freeEnds[0] || tile.pips[0] === freeEnds[1] || tile.pips[1] === freeEnds[1]);
|
const canPlay = tiles.some(tile => tile.pips[0] === freeEnds[0] || tile.pips[1] === freeEnds[0] || tile.pips[0] === freeEnds[1] || tile.pips[1] === freeEnds[1]);
|
||||||
return !canPlay;
|
return this.blockedCount >= 4 && !canPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
isGameOver(): boolean {
|
isGameOver(): boolean {
|
||||||
@ -144,7 +144,7 @@ export class DominoesGame extends EventEmitter {
|
|||||||
playTurn() {
|
playTurn() {
|
||||||
try {
|
try {
|
||||||
const player = this.players[this.currentPlayerIndex];
|
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.logger.debug(`${player.name}'s turn (${player.hand.length} tiles)`);
|
||||||
this.printPlayerHand(player);
|
this.printPlayerHand(player);
|
||||||
printBoard(this.board)
|
printBoard(this.board)
|
||||||
@ -222,6 +222,7 @@ export class DominoesGame extends EventEmitter {
|
|||||||
players: this.players.map(player => player.getState(true)),
|
players: this.players.map(player => player.getState(true)),
|
||||||
board: this.board.tiles.map(tile => tile.getState(true)),
|
board: this.board.tiles.map(tile => tile.getState(true)),
|
||||||
boneyard: this.board.boneyard.map(tile => tile.getState(true)),
|
boneyard: this.board.boneyard.map(tile => tile.getState(true)),
|
||||||
|
movements: this.board.movements
|
||||||
}
|
}
|
||||||
this.emit('game-over', summary);
|
this.emit('game-over', summary);
|
||||||
}
|
}
|
||||||
@ -264,7 +265,7 @@ export class DominoesGame extends EventEmitter {
|
|||||||
this.deal();
|
this.deal();
|
||||||
const extractStates = (p: PlayerInterface) => ({
|
const extractStates = (p: PlayerInterface) => ({
|
||||||
player: p.getState(true),
|
player: p.getState(true),
|
||||||
gameState: this.getGameState()
|
gameState: this.getState()
|
||||||
});
|
});
|
||||||
await this.notificationService.sendEventToPlayers('server:hand-dealt', this.players, extractStates);
|
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 currentPlayer = this.players[this.currentPlayerIndex]
|
||||||
|
const lastMove = this.lastMove?.getState() || null;
|
||||||
|
const movements = this.board.movements.map(move => move.getState());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
lastMove: this.lastMove,
|
lastMove,
|
||||||
gameInProgress: this.gameInProgress,
|
gameInProgress: this.gameInProgress,
|
||||||
winner: this.winner,
|
winner: this.winner,
|
||||||
tileSelectionPhase: this.tileSelectionPhase,
|
tileSelectionPhase: this.tileSelectionPhase,
|
||||||
@ -337,10 +341,11 @@ export class DominoesGame extends EventEmitter {
|
|||||||
gameTied: this.gameTied,
|
gameTied: this.gameTied,
|
||||||
gameId: this.id,
|
gameId: this.id,
|
||||||
boneyard: this.board.boneyard.map(tile => tile.getState(false)),
|
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(),
|
currentPlayer: currentPlayer.getState(),
|
||||||
board: this.board.tiles.map(tile => tile.getState(true)),
|
board: this.board.tiles.map(tile => tile.getState(true)),
|
||||||
boardFreeEnds: this.board.getFreeEnds(),
|
boardFreeEnds: this.board.getFreeEnds(),
|
||||||
|
movements
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ export class MatchSession {
|
|||||||
private clientsReady: string[] = [];
|
private clientsReady: string[] = [];
|
||||||
private gameSummaries: GameSummary[] = [];
|
private gameSummaries: GameSummary[] = [];
|
||||||
private sessionService: SessionService = new SessionService();
|
private sessionService: SessionService = new SessionService();
|
||||||
|
private room: string;
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
matchInProgress: boolean = false;
|
matchInProgress: boolean = false;
|
||||||
@ -46,6 +47,7 @@ export class MatchSession {
|
|||||||
const { sessionName, seed, winType, winTarget } = options;
|
const { sessionName, seed, winType, winTarget } = options;
|
||||||
this.seed = seed || getRandomSeed();
|
this.seed = seed || getRandomSeed();
|
||||||
this.id = uuid();
|
this.id = uuid();
|
||||||
|
this.room = `room-${this.id}`;
|
||||||
this.name = sessionName || `Match ${this.id}`;
|
this.name = sessionName || `Match ${this.id}`;
|
||||||
this.addPlayerToSession(creator);
|
this.addPlayerToSession(creator);
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
@ -187,7 +189,6 @@ export class MatchSession {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.status = 'waiting'
|
this.status = 'waiting'
|
||||||
// await this.playerNotificationManager.notifyMatchState(this);
|
|
||||||
this.notificationService.sendEventToPlayers('server:game-finished', this.players, {
|
this.notificationService.sendEventToPlayers('server:game-finished', this.players, {
|
||||||
lastGame: gameSummary,
|
lastGame: gameSummary,
|
||||||
sessionState: this.getState(true)
|
sessionState: this.getState(true)
|
||||||
@ -397,6 +398,7 @@ export class MatchSession {
|
|||||||
matchInProgress: this.matchInProgress,
|
matchInProgress: this.matchInProgress,
|
||||||
gameSummaries: this.gameSummaries,
|
gameSummaries: this.gameSummaries,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
|
room: this.room,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { PlayerMove } from "../entities/PlayerMove";
|
import { PlayerDto, PlayerMoveDto } from "./PlayerDto";
|
||||||
import { PlayerDto } from "./PlayerDto";
|
|
||||||
|
|
||||||
export interface GameState {
|
export interface GameState {
|
||||||
id: string;
|
id: string;
|
||||||
@ -14,5 +13,6 @@ export interface GameState {
|
|||||||
gameId: string;
|
gameId: string;
|
||||||
tileSelectionPhase: boolean;
|
tileSelectionPhase: boolean;
|
||||||
boardFreeEnds: number[];
|
boardFreeEnds: number[];
|
||||||
lastMove: PlayerMove | null;
|
lastMove: PlayerMoveDto | null;
|
||||||
|
movements: PlayerMoveDto[];
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { Score } from "../../server/db/interfaces";
|
import { Score } from "../../server/db/interfaces";
|
||||||
|
import { PlayerMove } from "../entities/PlayerMove";
|
||||||
import { PlayerDto, TileDto } from "./PlayerDto";
|
import { PlayerDto, TileDto } from "./PlayerDto";
|
||||||
|
|
||||||
export interface GameSummary {
|
export interface GameSummary {
|
||||||
@ -10,4 +11,5 @@ export interface GameSummary {
|
|||||||
players?: PlayerDto[];
|
players?: PlayerDto[];
|
||||||
board: TileDto[]
|
board: TileDto[]
|
||||||
boneyard: TileDto[]
|
boneyard: TileDto[]
|
||||||
|
movements: PlayerMove[]
|
||||||
}
|
}
|
@ -10,4 +10,5 @@ export interface MatchSessionOptions {
|
|||||||
seed: string
|
seed: string
|
||||||
sessionName: string
|
sessionName: string
|
||||||
numPlayers: 1 | 2 | 3 | 4
|
numPlayers: 1 | 2 | 3 | 4
|
||||||
|
turnWaitSeconds: number
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { Score } from "../../server/db/interfaces";
|
import { Score } from "../../server/db/interfaces";
|
||||||
|
import { GameState } from "./GameState";
|
||||||
import { GameSummary } from "./GameSummary";
|
import { GameSummary } from "./GameSummary";
|
||||||
import { MatchSessionOptions } from "./MatchSessionOptions";
|
import { MatchSessionOptions } from "./MatchSessionOptions";
|
||||||
import { PlayerDto } from "./PlayerDto";
|
import { PlayerDto } from "./PlayerDto";
|
||||||
@ -22,4 +23,6 @@ export interface MatchSessionState {
|
|||||||
playersReady: number,
|
playersReady: number,
|
||||||
gameSummaries: GameSummary[];
|
gameSummaries: GameSummary[];
|
||||||
options: MatchSessionOptions
|
options: MatchSessionOptions
|
||||||
|
currentGame?: GameState
|
||||||
|
room: string
|
||||||
}
|
}
|
@ -15,3 +15,11 @@ export interface PlayerDto {
|
|||||||
ready: boolean;
|
ready: boolean;
|
||||||
isHuman: 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[] = [];
|
tiles: Tile[] = [];
|
||||||
boneyard: Tile[] = [];
|
boneyard: Tile[] = [];
|
||||||
logger = new LoggingService();
|
logger = new LoggingService();
|
||||||
|
movements: PlayerMove[] = [];
|
||||||
|
|
||||||
constructor(private rng: PRNG) {}
|
constructor(private rng: PRNG) {}
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ export class Board {
|
|||||||
this.playTileRight(tile);
|
this.playTileRight(tile);
|
||||||
// printLine(`${tile} -- right`);
|
// printLine(`${tile} -- right`);
|
||||||
}
|
}
|
||||||
|
this.movements.push(playerMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
playTileLeft(tile: Tile) {
|
playTileLeft(tile: Tile) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { uuid } from "../../common/utilities";
|
import { uuid } from "../../common/utilities";
|
||||||
import { PlayerMoveSideType } from "../constants";
|
import { PlayerMoveSideType } from "../constants";
|
||||||
|
import { PlayerMoveDto } from "../dto/PlayerDto";
|
||||||
import { Tile } from "./Tile";
|
import { Tile } from "./Tile";
|
||||||
|
|
||||||
export class PlayerMove {
|
export class PlayerMove {
|
||||||
@ -9,4 +10,14 @@ export class PlayerMove {
|
|||||||
toString() {
|
toString() {
|
||||||
return `PlayerMove:([${this.tile.pips[0]}|${this.tile.pips[1]}] ${this.type})`;
|
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,42 +6,83 @@ import { TemporalTokenMongoManager } from '../db/mongo/TemporalTokenMongoManager
|
|||||||
import { BaseController } from './BaseController';
|
import { BaseController } from './BaseController';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import { AuthenticationOption, Token, User } from '../db/interfaces';
|
import { AuthenticationOption, Token, User } from '../db/interfaces';
|
||||||
|
import { UserSessionMongoManager } from '../db/mongo/UserSessionMongoManager';
|
||||||
|
|
||||||
export class AuthController extends BaseController {
|
export class AuthController extends BaseController {
|
||||||
security = new SecurityManager();
|
security = new SecurityManager();
|
||||||
usersManager = new UsersMongoManager();
|
usersManager = new UsersMongoManager();
|
||||||
temporalTokenManager = new TemporalTokenMongoManager();
|
temporalTokenManager = new TemporalTokenMongoManager();
|
||||||
|
userSessionManager = new UserSessionMongoManager();
|
||||||
|
|
||||||
async login(req: Request, res: Response): Promise<void> {
|
async login(req: Request, res: Response): Promise<void> {
|
||||||
const { log } = req;
|
const { log } = req;
|
||||||
try {
|
try {
|
||||||
let token = null
|
|
||||||
const { username, password } = req.body;
|
const { username, password } = req.body;
|
||||||
this.logger.debug('login', username, password);
|
|
||||||
const { valid: isValidPassword, user } = await this._checkPassword(username, password);
|
const { valid: isValidPassword, user } = await this._checkPassword(username, password);
|
||||||
this.logger.debug('isValidPassword', isValidPassword);
|
if (!isValidPassword || user === null) {
|
||||||
if (!isValidPassword) {
|
|
||||||
res.status(401).json({ error: 'Unauthorized' }).end();
|
res.status(401).json({ error: 'Unauthorized' }).end();
|
||||||
log.error('Unauthorized login attempt for user: ', username);
|
log.error('Unauthorized login attempt for user: ', username);
|
||||||
return;
|
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) {
|
} catch (error) {
|
||||||
this.handleError(res, error);
|
this.handleError(res, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_jwtSignUser(user: User | null, res: Response) {
|
async refresh(req: Request, res: Response): Promise<void> {
|
||||||
|
try {
|
||||||
|
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) {
|
||||||
|
res.status(401).json({ error: 'Unauthorized' }).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _jwtSignUser(user: User | null, res: Response, isFromRefresh: boolean = false) {
|
||||||
if (user === null) {
|
if (user === null) {
|
||||||
res.status(401).json({ error: 'Unauthorized' }).end();
|
res.status(401).json({ error: 'Unauthorized' }).end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete user.hash;
|
delete user.hash;
|
||||||
const token = this.security.signJwt(user);
|
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) {
|
if (token === null) {
|
||||||
res.status(401).json({ error: 'Unauthorized' }).end();
|
res.status(401).json({ error: 'Unauthorized' }).end();
|
||||||
} else {
|
} else {
|
||||||
res.status(200).json({ token }).end();
|
const data: {
|
||||||
|
token: string,
|
||||||
|
refreshToken?: string
|
||||||
|
} = { token };
|
||||||
|
if (!isFromRefresh) {
|
||||||
|
data.refreshToken = this.security.signJwt({ sessionId: uuid, user}, true);
|
||||||
|
}
|
||||||
|
res.status(200).json(data).end();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -159,21 +200,27 @@ export class AuthController extends BaseController {
|
|||||||
static authenticate(options: AuthenticationOption = {}) {
|
static authenticate(options: AuthenticationOption = {}) {
|
||||||
return async function(req: Request, res: Response, next: NextFunction) {
|
return async function(req: Request, res: Response, next: NextFunction) {
|
||||||
const security = new SecurityManager();
|
const security = new SecurityManager();
|
||||||
|
const userSessionManager = new UserSessionMongoManager();
|
||||||
const token = req.headers.authorization;
|
const token = req.headers.authorization;
|
||||||
const { roles = [] } = options;
|
const { roles = [] } = options;
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return res.status(401).json({ error: 'Unauthorized' });
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
try {
|
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);
|
const validRoles = await AuthController.checkRoles(user, roles);
|
||||||
if (!validRoles) {
|
if (!validRoles) {
|
||||||
return res.status(403).json({ error: 'Forbidden' });
|
return res.status(403).json({ error: 'Forbidden' });
|
||||||
}
|
}
|
||||||
|
if (userSession?.uuid !== parsed.sessionId) {
|
||||||
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
|
}
|
||||||
req.user = user;
|
req.user = user;
|
||||||
next();
|
next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(403).json({ error: 'Forbidden' });
|
return res.status(401).json({ error: 'Token expired' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +241,7 @@ export class AuthController extends BaseController {
|
|||||||
req.token = apiToken;
|
req.token = apiToken;
|
||||||
next();
|
next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(403).json({ error: 'Forbidden' });
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
src/server/controllers/UpdaterController.ts
Normal file
50
src/server/controllers/UpdaterController.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import { BaseController } from "./BaseController";
|
||||||
|
|
||||||
|
const json = {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"notes": `- v0.2.0
|
||||||
|
Added: session expiration and renew handling
|
||||||
|
Added: Allow unique session per user
|
||||||
|
Added: Socket.io room management
|
||||||
|
Added: Game: added turn waiting timer
|
||||||
|
Added: Game: added timed button on game summaries
|
||||||
|
Added: Added new header
|
||||||
|
Added: New sound library (Howlerjs)
|
||||||
|
Fixed: pp data persistance
|
||||||
|
Fixed: Some other Fixes
|
||||||
|
- v0.1.12
|
||||||
|
Added: I18n translations
|
||||||
|
Added: Win conditions
|
||||||
|
Fixed: Multiplayer join button not accessible
|
||||||
|
- v0.1.8
|
||||||
|
Added: Updater
|
||||||
|
Added: Refresh authentication when expires
|
||||||
|
Added: Match summary page phase 1`,
|
||||||
|
"pub_date": "2024-07-20T10:25:57Z",
|
||||||
|
"platforms": {
|
||||||
|
"windows-x86_64": {
|
||||||
|
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVTdDh5VEM1Y1hnUUEzRXpPWDhLQ0JDSjU0UDhwdnFqLzQ0NEV1RFRudSsyS3AwcmdpbDd2SmVkV1VwdmNXWVdnbkF2S3ZPMWZKTDRzdHZ0djVjZWNENk51TGlWbjRsWXdJPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzIxOTE4NDU2CWZpbGU6ZG9taW5vLWNsaWVudF8wLjIuMF94NjQtc2V0dXAubnNpcy56aXAKTnpuMkJueXBJaGVEYkpMS2phMm5ybkp5aHRKVUtLbHJYaVVrYXRXMXg1R1owQjN2VzRVVmlOMnJMWUlIMzBCSE5WeHpIYUY5dmVzTG5SdDEyNGNPQXc9PQo=",
|
||||||
|
"url": "https://domserv.xintanalabs.net/updates/domino-client_0.2.0_x64-setup.nsis.zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdaterController extends BaseController {
|
||||||
|
async checkUpdate(req: Request, res: Response): Promise<any> {
|
||||||
|
this.logger.info('Checking for updates');
|
||||||
|
return res.json(json).status(200).end();
|
||||||
|
|
||||||
|
// return res.status(204).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// async startMatchSession(data: any): Promise<any> {
|
||||||
|
// const response = await this.sessionManager.startSession(data);
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async joinMatchSession(data: any, socketId: string): Promise<any> {
|
||||||
|
// const response = await this.sessionManager.joinSession(data, socketId);
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
}
|
@ -18,6 +18,7 @@ export function matchSessionAdapter(session: MatchSession, showPips: boolean = f
|
|||||||
status: state.status,
|
status: state.status,
|
||||||
matchInProgress: state.matchInProgress,
|
matchInProgress: state.matchInProgress,
|
||||||
gameSummaries: state.gameSummaries,
|
gameSummaries: state.gameSummaries,
|
||||||
|
room: state.room
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -61,6 +61,7 @@ export interface DbMatchSession extends EntityMongo {
|
|||||||
status: string;
|
status: string;
|
||||||
matchInProgress: boolean;
|
matchInProgress: boolean;
|
||||||
gameSummaries: GameSummary[];
|
gameSummaries: GameSummary[];
|
||||||
|
room: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DbUser extends EntityMongo {
|
export interface DbUser extends EntityMongo {
|
||||||
@ -116,3 +117,8 @@ export interface DbListResponse{
|
|||||||
sort?: any;
|
sort?: any;
|
||||||
data: EntityMongo[];
|
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>;
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ app.use(express.text());
|
|||||||
app.use(express.urlencoded({extended: true }));
|
app.use(express.urlencoded({extended: true }));
|
||||||
app.use(useRouter())
|
app.use(useRouter())
|
||||||
|
|
||||||
|
app.use(express.static(join(process.cwd(), 'public')));
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.sendFile(join(__dirname, 'index.html'));
|
res.sendFile(join(__dirname, 'index.html'));
|
||||||
|
@ -2,8 +2,9 @@ import crypto from 'crypto';
|
|||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import { User } from '../db/interfaces';
|
import { User } from '../db/interfaces';
|
||||||
|
import { ManagerBase } from './ManagerBase';
|
||||||
|
|
||||||
export class SecurityManager {
|
export class SecurityManager extends ManagerBase {
|
||||||
saltRounds = Number(process.env.SALT_ROUNDS);
|
saltRounds = Number(process.env.SALT_ROUNDS);
|
||||||
jwtSecretKey = process.env.JWT_SECRET_KEY || '';
|
jwtSecretKey = process.env.JWT_SECRET_KEY || '';
|
||||||
|
|
||||||
@ -20,18 +21,21 @@ export class SecurityManager {
|
|||||||
return crypto.randomBytes(32).toString('hex');
|
return crypto.randomBytes(32).toString('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
signJwt(data: any) {
|
signJwt(data: any, longTerm: boolean = false): string {
|
||||||
return jwt.sign(data, this.jwtSecretKey, { expiresIn: '3h' });
|
const expiresIn: string = longTerm ? '7d' : '3h'
|
||||||
|
delete data.iat;
|
||||||
|
delete data.exp;
|
||||||
|
return jwt.sign(data, this.jwtSecretKey, { expiresIn });
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: verificar esto
|
// TODO: verificar esto
|
||||||
async verifyJwt(token: string): Promise<User> {
|
async verifyJwt(token: string): Promise<any> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
jwt.verify(token, this.jwtSecretKey, (err, decoded) => {
|
jwt.verify(token, this.jwtSecretKey, (err, decoded) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
resolve(decoded as User);
|
resolve(decoded);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Request, Response, Router } from 'express';
|
import { Request, Response, Router } from 'express';
|
||||||
import { AuthController } from '../controllers/AuthController';
|
import { AuthController } from '../controllers/AuthController';
|
||||||
|
import { UpdaterController } from '../controllers/UpdaterController';
|
||||||
|
|
||||||
import adminRouter from './adminRouter';
|
import adminRouter from './adminRouter';
|
||||||
import userRouter from './userRouter';
|
import userRouter from './userRouter';
|
||||||
@ -8,13 +9,19 @@ import gameRouter from './gameRouter';
|
|||||||
export default function(): Router {
|
export default function(): Router {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
const authController = new AuthController();
|
const authController = new AuthController();
|
||||||
|
const updaterController = new UpdaterController();
|
||||||
|
|
||||||
router.get('/version', async function(req: Request, res: Response){
|
router.get('/version', async function(req: Request, res: Response){
|
||||||
res.send('1.0.0').end();
|
res.json({
|
||||||
|
app: 'domino',
|
||||||
|
version: '0.1.4-test',
|
||||||
|
}).end();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/auth/code', (req: Request, res: Response) => authController.twoFactorCodeAuthentication(req, res));
|
router.post('/auth/code', (req: Request, res: Response) => authController.twoFactorCodeAuthentication(req, res));
|
||||||
router.post('/login', (req: Request, res: Response) => authController.login(req, res));
|
router.post('/login', (req: Request, res: Response) => authController.login(req, res));
|
||||||
|
router.post('/refresh', (req: Request, res: Response) => authController.refresh(req, res));
|
||||||
|
router.get('/updater/:target/:arch/:currentVersion', (req: Request, res: Response) => updaterController.checkUpdate(req, res));
|
||||||
|
|
||||||
router.use('/admin', adminRouter());
|
router.use('/admin', adminRouter());
|
||||||
router.use('/user', userRouter());
|
router.use('/user', userRouter());
|
||||||
|
@ -97,7 +97,6 @@ export class InteractionService extends ServiceBase{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onPlayerReady(data: any): any {
|
private onPlayerReady(data: any): any {
|
||||||
const { userId, sessionId } = data;
|
const { userId, sessionId } = data;
|
||||||
const session: MatchSession | undefined = this.sessionManager.getSession(sessionId);
|
const session: MatchSession | undefined = this.sessionManager.getSession(sessionId);
|
||||||
|
@ -10,23 +10,23 @@ export class PlayerNotificationService extends ServiceBase {
|
|||||||
clientNotifier: NetworkClientNotifier = new NetworkClientNotifier();
|
clientNotifier: NetworkClientNotifier = new NetworkClientNotifier();
|
||||||
|
|
||||||
notifyGameState(game: DominoesGame) {
|
notifyGameState(game: DominoesGame) {
|
||||||
const gameState: GameState = game.getGameState();
|
const gameState: GameState = game.getState();
|
||||||
const { players } = game;
|
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[]) {
|
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) {
|
notifyMatchState(session: MatchSession) {
|
||||||
const { players } = session;
|
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 = {}) {
|
async sendEventToPlayers(event: string, players: PlayerInterface[], data: Function | any = {}) {
|
||||||
players.forEach((player) => {
|
players.filter(p => p instanceof NetworkPlayer).forEach((player) => {
|
||||||
let dataTosend = data;
|
let dataTosend = data;
|
||||||
if (typeof data === 'function') {
|
if (typeof data === 'function') {
|
||||||
dataTosend = data(player);
|
dataTosend = data(player);
|
||||||
@ -37,6 +37,8 @@ export class PlayerNotificationService extends ServiceBase {
|
|||||||
|
|
||||||
sendEvent(event: string, player: PlayerInterface, data: any = {}) {
|
sendEvent(event: string, player: PlayerInterface, data: any = {}) {
|
||||||
this.logger.debug(`Sending event '${event}' to player ${player.id}`);
|
this.logger.debug(`Sending event '${event}' to player ${player.id}`);
|
||||||
|
if (player instanceof NetworkPlayer) {
|
||||||
this.clientNotifier.sendEvent(player as NetworkPlayer, event, data);
|
this.clientNotifier.sendEvent(player as NetworkPlayer, event, data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,7 +2,6 @@ import { Server as HttpServer } from "http";
|
|||||||
import { ServiceBase } from "./ServiceBase";
|
import { ServiceBase } from "./ServiceBase";
|
||||||
import { Server } from "socket.io";
|
import { Server } from "socket.io";
|
||||||
import { SecurityManager } from "../managers/SecurityManager";
|
import { SecurityManager } from "../managers/SecurityManager";
|
||||||
import { User } from "../db/interfaces";
|
|
||||||
import { Socket } from "socket.io";
|
import { Socket } from "socket.io";
|
||||||
import { InteractionService } from "./InteractionService";
|
import { InteractionService } from "./InteractionService";
|
||||||
import { ClientEvents } from "../../game/constants";
|
import { ClientEvents } from "../../game/constants";
|
||||||
@ -24,7 +23,7 @@ export class SocketIoService extends ServiceBase {
|
|||||||
if (socket.handshake.auth && socket.handshake.auth.token) {
|
if (socket.handshake.auth && socket.handshake.auth.token) {
|
||||||
const token = socket.handshake.auth.token;
|
const token = socket.handshake.auth.token;
|
||||||
try {
|
try {
|
||||||
const user: User = await this.security.verifyJwt(token);
|
const { user } = await this.security.verifyJwt(token);
|
||||||
socket.user = user;
|
socket.user = user;
|
||||||
next();
|
next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -62,7 +61,6 @@ export class SocketIoService extends ServiceBase {
|
|||||||
const userId = user._id.toString();
|
const userId = user._id.toString();
|
||||||
if (!SocketIoService.clients.has(userId)) {
|
if (!SocketIoService.clients.has(userId)) {
|
||||||
SocketIoService.clients.set(userId, { socketId, alive: true, user: socket.user });
|
SocketIoService.clients.set(userId, { socketId, alive: true, user: socket.user });
|
||||||
socket.join('room-general')
|
|
||||||
} else {
|
} else {
|
||||||
const client = SocketIoService.clients.get(userId);
|
const client = SocketIoService.clients.get(userId);
|
||||||
this.interactionService.updateSocketId(client.sessionId, userId, socketId);
|
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) => {
|
socket.on(ClientEvents.CLIENT_EVENT, (data) => {
|
||||||
this.interactionService.handleClientEvent(data);
|
this.interactionService.handleClientEvent(data);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user