added handler for login

This commit is contained in:
Wenszel 2022-05-29 14:34:18 +02:00
parent ecc319b529
commit 9686276ece
12 changed files with 23967 additions and 336 deletions

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"jsxSingleQuote": true,
"semi": true,
"singleQuote": true,
"printWidth": 120,
"tabWidth": 4,
"trailingComma": "es5",
"arrowParens": "avoid"
}

View File

@ -0,0 +1,85 @@
const RoomModel = require('../schemas/room');
const { colors } = require('../utils/constants');
const { getStartPositions } = require('../utils/functions');
module.exports = (io, socket) => {
const req = socket.request;
const login = data => {
// When new player login to game we are looking for not full and not started room to put player there
RoomModel.findOne({ full: false, started: false }, function (err, room) {
if (room) {
// If there is one adds player to it
addPlayerToExistingRoom(room, data);
} else {
// If not creates new room and add player to it
createNewRoom(data);
}
});
};
socket.on('player:login', login);
function createNewRoom(data) {
const room = new RoomModel({
createDate: new Date(),
players: [
{
name: data.name,
color: colors[0],
},
],
pawns: getStartPositions(),
});
// Saves new room to database
room.save().then(() => {
// Since it is not bound to an HTTP request, the session must be manually reloaded and saved
req.session.reload(err => {
if (err) return socket.disconnect();
// Saving session data
req.session.roomId = room._id;
req.session.playerId = room.players[0]._id;
req.session.color = room.players[0].color;
req.session.save();
// Sending data to the user, after which player will be redirected to the game
socket.emit('player:data', JSON.stringify(req.session));
});
});
}
function addPlayerToExistingRoom(room, data) {
// Adding a new user to the room
room.players.push({
name: data.name,
ready: false,
color: colors[room.players.length],
});
const updatedRoom = { players: room.players };
// Checking if the room is full
if (room.players.length === 4) {
// Changes the properties of the room to the state to start the game
updatedRoom = {
...updatedRoom,
full: true,
started: true,
nextMoveTime: Date.now() + 15000,
pawns: getStartPositions(),
};
updatedRoom.players.forEach(player => (player.ready = true));
updatedRoom.players[0].nowMoving = true;
}
// Updates a room in the database
RoomModel.findOneAndUpdate({ _id: room._id }, updatedRoom).then(() => {
// Since it is not bound to an HTTP request, the session must be manually reloaded and saved
req.session.reload(err => {
if (err) return socket.disconnect();
// Saving session data
req.session.roomId = room._id;
req.session.playerId = updatedRoom.players[updatedRoom.players.length - 1]._id;
req.session.color = colors[updatedRoom.players.length - 1];
req.session.save();
// Sending data to the user, after which player will be redirected to the game
socket.emit('player:data', JSON.stringify(req.session));
});
});
}
};

