diff --git a/backend/index.mjs b/backend/index.mjs deleted file mode 100644 index b31b947..0000000 --- a/backend/index.mjs +++ /dev/null @@ -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) -}); diff --git a/backend/package.json b/backend/package.json index 6d2108c..d2ece0b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,13 +2,12 @@ "name": "centurion-via-backend", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "./src/index.mjs", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", - "type": "module", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0" diff --git a/backend/src/Lobby.js b/backend/src/Lobby.js new file mode 100644 index 0000000..427d9fc --- /dev/null +++ b/backend/src/Lobby.js @@ -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) + } +}; diff --git a/backend/src/User.js b/backend/src/User.js new file mode 100644 index 0000000..b071f72 --- /dev/null +++ b/backend/src/User.js @@ -0,0 +1,5 @@ +module.exports = class User { + constructor(id) { + this.id = id; + } +}; \ No newline at end of file diff --git a/backend/src/index.js b/backend/src/index.js new file mode 100644 index 0000000..b297585 --- /dev/null +++ b/backend/src/index.js @@ -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('
' + JSON.stringify(state) + '')); + +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 + }); + }); +}); \ No newline at end of file diff --git a/backend/src/service.js b/backend/src/service.js new file mode 100644 index 0000000..1afea33 --- /dev/null +++ b/backend/src/service.js @@ -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}; \ No newline at end of file diff --git a/backend/src/state.js b/backend/src/state.js new file mode 100644 index 0000000..a1ba849 --- /dev/null +++ b/backend/src/state.js @@ -0,0 +1,62 @@ +const Lobby = require("./Lobby.js"); +const User = require("./User.js"); +const {getRandomInt} = require("./util.js"); + +class State { + /** + * @type {Object.
' + JSON.stringify(state) + '') +}); diff --git a/backend/test/b.js b/backend/test/b.js new file mode 100644 index 0000000..0a199df --- /dev/null +++ b/backend/test/b.js @@ -0,0 +1,7 @@ +const state = require('./state.js'); + +module.exports = { + test: (i) => { + state.setA(i); + } +}; \ No newline at end of file diff --git a/backend/test/state.js b/backend/test/state.js new file mode 100644 index 0000000..8e75986 --- /dev/null +++ b/backend/test/state.js @@ -0,0 +1,12 @@ +class State { + a = 3; + constructor() { + + } + + setA(i) { + this.a = i; + } +} + +module.exports = new State(); \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8b7e2aa..0dec889 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,36 +2,56 @@ import React, {useEffect, useState} from 'react'; import './App.css'; import logo from "./via-logo.svg" import {Row} from "antd" -import socket from "./util/socket"; +import socket, { emit } from "./util/socket"; import NextShot from "./components/NextShot"; import ShotsTaken from "./components/ShotsTaken"; import Feed from "./components/Feed"; +import Lobby from "./components/Lobby"; const App = () => { + const [connected, setConnected] = useState(false); + const [lobbyId, setLobbyId] = useState(null); useEffect(() => { - socket.on('connected', () => { - console.log('connected :)') + socket.on('welcome', async (obj: any) => { + const {lobby} = obj; + setLobbyId(lobby); + setConnected(true); + + // const joined = await emit('join_lobby', 123); }); return () => { socket.off("SENDING_NEW_TIME"); - socket.off("connection"); + socket.off("welcome"); } }); + const gameContent = ( +