diff --git a/backend/index.js b/backend/index.js index c3cda72..56e468f 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,24 +1,27 @@ -const express = require('express'); -const session = require('express-session'); +import express from 'express'; +import session from 'express-session'; +import mongodb from 'mongodb'; +import MongoStore from 'connect-mongo'; +import cors from 'cors'; +import { createNanoEvents } from 'nanoevents'; + +import "dotenv/config"; + +import names from './names.json' assert { type: "json" }; const app = express(); -const { MongoClient, ObjectId } = require('mongodb'); -const MongoStore = require('connect-mongo'); -const cors = require('cors'); -require('dotenv').config(); + +const emitter = createNanoEvents(); +const { MongoClient, ObjectId } = mongodb; app.use(cors({ - origin: [ - process.env.FRONTEND, - ], + origin: process.env.FRONTEND, credentials: true, exposedHeaders: ['set-cookie'], })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -const names = require('./names.json'); - const client = new MongoClient(process.env.URI, { useUnifiedTopology: true }); (async () => { @@ -139,34 +142,40 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true }); } }); + const state = {} app.post('/api/answer', async (req, res) => { - if (req.session.loggedIn) { - if (req.body.data.id && req.body.data.name) { - const card = await cardsCollection.findOne({ _id: ObjectId(req.body.data.id) }); - if (card) { - const correct = card.name === req.body.data.name; - if (correct) { - req.session.right += 1; - } else { - req.session.wrong += 1; - } - answersCollection.insertOne({ - correct, - selected: req.body.data.name, - }); - res.status(200).send({ - correct, - card, - }); - } else { - res.status(500).send(); - } - } else { - res.status(400).send(); - } - } else { - res.status(403).send(); + if (!req.session.loggedIn) { + return res.status(403).send(); } + + if (!req.body.data.id || !req.body.data.name || !req.body.data.username) { + return res.status(400).send(); + } + + const card = await cardsCollection.findOne({ _id: ObjectId(req.body.data.id) }); + if (!card) { + return res.status(500).send(); + } + + const correct = card.name === req.body.data.name; + if (correct) { + req.session.right += 1; + } else { + req.session.wrong += 1; + } + answersCollection.insertOne({ + correct, + selected: req.body.data.name, + }); + + state[req.body.data.username] = true + emitter.emit('answer', req.body.data.username); + + // return res.status(200).send({ + // correct, + // card, + // }); + return res.status(200).send() }); app.get('/api/score', (req, res) => { @@ -219,5 +228,73 @@ const client = new MongoClient(process.env.URI, { useUnifiedTopology: true }); } }); + let usernames = new Set(); + app.post('/api/connect', async (req, res) => { + if (!req.session.loggedIn) { + return res.status(403).send(); + } + + const { username } = req.body; + usernames.add(username); + state[username] = false; + emitter.emit('connection', usernames) + + return res.status(200).send(); + }); + + app.post('/api/end', async (req, res) => { + if (!req.session.loggedIn) { + return res.status(403).send(); + } + + usernames = new Set(); + state = {} + return res.status(200).send(); + }); + + app.get('/api/stream', async (req, res) => { + res.set({ + 'Access-Control-Allow-Origin': '*', + 'Cache-Control': 'no-cache', + Connection: 'keep-alive', + 'Content-Type': 'text/event-stream', + }); + res.flushHeaders(); + + emitter.on('connection', (usernames) => { + const data = usernames + res.write(`data: ${JSON.stringify(data)}\nevent: userlist\n\n`); + }) + + emitter.on('answer', (username) => { + const data = { + username, + state + } + res.write(`data: ${JSON.stringify(data)}\nevent: answer\n\n`); + }); + + emitter.on('allDone', () => { + const data = {} + res.write(`data: ${JSON.stringify(data)}\nevent: reveal\n\n`); + }); + + res.on('close', () => { + res.end(); + }); + }); + + let answers = 0; + emitter.on('answer', () => { + answers += 1; + + if (answers === usernames.length) { + Object.keys(state).forEach((key) => { + state[key] = false + }) + emitter.emit('allDone'); + } + }); + app.listen(process.env.PORT, () => console.log(`Server started on ${process.env.PORT}`)); })(); diff --git a/backend/package.json b/backend/package.json index 2f3ce3b..22f48a1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { "dev": "nodemon index.js" }, @@ -19,7 +20,8 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "express-session": "^1.17.1", - "mongodb": "^3.6.5" + "mongodb": "^3.6.5", + "nanoevents": "^7.0.1" }, "eslintConfig": { "extends": "airbnb-base", diff --git a/backend/yarn.lock b/backend/yarn.lock index ac39a9c..9ad157c 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1193,6 +1193,11 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nanoevents@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/nanoevents/-/nanoevents-7.0.1.tgz#181580b47787688d8cac775b977b1cf24e26e570" + integrity sha512-o6lpKiCxLeijK4hgsqfR6CNToPyRU3keKyyI6uwuHRvpRTbZ0wXw51WRgyldVugZqoJfkGFrjrIenYH3bfEO3Q== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" diff --git a/frontend/package.json b/frontend/package.json index ae355dd..cb0666d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,7 +11,10 @@ "dependencies": { "axios": "^0.21.1", "core-js": "^3.6.5", - "vue": "^3.0.0", + "pinia": "^2.1.4", + "vue": "^3.3.4", + "vue-peel": "^0.1.1", + "vue-router": "4", "vue-spinner": "^1.0.4" }, "devDependencies": { @@ -30,7 +33,7 @@ "node": true }, "extends": [ - "plugin:vue/vue3-essential", + "plugin:vue/vue3-recommended", "eslint:recommended" ], "parserOptions": { diff --git a/frontend/public/index.html b/frontend/public/index.html index 062393e..9c03737 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -9,7 +9,7 @@ - <%= htmlWebpackPlugin.options.title %> + Флекспатруль мультиплеер