Merge pull request #10 from Wenszel/feature-deployment

Feature deployment
This commit is contained in:
Wiktor Smaga 2024-01-18 15:29:35 +01:00 committed by GitHub
commit c835846c2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 516 additions and 56 deletions

View File

@ -1,12 +1,13 @@
version: 2.1 version: 2.1
orbs:
aws-cli: circleci/aws-cli@4.1.2
aws-ecr: circleci/aws-ecr@9.0.1
aws-ecs: circleci/aws-ecs@4.0.0
jobs: jobs:
build_and_test: build_and_test:
docker: docker:
- image: circleci/node:14 - image: circleci/node:14
working_directory: ~/app working_directory: ~/app
steps: steps:
- checkout - checkout
- run: - run:
@ -26,9 +27,41 @@ jobs:
name: Test Frontend name: Test Frontend
command: | command: |
npm test npm test
run_task:
docker:
- image: cimg/python:3.10
steps:
- aws-cli/setup:
role_arn: arn:aws:iam::797929460436:role/ecs
role_session_name: example-session
- aws-ecs/run_task:
awsvpc: false
cluster: arn:aws:ecs:eu-north-1:797929460436:cluster/mern-ludo-cluster
launch_type: EC2
task_definition: mern-ludo-docker-task
workflows: workflows:
version: 2 build_and_test_and_deploy:
build:
jobs: jobs:
- build_and_test - build_and_test
- aws-ecr/build_and_push_image:
auth:
- aws-cli/setup:
role_arn: arn:aws:iam::797929460436:role/openid
role_session_name: example-session
repo: mern-ludo
public_registry: true
tag: latest
requires:
- build_and_test
filters:
branches:
only:
- main
- run_task:
requires:
- aws-ecr/build_and_push_image
filters:
branches:
only:
- main

35
.dockerignore Normal file
View File

@ -0,0 +1,35 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/engine/reference/builder/#dockerignore-file
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
**/build
**/dist
LICENSE
README.md
node_modules

3
.gitignore vendored
View File

@ -9,7 +9,7 @@ backend/node_modules
/coverage /coverage
# production # production
/build build
# misc # misc
.DS_Store .DS_Store
@ -21,3 +21,4 @@ backend/node_modules
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
.env

19
Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM node:14 as frontend
WORKDIR /app
COPY . /app
RUN npm install --production
RUN npm run build
FROM node:14 as backend
WORKDIR /app
COPY /backend /app
RUN npm install
FROM node:14
WORKDIR /app
COPY --from=backend /app /app/
COPY --from=frontend /app/build /app/build
EXPOSE 8080
CMD ["npm", "run", "start"]

View File

