From 6dc331c3923a6f85b240c9cd386ca6108efb4227 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Mon, 20 May 2019 20:01:42 +0200 Subject: [PATCH] Bug Fixes and field toggle - fixed overlay bugs - added feedback to startRound button - switched to socket.io for field toggle - added compression and minify --- CHANGELOG.md | 2 + app.js | 7 +++ package-lock.json | 84 +++++++++++++++++++++++++++++++++ package.json | 5 +- public/javascripts/bingo-web.js | 67 +++++++++++--------------- routes/bingo.js | 22 ++++++++- 6 files changed, 146 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f64c2..c12fcf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - socket.io for real time communication +- compression and minify ## Changed - frontend to use socket.io instead of graphql for refreshing +- use of socket.io for toggeling binogo fields ### Removed diff --git a/app.js b/app.js index 6d8fcb4..195a2f9 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,9 @@ const createError = require('http-errors'), cookieParser = require('cookie-parser'), logger = require('morgan'), compileSass = require('express-compile-sass'), + minify = require('express-minify'), + compression = require('compression'), + uglifyEs = require('uglify-es'), session = require('express-session'), pgSession = require('connect-pg-simple')(session), fsx = require('fs-extra'), @@ -48,6 +51,10 @@ async function init() { app.set('view engine', 'pug'); app.set('trust proxy', 1); + app.use(compression()); + app.use(minify({ + uglifyJsModule: uglifyEs + })); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({extended: false})); diff --git a/package-lock.json b/package-lock.json index df255e2..69abc15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -800,6 +800,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -815,6 +820,38 @@ "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "requires": { + "mime-db": ">= 1.40.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1744,6 +1781,32 @@ } } }, + "express-minify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/express-minify/-/express-minify-1.0.0.tgz", + "integrity": "sha512-04/iYxB79jGeNZBBkbAW7L7FMG4Wtu78F1SayXIKiJD6MfqYnOI3DD8no7QOntgedYCdYUpj+Skg8QWR/2WnMQ==", + "requires": { + "clean-css": "^4.1.7", + "on-headers": "^1.0.1", + "uglify-js": "^3.0.28" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "uglify-js": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz", + "integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==", + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + } + } + } + }, "express-session": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", @@ -5787,6 +5850,27 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", diff --git a/package.json b/package.json index e8716eb..fe732bd 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,14 @@ "start": "node ./bin/www" }, "dependencies": { + "compression": "^1.7.4", "connect-pg-simple": "5.0.0", "cookie-parser": "1.4.4", "debug": "4.1.1", "express": "4.17.0", "express-compile-sass": "latest", "express-graphql": "0.8.0", + "express-minify": "^1.0.0", "express-session": "latest", "fs-extra": "8.0.1", "graphql": "14.3.0", @@ -26,7 +28,8 @@ "node-sass": "4.12.0", "pg": "7.11.0", "pug": "2.0.3", - "socket.io": "^2.2.0" + "socket.io": "^2.2.0", + "uglify-es": "^3.3.9" }, "devDependencies": { "eslint": "^5.16.0", diff --git a/public/javascripts/bingo-web.js b/public/javascripts/bingo-web.js index de97fec..ea510c7 100644 --- a/public/javascripts/bingo-web.js +++ b/public/javascripts/bingo-web.js @@ -378,9 +378,11 @@ async function sendChatMessage() { * @returns {Promise} */ async function startRound() { + let roundStart = document.querySelector('#button-round-start'); let textinput = document.querySelector('#input-bingo-words'); let words = getLobbyWords(); if (words.length > 0) { + roundStart.setAttribute('class', 'pending'); let gridSize = document.querySelector('#input-grid-size').value || 3; let resultWords = await BingoGraphqlHelper.setLobbySettings(words, gridSize); if (resultWords) { @@ -402,6 +404,7 @@ async function startRound() { console.error(response); showError('Error when starting round.'); } + roundStart.setAttribute('class', ''); } } else { throw new Error('No words provided.'); @@ -429,32 +432,8 @@ async function submitFieldToggle(wordPanel) { let column = Number(wordPanel.getAttribute('b-column')); let wordClass = wordPanel.getAttribute('class'); wordPanel.setAttribute('class', wordClass + ' pending'); - let response = await postGraphqlQuery(` - mutation($lobbyId:ID!, $row:Int!, $column:Int!){ - bingo { - mutateLobby(id:$lobbyId) { - toggleGridField(location:{row:$row, column:$column}) { - submitted - grid { - bingo - } - } - } - } - }`, {lobbyId: getLobbyParam(), row: row, column: column}); - wordPanel.setAttribute('class', wordClass); - - if (response.status === 200) { - wordPanel.setAttribute('b-sub', response.data.bingo.mutateLobby.toggleGridField.submitted); - if (response.data.bingo.mutateLobby.toggleGridField.grid.bingo) - document.querySelector('#container-bingo-button').setAttribute('class', ''); - else - document.querySelector('#container-bingo-button').setAttribute('class', 'hidden'); - } else { - console.error(response); - showError('Error when submitting field toggle'); - } + socket.emit('fieldToggle', {row: row, column: column}); } /** @@ -483,7 +462,7 @@ async function setRoundFinished() { /** * Submits bingo - * @returns {Promise} + * @returns {Promise} */ async function submitBingo() { let response = await postGraphqlQuery(` @@ -504,8 +483,7 @@ async function submitBingo() { }`, {lobbyId: getLobbyParam()}); if (response.status === 200 && response.data.bingo.mutateLobby.submitBingo) { - let round = response.data.bingo.mutateLobby.submitBingo; - displayWinner(round); + return true; } else { console.error(response); showError('Failed to submit bingo'); @@ -514,10 +492,10 @@ async function submitBingo() { /** * Displays the winner of the game in a popup. - * @param roundInfo {Object} - the round object as returned by graphql + * @param winner {Object} - the round object as returned by graphql */ -function displayWinner(roundInfo) { - let name = roundInfo.winner.username; +function displayWinner(winner) { + let name = winner.username; let winnerDiv = document.createElement('div'); let greyoverDiv = document.createElement('div'); winnerDiv.setAttribute('class', 'popup'); @@ -585,7 +563,7 @@ function addChatMessage(messageObject, player) { ${messageObject.htmlContent}`; - if (messageObject.author && messageObject.author.id !== player) + if (messageObject.type === 'USER' && messageObject.author && messageObject.author.id !== player) spawnNotification(messageObject.content, messageObject.author.username); let chatContent = document.querySelector('#chat-content'); @@ -678,16 +656,16 @@ function initSocketEvents(data) { }); socket.on('message', (msg) => { - console.log(msg); addChatMessage(msg, playerId); }); - socket.on('statusChange', (status) => { - console.log(`Status changed to ${status}`); - if (status === 'FINISHED') - BingoGraphqlHelper.loadWinnerInfo(); - else + socket.on('statusChange', (status, winner) => { + if (status === 'FINISHED') { + if (document.querySelector('#container-bingo-round')) + displayWinner(winner); + } else { window.location.reload(); + } }); socket.on('playerJoin', (playerObject) => { @@ -699,7 +677,6 @@ function initSocketEvents(data) { }); socket.on('usernameChange', (playerObject) => { - console.log(playerObject); document.querySelector(`.playerEntryContainer[b-pid='${playerObject.id}'] .playerNameSpan`).innerText = playerObject.username; }); @@ -710,6 +687,16 @@ function initSocketEvents(data) { showError('Failed to load new lobby words.'); } }); + + socket.on('fieldChange', (field) => { + let wordPanel = document.querySelector(`.bingoWordPanel[b-row='${field.row}'][b-column='${field.column}']`); + wordPanel.setAttribute('b-sub', field.submitted); + wordPanel.setAttribute('class', 'bingoWordPanel'); + if (field.bingo) + document.querySelector('#container-bingo-button').setAttribute('class', ''); + else + document.querySelector('#container-bingo-button').setAttribute('class', 'hidden'); + }); } /** @@ -747,6 +734,8 @@ window.onload = async () => { showError(err.message); } } + let chatContent = document.querySelector('#chat-content'); + chatContent.scrollTop = chatContent.scrollHeight; }; let socket = null; diff --git a/routes/bingo.js b/routes/bingo.js index 11a0fda..a48db69 100644 --- a/routes/bingo.js +++ b/routes/bingo.js @@ -891,7 +891,7 @@ class RoundWrapper { let updateResult = await bdm.setRoundWinner(this.id, winnerId); if (updateResult) await this.setFinished(); - (await this.lobby()).socket.emit('statusChange', 'FINISHED'); + (await this.lobby()).socket.emit('statusChange', 'FINISHED', await resolvePlayer(new PlayerWrapper(winnerId))); return true; } } @@ -1456,6 +1456,20 @@ async function resolvePlayer(playerWrapper, lobbyId) { }; } +/** + * Resolves a fieldWrapper object + * @param fieldWrapper + * @returns {Promise<{submitted: (Object.submitted|*), column: *, bingo: boolean, row: (Object.grid_row|number|*)}>} + */ +async function resolveGridField(fieldWrapper) { + return { + row: fieldWrapper.row, + column: fieldWrapper.column, + submitted: fieldWrapper.submitted, + bingo: await fieldWrapper.grid.bingo() + }; +} + /** * Returns resolved message data. * @param lobbyId @@ -1493,6 +1507,12 @@ function createSocketIfNotExist(io, lobbyId) { console.log(err); } }); + socket.on('fieldToggle', async (context, location) => { + let {row, column} = location; + let result = await (await (new PlayerWrapper(context.playerId)).grid({lobbyId: lobbyId})) + .toggleField(row, column); + socket.emit('fieldChange', await resolveGridField(result)); + }); }); } }