fixed timeout issue
implemented timeoutManager, a more efficient solution for managing timeouts in RAM memory. this resolves the problem of lingering timeouts in the server, providing faster removal of old timeouts and improving overall performance.
This commit is contained in:
parent
f07c1c8577
commit
e5a69fa4a9
29
README.md
29
README.md
@ -1,11 +1,14 @@
|
|||||||
# <center>Online Multiplayer Ludo Game</center>
|
<h1 align="center">Online Multiplayer Ludo Game </h1>
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
Ludo Online is a multiplayer web-based implementation of the classic board game Ludo, built using the MERN stack and integrated with SocketIO for real-time communication.
|
Ludo Online is a multiplayer web-based implementation of the classic board game Ludo, built using the MERN stack and integrated with SocketIO for real-time communication.
|
||||||
|
|
||||||
\>\> Play Online here <<
|
<p align="center">
|
||||||
\>\> [Watch YouTube Video here](https://youtu.be/mGMnH9Nvsyw) <<
|
>> Play Online here <<
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
>> <a href="https://youtu.be/mGMnH9Nvsyw">Watch YouTube Video here</a> <<
|
||||||
|
</p>
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@ -14,34 +17,50 @@ Ludo Online is a multiplayer web-based implementation of the classic board game
|
|||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
Frontend:
|
Frontend:
|
||||||
|
|
||||||
  
|
  
|
||||||
  
|
  
|
||||||
|
|
||||||
Backend:
|
Backend:
|
||||||
|
|
||||||
   
|
   
|
||||||
|
|
||||||
Tests:
|
Tests:
|
||||||
|
|
||||||
  
|
  
|
||||||
|
|
||||||
Tools:
|
Tools:
|
||||||
|
|
||||||
    
|
    
|
||||||
|
|
||||||
## Key Features and Challenges
|
## Key Features and Challenges
|
||||||
|
|
||||||
- Maintained session consistency with **Express Session** and **MongoDB**.
|
- Maintained session consistency with **Express Session** and **MongoDB**.
|
||||||
|
|
||||||
- Enabled real-time communication via **WebSocket** and **SocketIO**.
|
- Enabled real-time communication via **WebSocket** and **SocketIO**.
|
||||||
|
|
||||||
- Maintained code reliability by implementing unit and integration tests using **Mocha**, **Chai**, and **Jest**.
|
- Maintained code reliability by implementing unit and integration tests using **Mocha**, **Chai**, and **Jest**.
|
||||||
|
|
||||||
- Hosted in a **Docker** container on **AWS EC2**.
|
- Hosted in a **Docker** container on **AWS EC2**.
|
||||||
|
|
||||||
- Established CI/CD using **CircleCI**.
|
- Established CI/CD using **CircleCI**.
|
||||||
|
|
||||||
- Implemented E2E tests utilizing **Cypress**, addressing challenges related to [testing collaboration](https://docs.cypress.io/guides/references/trade-offs#Multiple-browsers-open-at-the-same-time) and canvas functionality in the application.
|
- Implemented E2E tests utilizing **Cypress**, addressing challenges related to [testing collaboration](https://docs.cypress.io/guides/references/trade-offs#Multiple-browsers-open-at-the-same-time) and canvas functionality in the application.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download this repository
|
1. Download this repository
|
||||||
|
|
||||||
2. Generate your own [mongoDB atlas](https://www.mongodb.com) credential URL. It should looks like this:
|
2. Generate your own [mongoDB atlas](https://www.mongodb.com) credential URL. It should looks like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
mongodb+srv://madmin:<password>@clustername.mongodb.net/<dbname>?retryWrites=true&w=majority
|
mongodb+srv://madmin:<password>@clustername.mongodb.net/<dbname>?retryWrites=true&w=majority
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Add this URL to the /backend/credentials.js file
|
3. Add this URL to the /backend/credentials.js file
|
||||||
|
|
||||||
4. Perform these commands in the main directory:
|
4. Perform these commands in the main directory:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const { getRoom, updateRoom } = require('../services/roomService');
|
const { getRoom, updateRoom } = require('../services/roomService');
|
||||||
const { colors } = require('../utils/constants');
|
const { COLORS } = require('../utils/constants');
|
||||||
|
|
||||||
module.exports = socket => {
|
module.exports = socket => {
|
||||||
const req = socket.request;
|
const req = socket.request;
|
||||||
@ -44,7 +44,7 @@ module.exports = socket => {
|
|||||||
if (err) return socket.disconnect();
|
if (err) return socket.disconnect();
|
||||||
req.session.roomId = room._id.toString();
|
req.session.roomId = room._id.toString();
|
||||||
req.session.playerId = room.players[room.players.length - 1]._id.toString();
|
req.session.playerId = room.players[room.players.length - 1]._id.toString();
|
||||||
req.session.color = colors[room.players.length - 1];
|
req.session.color = COLORS[room.players.length - 1];
|
||||||
req.session.save();
|
req.session.save();
|
||||||
socket.join(room._id.toString());
|
socket.join(room._id.toString());
|
||||||
socket.emit('player:data', JSON.stringify(req.session));
|
socket.emit('player:data', JSON.stringify(req.session));
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const { colors } = require('../utils/constants');
|
const { COLORS, MOVE_TIME } = require('../utils/constants');
|
||||||
const { makeRandomMove } = require('../handlers/handlersFunctions');
|
const { makeRandomMove } = require('../handlers/handlersFunctions');
|
||||||
|
const timeoutManager = require('./timeoutManager.js');
|
||||||
const PawnSchema = require('./pawn');
|
const PawnSchema = require('./pawn');
|
||||||
const PlayerSchema = require('./player');
|
const PlayerSchema = require('./player');
|
||||||
|
|
||||||
@ -12,7 +13,6 @@ const RoomSchema = new mongoose.Schema({
|
|||||||
started: { type: Boolean, default: false },
|
started: { type: Boolean, default: false },
|
||||||
full: { type: Boolean, default: false },
|
full: { type: Boolean, default: false },
|
||||||
nextMoveTime: Number,
|
nextMoveTime: Number,
|
||||||
timeoutID: Number,
|
|
||||||
rolledNumber: Number,
|
rolledNumber: Number,
|
||||||
players: [PlayerSchema],
|
players: [PlayerSchema],
|
||||||
winner: { type: String, default: null },
|
winner: { type: String, default: null },
|
||||||
@ -24,10 +24,10 @@ const RoomSchema = new mongoose.Schema({
|
|||||||
let pawn = {};
|
let pawn = {};
|
||||||
pawn.basePos = i;
|
pawn.basePos = i;
|
||||||
pawn.position = i;
|
pawn.position = i;
|
||||||
if (i < 4) pawn.color = colors[0];
|
if (i < 4) pawn.color = COLORS[0];
|
||||||
else if (i < 8) pawn.color = colors[1];
|
else if (i < 8) pawn.color = COLORS[1];
|
||||||
else if (i < 12) pawn.color = colors[2];
|
else if (i < 12) pawn.color = COLORS[2];
|
||||||
else if (i < 16) pawn.color = colors[3];
|
else if (i < 16) pawn.color = COLORS[3];
|
||||||
startPositions.push(pawn);
|
startPositions.push(pawn);
|
||||||
}
|
}
|
||||||
return startPositions;
|
return startPositions;
|
||||||
@ -54,10 +54,10 @@ RoomSchema.methods.changeMovingPlayer = function () {
|
|||||||
} else {
|
} else {
|
||||||
this.players[playerIndex + 1].nowMoving = true;
|
this.players[playerIndex + 1].nowMoving = true;
|
||||||
}
|
}
|
||||||
this.nextMoveTime = Date.now() + 15000;
|
this.nextMoveTime = Date.now() + MOVE_TIME;
|
||||||
this.rolledNumber = null;
|
this.rolledNumber = null;
|
||||||
if (this.timeoutID) clearTimeout(this.timeoutID);
|
timeoutManager.clear(this._id.toString());
|
||||||
this.timeoutID = setTimeout(makeRandomMove, 15000, this._id.toString());
|
timeoutManager.set(makeRandomMove, MOVE_TIME, this._id.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomSchema.methods.movePawn = function (pawn) {
|
RoomSchema.methods.movePawn = function (pawn) {
|
||||||
@ -83,14 +83,14 @@ RoomSchema.methods.canStartGame = function () {
|
|||||||
|
|
||||||
RoomSchema.methods.startGame = function () {
|
RoomSchema.methods.startGame = function () {
|
||||||
this.started = true;
|
this.started = true;
|
||||||
this.nextMoveTime = Date.now() + 15000;
|
this.nextMoveTime = Date.now() + MOVE_TIME;
|
||||||
this.players.forEach(player => (player.ready = true));
|
this.players.forEach(player => (player.ready = true));
|
||||||
this.players[0].nowMoving = true;
|
this.players[0].nowMoving = true;
|
||||||
this.timeoutID = setTimeout(makeRandomMove, 15000, this._id.toString());
|
timeoutManager.set(makeRandomMove, MOVE_TIME, this._id.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomSchema.methods.endGame = function (winner) {
|
RoomSchema.methods.endGame = function (winner) {
|
||||||
this.timeoutID = null;
|
timeoutManager.clear(this._id.toString());
|
||||||
this.rolledNumber = null;
|
this.rolledNumber = null;
|
||||||
this.nextMoveTime = null;
|
this.nextMoveTime = null;
|
||||||
this.players.map(player => (player.nowMoving = false));
|
this.players.map(player => (player.nowMoving = false));
|
||||||
@ -131,7 +131,7 @@ RoomSchema.methods.addPlayer = function (name, id) {
|
|||||||
sessionID: id,
|
sessionID: id,
|
||||||
name: name,
|
name: name,
|
||||||
ready: false,
|
ready: false,
|
||||||
color: colors[this.players.length],
|
color: COLORS[this.players.length],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
19
backend/models/timeoutManager.js
Normal file
19
backend/models/timeoutManager.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const timeoutManager = {
|
||||||
|
timeouts: new Map(),
|
||||||
|
add: function (roomId, timeoutId) {
|
||||||
|
this.timeouts.set(roomId, timeoutId);
|
||||||
|
},
|
||||||
|
get: function (roomId) {
|
||||||
|
return this.timeouts.get(roomId);
|
||||||
|
},
|
||||||
|
clear: function (roomId) {
|
||||||
|
clearTimeout(this.timeouts.get(roomId));
|
||||||
|
this.timeouts.delete(roomId);
|
||||||
|
},
|
||||||
|
set: function (timeoutFunction, time, roomId) {
|
||||||
|
const timeoutId = setTimeout(timeoutFunction, time, roomId);
|
||||||
|
this.add(roomId, timeoutId);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = timeoutManager;
|
||||||
275
backend/package-lock.json
generated
275
backend/package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
"mongoose": "^5.12.0",
|
"mongoose": "^5.12.0",
|
||||||
|
"sinon": "^17.0.1",
|
||||||
"socket.io": "^4.5.1"
|
"socket.io": "^4.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -21,6 +22,45 @@
|
|||||||
"socket.io-client": "^4.7.2"
|
"socket.io-client": "^4.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@sinonjs/commons": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sinonjs/fake-timers": {
|
||||||
|
"version": "11.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz",
|
||||||
|
"integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sinonjs/samsam": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": "^2.0.0",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"type-detect": "^4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sinonjs/text-encoding": {
|
||||||
|
"version": "0.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
|
||||||
|
"integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ=="
|
||||||
|
},
|
||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
@ -1081,7 +1121,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@ -1257,6 +1296,11 @@
|
|||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/just-extend": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg=="
|
||||||
|
},
|
||||||
"node_modules/kareem": {
|
"node_modules/kareem": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
||||||
@ -1293,6 +1337,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"node_modules/lodash.set": {
|
"node_modules/lodash.set": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
|
||||||
@ -1676,6 +1725,55 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nise": {
|
||||||
|
"version": "5.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz",
|
||||||
|
"integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": "^2.0.0",
|
||||||
|
"@sinonjs/fake-timers": "^10.0.2",
|
||||||
|
"@sinonjs/text-encoding": "^0.7.1",
|
||||||
|
"just-extend": "^4.0.2",
|
||||||
|
"path-to-regexp": "^1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nise/node_modules/@sinonjs/commons": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nise/node_modules/@sinonjs/fake-timers": {
|
||||||
|
"version": "10.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
|
||||||
|
"integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
|
||||||
|
"dependencies": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nise/node_modules/isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||||
|
},
|
||||||
|
"node_modules/nise/node_modules/path-to-regexp": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
@ -2039,6 +2137,42 @@
|
|||||||
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
|
||||||
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
|
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sinon": {
|
||||||
|
"version": "17.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz",
|
||||||
|
"integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": "^3.0.0",
|
||||||
|
"@sinonjs/fake-timers": "^11.2.2",
|
||||||
|
"@sinonjs/samsam": "^8.0.0",
|
||||||
|
"diff": "^5.1.0",
|
||||||
|
"nise": "^5.1.5",
|
||||||
|
"supports-color": "^7.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/sinon"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sinon/node_modules/diff": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sinon/node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sliced": {
|
"node_modules/sliced": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
||||||
@ -2306,7 +2440,6 @@
|
|||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
@ -2506,6 +2639,47 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
|
||||||
|
"requires": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sinonjs/fake-timers": {
|
||||||
|
"version": "11.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz",
|
||||||
|
"integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==",
|
||||||
|
"requires": {
|
||||||
|
"@sinonjs/commons": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sinonjs/samsam": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==",
|
||||||
|
"requires": {
|
||||||
|
"@sinonjs/commons": "^2.0.0",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"type-detect": "^4.0.8"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
|
||||||
|
"requires": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sinonjs/text-encoding": {
|
||||||
|
"version": "0.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz",
|
||||||
|
"integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ=="
|
||||||
|
},
|
||||||
"@socket.io/component-emitter": {
|
"@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
@ -3291,8 +3465,7 @@
|
|||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"he": {
|
"he": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -3412,6 +3585,11 @@
|
|||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"just-extend": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg=="
|
||||||
|
},
|
||||||
"kareem": {
|
"kareem": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
||||||
@ -3439,6 +3617,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||||
},
|
},
|
||||||
|
"lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"lodash.set": {
|
"lodash.set": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
|
||||||
@ -3711,6 +3894,59 @@
|
|||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||||
},
|
},
|
||||||
|
"nise": {
|
||||||
|
"version": "5.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz",
|
||||||
|
"integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==",
|
||||||
|
"requires": {
|
||||||
|
"@sinonjs/commons": "^2.0.0",
|
||||||
|
"@sinonjs/fake-timers": "^10.0.2",
|
||||||
|
"@sinonjs/text-encoding": "^0.7.1",
|
||||||
|
"just-extend": "^4.0.2",
|
||||||
|
"path-to-regexp": "^1.7.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==",
|
||||||
|
"requires": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sinonjs/fake-timers": {
|
||||||
|
"version": "10.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
|
||||||
|
"integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
|
||||||
|
"requires": {
|
||||||
|
"@sinonjs/commons": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sinonjs/commons": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==",
|
||||||
|
"requires": {
|
||||||
|
"type-detect": "4.0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
|
||||||
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||||
|
"requires": {
|
||||||
|
"isarray": "0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
@ -3989,6 +4225,34 @@
|
|||||||
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
|
||||||
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
|
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
|
||||||
},
|
},
|
||||||
|
"sinon": {
|
||||||
|
"version": "17.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz",
|
||||||
|
"integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==",
|
||||||
|
"requires": {
|
||||||
|
"@sinonjs/commons": "^3.0.0",
|
||||||
|
"@sinonjs/fake-timers": "^11.2.2",
|
||||||
|
"@sinonjs/samsam": "^8.0.0",
|
||||||
|
"diff": "^5.1.0",
|
||||||
|
"nise": "^5.1.5",
|
||||||
|
"supports-color": "^7.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"diff": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw=="
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sliced": {
|
"sliced": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
||||||
@ -4187,8 +4451,7 @@
|
|||||||
"type-detect": {
|
"type-detect": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"type-is": {
|
"type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
"mongoose": "^5.12.0",
|
"mongoose": "^5.12.0",
|
||||||
|
"sinon": "^17.0.1",
|
||||||
"socket.io": "^4.5.1"
|
"socket.io": "^4.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
50
backend/tests/models/timeoutManager.test.js
Normal file
50
backend/tests/models/timeoutManager.test.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const chai = require('chai');
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const timeoutManager = require('../../models/timeoutManager');
|
||||||
|
|
||||||
|
const { expect } = chai;
|
||||||
|
|
||||||
|
describe('timeoutManager', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
timeoutManager.timeouts.clear();
|
||||||
|
sinon.useFakeTimers({ shouldClearNativeTimers: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a timeout to the map', () => {
|
||||||
|
timeoutManager.add('room1', 1);
|
||||||
|
expect(timeoutManager.timeouts.size).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a timeout from the map', () => {
|
||||||
|
timeoutManager.add('room1', 1);
|
||||||
|
const timeoutId = timeoutManager.get('room1');
|
||||||
|
expect(timeoutId).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear a timeout from the map', () => {
|
||||||
|
timeoutManager.add('room1', 1);
|
||||||
|
timeoutManager.clear('room1');
|
||||||
|
expect(timeoutManager.timeouts.size).to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set a new timeout', () => {
|
||||||
|
const timeoutFunction = sinon.spy();
|
||||||
|
timeoutManager.set(timeoutFunction, 100, 'room1');
|
||||||
|
expect(timeoutManager.timeouts.size).to.equal(1);
|
||||||
|
sinon.clock.tick(101);
|
||||||
|
sinon.assert.calledOnce(timeoutFunction);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call the timeout function if cleared', () => {
|
||||||
|
const timeoutFunction = sinon.spy();
|
||||||
|
timeoutManager.set(timeoutFunction, 100, 'room1');
|
||||||
|
timeoutManager.clear('room1');
|
||||||
|
sinon.clock.tick(101);
|
||||||
|
sinon.assert.notCalled(timeoutFunction);
|
||||||
|
expect(timeoutManager.timeouts.size).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,2 +1,3 @@
|
|||||||
const colors = ["red", "blue", "green", "yellow"];
|
const COLORS = ['red', 'blue', 'green', 'yellow'];
|
||||||
module.exports = { colors };
|
const MOVE_TIME = 15000;
|
||||||
|
module.exports = { COLORS, MOVE_TIME };
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user