@ -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) << >> <a href="http://ec2-51-20-142-4.eu-north-1.compute.amazonaws.com:8080">Play online here</a> <<
</p>
<p align="center">
>> <a href="https://youtu.be/mGMnH9Nvsyw">Watch YouTube Video here</a> <<
</p>
## Architecture ## Architecture
@ -14,34 +17,49 @@ Ludo Online is a multiplayer web-based implementation of the classic board game
## Tech Stack ## Tech Stack
Frontend: Frontend:
![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E) ![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB) ![React Router](https://img.shields.io/badge/React_Router-CA4245?style=for-the-badge&logo=react-router&logoColor=white) ![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E) ![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB) ![React Router](https://img.shields.io/badge/React_Router-CA4245?style=for-the-badge&logo=react-router&logoColor=white)
![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge&logo=css3&logoColor=white) ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) ![MUI](https://img.shields.io/badge/MUI-%230081CB.svg?style=for-the-badge&logo=mui&logoColor=white) ![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge&logo=css3&logoColor=white) ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) ![MUI](https://img.shields.io/badge/MUI-%230081CB.svg?style=for-the-badge&logo=mui&logoColor=white)
Backend: Backend:
![MongoDB](https://img.shields.io/badge/MongoDB-%234ea94b.svg?style=for-the-badge&logo=mongodb&logoColor=white) ![Express.js](https://img.shields.io/badge/express.js-%23404d59.svg?style=for-the-badge&logo=express&logoColor=%2361DAFB) ![Socket.io](https://img.shields.io/badge/Socket.io-black?style=for-the-badge&logo=socket.io&badgeColor=010101) ![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white) ![MongoDB](https://img.shields.io/badge/MongoDB-%234ea94b.svg?style=for-the-badge&logo=mongodb&logoColor=white) ![Express.js](https://img.shields.io/badge/express.js-%23404d59.svg?style=for-the-badge&logo=express&logoColor=%2361DAFB) ![Socket.io](https://img.shields.io/badge/Socket.io-black?style=for-the-badge&logo=socket.io&badgeColor=010101) ![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white)
Tests: Tests:
![cypress](https://img.shields.io/badge/-cypress-%23E5E5E5?style=for-the-badge&logo=cypress&logoColor=058a5e) ![Mocha](https://img.shields.io/badge/-mocha-%238D6748?style=for-the-badge&logo=mocha&logoColor=white) ![Jest](https://img.shields.io/badge/-jest-%23C21325?style=for-the-badge&logo=jest&logoColor=white) ![cypress](https://img.shields.io/badge/-cypress-%23E5E5E5?style=for-the-badge&logo=cypress&logoColor=058a5e) ![Mocha](https://img.shields.io/badge/-mocha-%238D6748?style=for-the-badge&logo=mocha&logoColor=white) ![Jest](https://img.shields.io/badge/-jest-%23C21325?style=for-the-badge&logo=jest&logoColor=white)
Tools:
Other:
![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white) ![AWS](https://img.shields.io/badge/AWS-%23FF9900.svg?style=for-the-badge&logo=amazon-aws&logoColor=white) ![CircleCI](https://img.shields.io/badge/circle%20ci-%23161616.svg?style=for-the-badge&logo=circleci&logoColor=white) ![Git](https://img.shields.io/badge/git-%23F05033.svg?style=for-the-badge&logo=git&logoColor=white) ![Jira](https://img.shields.io/badge/jira-%230A0FFF.svg?style=for-the-badge&logo=jira&logoColor=white) ![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white) ![AWS](https://img.shields.io/badge/AWS-%23FF9900.svg?style=for-the-badge&logo=amazon-aws&logoColor=white) ![CircleCI](https://img.shields.io/badge/circle%20ci-%23161616.svg?style=for-the-badge&logo=circleci&logoColor=white) ![Git](https://img.shields.io/badge/git-%23F05033.svg?style=for-the-badge&logo=git&logoColor=white) ![Jira](https://img.shields.io/badge/jira-%230A0FFF.svg?style=for-the-badge&logo=jira&logoColor=white)
## 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**.
- 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.
- Established a CI/CD pipeline using **CircleCI**, with pushing **Docker** container to **AWS ECR** and deploying to **AWS ECS**
## 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/.env file (refer to .env.example)
4. Perform these commands in the main directory: 4. Perform these commands in the main directory:
``` ```

3
backend/.env.example Normal file
View File

@ -0,0 +1,3 @@
PORT=8080
CONNECTION_URI=your_mongodb_connection_uri
NODE_ENV="development"

View File

@ -1,9 +1,7 @@
const CONNECTION_URI = require('../credentials.js');
module.exports = function (mongoose) { module.exports = function (mongoose) {
mongoose.set('useFindAndModify', false); mongoose.set('useFindAndModify', false);
mongoose mongoose
.connect(CONNECTION_URI, { .connect(process.env.CONNECTION_URI, {
useNewUrlParser: true, useNewUrlParser: true,
useUnifiedTopology: true, useUnifiedTopology: true,
dbName: 'test', dbName: 'test',

View File

@ -1,8 +1,8 @@
const session = require('express-session'); const session = require('express-session');
const CONNECTION_URI = require('../credentials.js');
const MongoDBStore = require('connect-mongodb-session')(session); const MongoDBStore = require('connect-mongodb-session')(session);
const store = new MongoDBStore({ const store = new MongoDBStore({
uri: CONNECTION_URI, uri: process.env.CONNECTION_URI,
collection: 'sessions', collection: 'sessions',
}); });
const sessionMiddleware = session({ const sessionMiddleware = session({

View File

@ -1,2 +0,0 @@
// Write your own mongoDBatlas credentials here
module.exports = '';

View File

@ -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));

View File

@ -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],
}); });
}; };

View 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;

View File

@ -10,9 +10,11 @@
"connect-mongodb-session": "^3.1.1", "connect-mongodb-session": "^3.1.1",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.3.1",
"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 +23,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",
@ -668,6 +709,17 @@
"node": ">=0.3.1" "node": ">=0.3.1"
} }
}, },
"node_modules/dotenv": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/motdotla/dotenv?sponsor=1"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -1081,7 +1133,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 +1308,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 +1349,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 +1737,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 +2149,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 +2452,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 +2651,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",
@ -2983,6 +3169,11 @@
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true "dev": true
}, },
"dotenv": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ=="
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -3291,8 +3482,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 +3602,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 +3634,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 +3911,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 +4242,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 +4468,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",