1626
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
"dependencies": { "dependencies": {
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"connect-mongo": "^4.4.0", "connect-mongo": "^4.4.0",
"connect-mongodb-session": "^2.4.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",
"express": "^4.17.1", "express": "^4.17.1",

View File

@ -1,125 +1,47 @@
const express = require('express'); const express = require("express");
const router = express.Router(); const router = express.Router();
const RoomModel = require('../schemas/room'); const RoomModel = require("../schemas/room");
const colors = ['red','blue','green','yellow'];
function getStartPositions(){
const startPositions = [];
for( let i = 0; i < 16; i++){
let pawn = {};
pawn.basePos = i;
pawn.position = i;
if(i < 4) pawn.color = colors[0];
else if(i < 8) pawn.color = colors[1];
else if(i < 12) pawn.color = colors[2];
else if (i < 16) pawn.color = colors[3]
startPositions.push(pawn);
}
return startPositions;
}
//creating new room in db
router.post('/add', function (req, res) {
RoomModel.findOne( { full: false, started: false }, function (err, results) {
if (err) console.log(err);
if (!results) {
let newRoom = new RoomModel({
createDate: new Date,
full: false,
started: false,
players: [{
name: req.body.name,
nowMoving: false,
ready: false,
color: colors[0]
}],
pawns: getStartPositions(),
});
newRoom.save()
.then(function(){
req.session.roomId = newRoom._id;
req.session.playerId = newRoom.players[0]._id;
req.session.color = newRoom.players[0].color;
res.status(200).send(req.session.playerId);
})
.catch(err => res.status(400).json('Error: ' + err))
}else {
let players = results.players;
players.push({
name: req.body.name,
ready: false,
color: colors[players.length]
});
let updateObj = { players: players }
// Checks if room is full => if true start game
if (players.length === 4) {
updateObj.full = true; // Room is full
updateObj.started = true; // Game started
updateObj.nextMoveTime = Date.now() + 15000;
updateObj.players.forEach(player => player.ready = true);
updateObj.players[0].nowMoving = true; //First joined player moving
updateObj.pawns = getStartPositions();
}
RoomModel.findOneAndUpdate(
{ _id: results._id }, //find room by id
updateObj)
.then(()=>{
req.session.roomId = results._id;
req.session.playerId = updateObj.players[updateObj.players.length-1]._id;
req.session.color = colors[updateObj.players.length-1];
res.status(200).send(req.session.playerId);
});
}
});
});
//get room values //get room values
router.get('/', function(req,res){ router.get("/", function (req, res) {
RoomModel.findOne( RoomModel.findOne(
{ _id: req.session.roomId }, //find room by id { _id: req.session.roomId }, //find room by id
function (err, docs) { function (err, docs) {
if (err){ if (err) {
console.log(err) console.log(err);
} } else {
else{ if (docs) {
if(docs){ if (docs.nextMoveTime <= Date.now()) {
if(docs.nextMoveTime <= Date.now()){ RoomModel.findOne({ _id: req.session.roomId }, function (err, doc) {
RoomModel.findOne({_id: req.session.roomId}, function (err, doc){
if (err) { if (err) {
res.status(500).send(err) res.status(500).send(err);
} else { } else {
const index = doc.players.findIndex( player => player.nowMoving === true); const index = doc.players.findIndex(player => player.nowMoving === true);
const roomSize = doc.players.length; const roomSize = doc.players.length;
doc.players[index].nowMoving = false; doc.players[index].nowMoving = false;
if(index + 1 === roomSize){ if (index + 1 === roomSize) {
doc.players[0].nowMoving = true; doc.players[0].nowMoving = true;
}else{ } else {
doc.players[index + 1].nowMoving = true; doc.players[index + 1].nowMoving = true;
} }
doc.nextMoveTime = Date.now()+15000; doc.nextMoveTime = Date.now() + 15000;
RoomModel.findOneAndUpdate({_id: req.session.roomId}, doc, function(err, docs){ RoomModel.findOneAndUpdate({ _id: req.session.roomId }, doc, function (err, docs) {
if(err){ if (err) {
res.status(500).send(err) res.status(500).send(err);
}else{ } else {
res.send(docs); res.send(docs);
} }
}); });
} }
}); });
}else{ } else {
res.send(docs); res.send(docs);
} }
} }
} }
} }
) );
}); });
module.exports = router; module.exports = router;

View File

@ -4,22 +4,26 @@ var Schema = mongoose.Schema;
var RoomSchema = new Schema({ var RoomSchema = new Schema({
createDate: Date, createDate: Date,
started: Boolean, started: { type: Boolean, default: false },
full: Boolean, full: { type: Boolean, default: false },
nextMoveTime: Number, nextMoveTime: Number,
players: [{ players: [
name: String, {
color: String, name: String,
ready: Boolean, color: String,
nowMoving: Boolean, ready: { type: Boolean, default: false },
}], nowMoving: { type: Boolean, default: false },
pawns: [{ },
color: String, ],
basePos: Number, pawns: [
position: Number, {
}], color: String,
basePos: Number,
position: Number,
},
],
}); });
var RoomModel = mongoose.model('RoomModel', RoomSchema ); var RoomModel = mongoose.model('RoomModel', RoomSchema);
module.exports = RoomModel; module.exports = RoomModel;

View File

@ -1,66 +1,97 @@
const express = require("express"); const express = require('express');
const cors = require("cors"); const cors = require('cors');
const cookieParser = require("cookie-parser"); const cookieParser = require('cookie-parser');
const { sessionMiddleware, wrap } = require("./controllers/serverController"); const { sessionMiddleware, wrap } = require('./controllers/serverController');
const registerPlayerHandlers = require('./handlers/playerHandler');
const PORT = 8080;
const mongoose = require('mongoose');
const CONNECTION_URI = require('./credentials.js');
const app = express(); const app = express();
app.use(cookieParser()); app.use(cookieParser());
app.use( app.use(
express.urlencoded({ express.urlencoded({
extended: true, extended: true,
}) })
); );
app.use(express.json()); app.use(express.json());
app.set("trust proxy", 1); app.set('trust proxy', 1);
app.use( app.use(
cors({ cors({
origin: "http://localhost:3000", origin: 'http://localhost:3000',
credentials: true, credentials: true,
}) })
); );
const PORT = 5000;
app.use(sessionMiddleware); app.use(sessionMiddleware);
//DATABASE CONFIG
const mongoose = require("mongoose");
mongoose.set("useFindAndModify", false);
const CONNECTION_URI = require("./credentials.js");
mongoose.set('useFindAndModify', false);
mongoose mongoose
.connect(CONNECTION_URI, { .connect(CONNECTION_URI, {
useNewUrlParser: true, useNewUrlParser: true,
useUnifiedTopology: true, useUnifiedTopology: true,
}) })
.then(() => { .then(() => {
console.log("MongoDB Connected…"); console.log('MongoDB Connected…');
}) })
.catch((err) => console.error(err)); .catch(err => console.error(err));
//SESSION CONFIG
if (process.env.NODE_ENV === "production") {
app.use(express.static("/app/build"));
app.get("/", (req, res) => {
res.sendFile("/app/build/index.html");
});
}
const server = app.listen(PORT, () => { const server = app.listen(PORT, () => {
console.log("Server runs on port " + PORT); console.log('Server runs on port ' + PORT);
}); });
const io = require("socket.io")(server, {
cors: { const io = require('socket.io')(server, {
origin: "http://localhost:3000", cors: {
credentials: true, origin: 'http://localhost:3000',
}, credentials: true,
},
allowRequest: (req, callback) => {
const fakeRes = {
getHeader() {
return [];
},
setHeader(key, values) {
req.cookieHolder = values[0];
},
writeHead() {},
};
sessionMiddleware(req, fakeRes, () => {
if (req.session) {
fakeRes.writeHead();
req.session.save();
}
callback(null, true);
});
},
});
io.engine.on('initial_headers', (headers, req) => {
if (req.cookieHolder) {
headers['set-cookie'] = req.cookieHolder;
delete req.cookieHolder;
}
}); });
io.use(wrap(sessionMiddleware)); io.use(wrap(sessionMiddleware));
io.on("connection", (socket) => {
socket.emit("client data", JSON.stringify(socket.request.session)); io.on('connection', socket => {
registerPlayerHandlers(io, socket);
if (socket.request.session.roomId) {
socket.join(socket.request.session.roomId);
socket.emit('player:data', JSON.stringify(session));
io.to(socket.request.session.roomId).emit('player joined');
}
}); });
//ROUTES CONFIG //ROUTES CONFIG
const roomRoutes = require("./routes/room"); const roomRoutes = require('./routes/room');
const playerRoutes = require("./routes/player"); const playerRoutes = require('./routes/player');
const gameRoutes = require("./routes/game"); const gameRoutes = require('./routes/game');
app.use("/player", playerRoutes); app.use('/player', playerRoutes);
app.use("/room", roomRoutes); app.use('/room', roomRoutes);
app.use("/game", gameRoutes); app.use('/game', gameRoutes);
if (process.env.NODE_ENV === 'production') {
app.use(express.static('/app/build'));
app.get('/', (req, res) => {
res.sendFile('/app/build/index.html');
});
}

View File

@ -0,0 +1,2 @@
const colors = ["red", "blue", "green", "yellow"];
module.exports = { colors };

View File

@ -0,0 +1,16 @@
const { colors } = require("./constants");
function getStartPositions() {
const startPositions = [];
for (let i = 0; i < 16; i++) {
let pawn = {};
pawn.basePos = i;
pawn.position = i;
if (i < 4) pawn.color = colors[0];
else if (i < 8) pawn.color = colors[1];
else if (i < 12) pawn.color = colors[2];
else if (i < 16) pawn.color = colors[3];
startPositions.push(pawn);
}
return startPositions;
}
module.exports = { getStartPositions };

22121
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +1,51 @@
import React, { useEffect, useState, createContext } from "react"; import React, { useEffect, useState, createContext } from 'react';
import axios from "axios"; import { io } from 'socket.io-client';
import { io } from "socket.io-client"; import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';
import { Beforeunload } from "react-beforeunload";
import {
BrowserRouter as Router,
Route,
Redirect,
Switch,
} from "react-router-dom";
import Gameboard from "./components/Gameboard"; import Gameboard from './components/Gameboard';
import NameInput from "./components/NameInput"; import NameInput from './components/NameInput';
export const PlayerDataContext = createContext(); export const PlayerDataContext = createContext();
export const SocketContext = createContext();
function App() { function App() {
const [playerData, setPlayerData] = useState(); const [playerData, setPlayerData] = useState();
const [redirect, setRedirect] = useState(); const [playerSocket, setPlayerSocket] = useState();
const [redirect, setRedirect] = useState();
useEffect(() => { useEffect(() => {
const socket = io("http://localhost:5000", { withCredentials: true }); const socket = io('http://localhost:8080', { withCredentials: true });
socket.on("client data", (data) => { socket.on('player:data', data => {
data = JSON.parse(data); console.log(data);
setPlayerData(data); data = JSON.parse(data);
data.roomId != null ? setRedirect(true) : setRedirect(false); setPlayerData(data);
}); data.roomId != null ? setRedirect(true) : setRedirect(false);
}, []); });
setPlayerSocket(socket);
}, []);
const handleExit = (e) => { return (
e.preventDefault(); <SocketContext.Provider value={playerSocket}>
window.addEventListener("unload", () => { <Router>
axios.post("/player/exit", { withCredentials: true }); {redirect ? <Redirect to='/game' /> : <Redirect to='/login' />}
}); <Switch>
}; <Route exact path='/'>
LOADING...
const idCallback = () => { </Route>
axios <Route path='/login'>
.get("/player/", { <NameInput />
withCredentials: true, </Route>
}) <Route path='/game'>
.then((response) => { {playerData ? (
setPlayerData(response.data); <PlayerDataContext.Provider value={playerData}>
console.log(response.data); <Gameboard />
setRedirect(true); </PlayerDataContext.Provider>
}); ) : null}
}; </Route>
</Switch>
return ( </Router>
<Router> </SocketContext.Provider>
{redirect ? <Redirect to="/game" /> : <Redirect to="/login" />} );
<Switch>
<Route exact path="/">
LOADING...
</Route>
<Route path="/login">
<NameInput idCallback={idCallback} />
</Route>
<Route path="/game">
{playerData ? (
<Beforeunload onBeforeunload={handleExit}>
<PlayerDataContext.Provider value={playerData}>
<Gameboard />
</PlayerDataContext.Provider>
</Beforeunload>
) : null}
</Route>
</Switch>
</Router>
);
} }
export default App; export default App;

View File

@ -1,30 +1,25 @@
import React, { useState } from 'react'; import React, { useState, useContext } from "react";
import axios from 'axios'; import { SocketContext } from "../App";
const NameInput = ({ idCallback }) => { const NameInput = () => {
const [inputValue, setInputValue] = useState(''); const socket = useContext(SocketContext);
const handleInputChange = (e) => { const [inputValue, setInputValue] = useState("");
setInputValue(e.target.value); const handleInputChange = (e) => {
} setInputValue(e.target.value);
};
const handleButtonClick = () => { const handleButtonClick = () => {
axios.post('/room/add',{ socket.emit("player:login", { name: inputValue });
name: inputValue };
},{ return (
withCredentials:true, <div>
"Content-Type": "application/json" <input
}) placeholder="Enter name"
.then(response => { type="text"
console.log(response.data); onChange={handleInputChange}
idCallback(response.data); />
}) <input type="submit" onClick={handleButtonClick} />
} </div>
return( );
<div> };
<input placeholder = "Enter name" type="text" onChange={handleInputChange}/>
<input type="submit" onClick={handleButtonClick}/>
</div>
)
}
export default NameInput; export default NameInput;