master
Wilco Kruijer 5 years ago
parent 248e65db47
commit ddeaca06c2
  1. 20
      backend/index.mjs
  2. 3
      backend/package.json
  3. 109
      backend/src/Lobby.js
  4. 5
      backend/src/User.js
  5. 44
      backend/src/index.js
  6. 43
      backend/src/service.js
  7. 62
      backend/src/state.js
  8. 15
      backend/src/util.js
  9. 15
      backend/test/a.js
  10. 7
      backend/test/b.js
  11. 12
      backend/test/state.js
  12. 34
      frontend/src/App.tsx
  13. 25
      frontend/src/components/Lobby.tsx
  14. 22
      frontend/src/util/socket.ts

@ -1,20 +0,0 @@
import express from "express";
import socketIO from "socket.io";
const PORT = 3001;
const app = express();
app.get('/', (req, res) => res.send('Hello World!'));
const server = app.listen(PORT, () => console.log(`Example app listening on port ${PORT}!`));
const io = socketIO(server);
io.on('connection', socket => {
console.log('a user connected', socket.id);
setInterval(() => {
console.log('send :)')
socket.emit("SENDING_NEW_TIME", "ASD")
}, 1500)
});

@ -2,13 +2,12 @@
"name": "centurion-via-backend", "name": "centurion-via-backend",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "./src/index.mjs",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"type": "module",
"dependencies": { "dependencies": {
"express": "^4.17.1", "express": "^4.17.1",
"socket.io": "^2.3.0" "socket.io": "^2.3.0"

@ -0,0 +1,109 @@
const User = require("./User.js");
module.exports = class Lobby {
/**
* @type {User[]}
*/
users = [];
/**
* @type {string|undefined}
*/
leaderId = undefined;
running = false;
runningInterval = undefined;
currentTime = 0;
constructor(name) {
this.name = name;
}
run() {
this.running = true;
this.runningInterval = setInterval(() => {
this.currentTime += 1;
}, 1000);
}
pause() {
this.running = false;
clearInterval(this.runningInterval);
}
/**
*
* @returns {boolean}
*/
hasUsers() {
return this.users.length !== 0;
}
setRandomLeader() {
if (this.hasUsers()) {
this.leaderId = this.users[0].id;
}
}
/**
*
* @param {User} user
*/
addUser(user) {
this.users.push(user);
}
/**
*
* @param id
* @returns {User|undefined}
*/
getUser(id) {
return this.users.find(u => u.id === id);
}
/**
*
* @param {string} id
*/
removeUser(id) {
this.users = this.users.filter(u => u.id !== id);
}
/**
*
* @returns {boolean}
*/
hasLeader() {
return !!this.leaderId;
}
/**
*
* @param {string} id
* @returns {boolean}
*/
isLeader(id) {
return this.leaderId === id;
}
/**
*
* @param {string} id
*/
setLeader(id) {
if (!this.getUser(id)) {
throw new Error('user_not_in_lobby');
}
this.leaderId = id;
}
/**
*
* @returns {User|undefined}
*/
getLeader() {
return this.users.find(u => u.id === this.leaderId)
}
};

@ -0,0 +1,5 @@
module.exports = class User {
constructor(id) {
this.id = id;
}
};

@ -0,0 +1,44 @@
const express = require("express");
const socketIO = require("socket.io");
const service = require("./service.js");
const state = require("./state.js");
const PORT = 3001;
const app = express();
const server = app.listen(PORT, () => console.log(`Example app listening on port ${PORT}!`));
const io = socketIO(server);
app.get('/', (req, res) => res.send('<pre>' + JSON.stringify(state) + '</pre>'));
io.on('connection', socket => {
const socketId = socket.id;
console.log('a user connected', socketId);
const lobby = service.joinLobby(socketId);
socket.join(lobby.name);
socket.emit('welcome', {lobby: lobby.name});
socket.on('disconnect', (reason) => {
console.log('Disconnected:', socketId);
service.leaveLobby(socketId);
});
socket.on('join_lobby', (lobbyId, callback) => {
console.log(`${socketId} wants to join '${lobbyId}'.`);
// Leave current lobby first
service.leaveLobby(socketId);
const lobby = service.joinLobby(socketId, lobbyId);
socket.join(lobby.name);
callback(null, {
status: 'ok',
lobby: lobby.name
});
});
});

@ -0,0 +1,43 @@
const User = require("./User.js");
const state = require("./state.js");
/**
*
* @param {string} socketId
* @param {number|undefined} lobbyId
* @returns {Lobby}
*/
function joinLobby(socketId, lobbyId=undefined) {
let lobby = state.getLobby(lobbyId);
if (!lobby) {
lobby = state.createRandomLobby();
}
lobby.addUser(new User(socketId));
if (!lobby.hasLeader()) {
lobby.setLeader(socketId);
}
state.lobbies[lobby.name] = lobby;
return lobby;
}
function leaveLobby(socketId) {
Object.keys(state.lobbies).forEach(lobbyId => {
const lobby = state.getLobby(lobbyId);
lobby.removeUser(socketId);
if (!lobby.hasUsers()) {
state.removeLobby(lobbyId);
return;
}
if (lobby.getLeader() === socketId) {
lobby.setRandomLeader();
}
});
}
module.exports = {joinLobby, leaveLobby};

@ -0,0 +1,62 @@
const Lobby = require("./Lobby.js");
const User = require("./User.js");
const {getRandomInt} = require("./util.js");
class State {
/**
* @type {Object.<string, Lobby>}
*/
lobbies = {};
lobbyCount = 0;
constructor() {
}
/**
* @returns {Lobby}
*/
createRandomLobby() {
let lobby = undefined;
while (!lobby) {
const id = getRandomInt(100, Math.max(1000, this.lobbyCount * 2));
lobby = this.createLobby(id);
}
return lobby;
}
/**
*
* @param lobbyId
* @returns {Lobby|undefined}
*/
getLobby(lobbyId) {
if (!lobbyId || !this.lobbies.hasOwnProperty(lobbyId)) {
return undefined;
}
return this.lobbies[lobbyId];
}
/**
* Returns undefined when the lobby already exists.
* @param {number} lobbyId
* @returns {Lobby|undefined}
*/
createLobby(lobbyId) {
if (this.lobbies.hasOwnProperty(lobbyId)) {
return undefined;
}
this.lobbyCount += 1;
return new Lobby(lobbyId);
}
removeLobby(lobbyId) {
this.lobbyCount -= 1;
delete this.lobbies[lobbyId];
}
}
module.exports = new State();

@ -0,0 +1,15 @@
/**
* Generates random int
* @param {number} min, inclusive
* @param {number} max, exclusive
* @returns {number}
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
module.exports = {
getRandomInt
};

@ -0,0 +1,15 @@
const express = require('express');
const state = require('./state.js');
const b = require('./b.js');
const PORT = 3002;
const app = express();
const server = app.listen(PORT, () => console.log(`Example app listening on port ${PORT}!`));
app.get('/', (req, res) => {
let i = state.a;
b.test(i += 1);
return res.send('<pre>' + JSON.stringify(state) + '</pre>')
});

@ -0,0 +1,7 @@
const state = require('./state.js');
module.exports = {
test: (i) => {
state.setA(i);
}
};

@ -0,0 +1,12 @@
class State {
a = 3;
constructor() {
}
setA(i) {
this.a = i;
}
}
module.exports = new State();

@ -2,36 +2,56 @@ import React, {useEffect, useState} from 'react';
import './App.css'; import './App.css';
import logo from "./via-logo.svg" import logo from "./via-logo.svg"
import {Row} from "antd" import {Row} from "antd"
import socket from "./util/socket"; import socket, { emit } from "./util/socket";
import NextShot from "./components/NextShot"; import NextShot from "./components/NextShot";
import ShotsTaken from "./components/ShotsTaken"; import ShotsTaken from "./components/ShotsTaken";
import Feed from "./components/Feed"; import Feed from "./components/Feed";
import Lobby from "./components/Lobby";
const App = () => { const App = () => {
const [connected, setConnected] = useState(false);
const [lobbyId, setLobbyId] = useState(null);
useEffect(() => { useEffect(() => {
socket.on('connected', () => { socket.on('welcome', async (obj: any) => {
console.log('connected :)') const {lobby} = obj;
setLobbyId(lobby);
setConnected(true);
// const joined = await emit('join_lobby', 123);
}); });
return () => { return () => {
socket.off("SENDING_NEW_TIME"); socket.off("SENDING_NEW_TIME");
socket.off("connection"); socket.off("welcome");
} }
}); });
return ( const gameContent = (
<>
<section className="content">
<Row> <Row>
<NextShot/> <NextShot/>
<Feed/> <Feed/>
<ShotsTaken/> <ShotsTaken/>
</Row> </Row>
);
const lobbyContent = (
<Row>
<Lobby/>
</Row>
);
const content = lobbyContent;
return (
<>
<section className="content">
{content}
</section> </section>
<footer> <footer>
<img src={logo} className="via-logo" alt="logo"/> <img src={logo} className="via-logo" alt="logo"/>
<span>{connected ? 'Verbonden ' + lobbyId : ''}</span>
</footer> </footer>
</> </>
); );

@ -0,0 +1,25 @@
import React, {useEffect} from 'react';
import {Col, Progress} from "antd"
import socket from "../util/socket";
const Lobby = () => {
useEffect(() => {
socket.on("SENDING_NEW_TIME", (data: string) => {
});
return () => {
socket.off("SENDING_NEW_TIME");
}
});
return (
<Col className="sider" span={4} offset={10}>
<h1>Centurion!</h1>
</Col>
);
};
export default Lobby;

@ -1,3 +1,23 @@
import io from "socket.io-client"; import io from "socket.io-client";
export default io("http://localhost:3001");
const socket = io("http://localhost:3001");
export default socket;
/**
* Promisify emit.
* @param event
* @param arg
* @param callback
*/
export function emit(event: string, arg: any) {
return new Promise((resolve, reject) => {
socket.emit(event, arg, (err: any, res: any) => {
if (err) {
return reject(err);
}
resolve(res);
})
})
}
Loading…
Cancel
Save