View File

@ -5,9 +5,11 @@
"connect-mongodb-session": "^3.1.1", "connect-mongodb-session": "^3.1.1",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.3.1",
"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": {

View File

@ -1,10 +1,12 @@
const express = require('express'); const express = require('express');
const cors = require('cors'); const cors = require('cors');
const path = require('path');
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
const mongoose = require('mongoose'); const mongoose = require('mongoose');
require('dotenv').config();
const { sessionMiddleware } = require('./config/session'); const { sessionMiddleware } = require('./config/session');
const PORT = 8080; const PORT = process.env.PORT;
const app = express(); const app = express();
@ -30,9 +32,10 @@ require('./config/database')(mongoose);
require('./config/socket')(server); require('./config/socket')(server);
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
app.use(express.static('/app/build')); app.use(express.static('./build'));
app.get('/', (req, res) => { app.get('*', (req, res) => {
res.sendFile('/app/build/index.html'); const indexPath = path.join(__dirname, './build/index.html');
res.sendFile(indexPath);
}); });
} }

View 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);
});
});

View File

@ -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 };

View File

@ -23,9 +23,7 @@
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"heroku-postbuild": "cd backend && npm install && cd .. && npm install && npm run build", "test": "react-scripts test"
"test": "react-scripts test",
"eject": "react-scripts eject"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
@ -48,11 +46,10 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"proxy": "http://localhost:5000",
"devDependencies": { "devDependencies": {
"@testing-library/jest-dom": "^6.1.5", "@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2", "@testing-library/react": "^14.1.2",
"cypress": "^13.6.1", "cypress": "^13.6.1",
"@babel/plugin-proposal-private-property-in-object": "^7.16.7" "@babel/plugin-transform-private-property-in-object": "^7.16.7"
} }
} }

View File

@ -13,7 +13,7 @@ function App() {
const [playerSocket, setPlayerSocket] = useState(); const [playerSocket, setPlayerSocket] = useState();
const [redirect, setRedirect] = useState(); const [redirect, setRedirect] = useState();
useEffect(() => { useEffect(() => {
const socket = io('http://localhost:8080', { withCredentials: true }); const socket = io(`http://${window.location.hostname}:8080`, { withCredentials: true });
socket.on('player:data', data => { socket.on('player:data', data => {
data = JSON.parse(data); data = JSON.parse(data);
setPlayerData(data); setPlayerData(data);

View File

@ -1,7 +1,7 @@
.serversTableContainer { .serversTableContainer {
display: flex; display: flex;
height: 500px;
overflow: scroll; overflow: scroll;
height: 500px;
width: 100%; width: 100%;
} }
.refresh { .refresh {

View File

@ -1,6 +1,8 @@
.roomName { .roomName {
max-width: 150px; max-width: 150px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left !important; text-align: left !important;
} }
.rooms > thead > tr :nth-child(2) { .rooms > thead > tr :nth-child(2) {
@ -30,6 +32,7 @@
.rooms { .rooms {
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
height: fit-content;
} }
.lastColumn { .lastColumn {