From 2e9ab08d5ab5a7008c7ee7b2343fae57992bad70 Mon Sep 17 00:00:00 2001 From: AlecM33 Date: Wed, 30 Mar 2022 21:19:43 -0400 Subject: [PATCH 1/2] 4-digit access codes --- client/src/config/globals.js | 2 +- server/config/globals.js | 6 ++-- server/modules/GameManager.js | 29 ++++++++++++++------ spec/unit/server/modules/GameManager_Spec.js | 20 ++++++++++++++ 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/client/src/config/globals.js b/client/src/config/globals.js index b8a95f0..6d07eb2 100644 --- a/client/src/config/globals.js +++ b/client/src/config/globals.js @@ -4,7 +4,7 @@ export const globals = { MAX_CUSTOM_ROLE_NAME_LENGTH: 30, MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 500, TOAST_DURATION_DEFAULT: 6, - ACCESS_CODE_LENGTH: 6, + ACCESS_CODE_LENGTH: 4, PLAYER_ID_COOKIE_KEY: 'play-werewolf-anon-id', ACCESS_CODE_CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789', COMMANDS: { diff --git a/server/config/globals.js b/server/config/globals.js index 1c16e11..57fab5c 100644 --- a/server/config/globals.js +++ b/server/config/globals.js @@ -1,6 +1,7 @@ const globals = { ACCESS_CODE_CHAR_POOL: 'BCDFGHJKLMNPQRSTVWXYZ0123456789', - ACCESS_CODE_LENGTH: 6, + ACCESS_CODE_LENGTH: 4, + ACCESS_CODE_GENERATION_ATTEMPTS: 50, CLOCK_TICK_INTERVAL_MILLIS: 10, STALE_GAME_HOURS: 12, CLIENT_COMMANDS: { @@ -33,7 +34,8 @@ const globals = { }, ERROR_MESSAGE: { GAME_IS_FULL: 'This game is full', - BAD_CREATE_REQUEST: 'Game has invalid options.' + BAD_CREATE_REQUEST: 'Game has invalid options.', + NO_UNIQUE_ACCESS_CODE: 'Could not generate a unique access code.' }, EVENTS: { PLAYER_JOINED: 'playerJoined', diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js index 1ba9d0d..506fa92 100644 --- a/server/modules/GameManager.js +++ b/server/modules/GameManager.js @@ -171,7 +171,10 @@ class GameManager { } else { // to avoid excessive memory build-up, every time a game is created, check for and purge any stale games. pruneStaleGames(this.activeGameRunner.activeGames, this.activeGameRunner.timerThreads, this.logger); - const newAccessCode = this.generateAccessCode(); + const newAccessCode = this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL); + if (newAccessCode === null) { + return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE); + } const moderator = initializeModerator(gameParams.moderatorName, gameParams.hasDedicatedModerator); moderator.assigned = true; if (gameParams.timerParams !== null) { @@ -205,15 +208,23 @@ class GameManager { } }; - generateAccessCode = () => { - const numLetters = globals.ACCESS_CODE_CHAR_POOL.length; - const codeDigits = []; - let iterations = globals.ACCESS_CODE_LENGTH; - while (iterations > 0) { - iterations--; - codeDigits.push(globals.ACCESS_CODE_CHAR_POOL[getRandomInt(numLetters)]); + generateAccessCode = (charPool) => { + const charCount = charPool.length; + let codeDigits, accessCode; + let attempts = 0; + while (!accessCode || (this.activeGameRunner.activeGames[accessCode] && attempts < globals.ACCESS_CODE_GENERATION_ATTEMPTS)) { + codeDigits = []; + let iterations = globals.ACCESS_CODE_LENGTH; + while (iterations > 0) { + iterations--; + codeDigits.push(charPool[getRandomInt(charCount)]); + } + accessCode = codeDigits.join(''); + attempts ++; } - return codeDigits.join(''); + return this.activeGameRunner.activeGames[accessCode] + ? null + : accessCode; }; transferModeratorPowers = (game, person, namespace, logger) => { diff --git a/spec/unit/server/modules/GameManager_Spec.js b/spec/unit/server/modules/GameManager_Spec.js index 9dd5be8..2f10f01 100644 --- a/spec/unit/server/modules/GameManager_Spec.js +++ b/spec/unit/server/modules/GameManager_Spec.js @@ -260,4 +260,24 @@ describe('GameManager', () => { expect(gameManager.namespace.in().emit).toHaveBeenCalledWith(globals.EVENTS.NEW_SPECTATOR, jasmine.anything()); }); }); + + describe('#generateAccessCode', () => { + it('should continue to generate access codes up to the max attempts when the generated code is already in use by another game', () => { + gameManager.activeGameRunner.activeGames = { + 'AAAA': {} + }; + + const accessCode = gameManager.generateAccessCode(['A']); + expect(accessCode).toEqual(null); // we might the max generation attempts of 50. + }); + + it('should generate and return a unique access code', () => { + gameManager.activeGameRunner.activeGames = { + 'AAAA': {} + }; + + const accessCode = gameManager.generateAccessCode(['B']); + expect(accessCode).toEqual('BBBB'); + }); + }) }); From 3b052f66c8405746fe78384afa7007bd38524671 Mon Sep 17 00:00:00 2001 From: AlecM33 Date: Wed, 30 Mar 2022 21:26:30 -0400 Subject: [PATCH 2/2] lint under new rules --- client/src/modules/GameCreationStepManager.js | 6 +++--- client/src/modules/UserUtility.js | 2 +- server/modules/GameManager.js | 14 +++++++------- spec/unit/server/modules/GameManager_Spec.js | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/client/src/modules/GameCreationStepManager.js b/client/src/modules/GameCreationStepManager.js index 36c1c04..f626fad 100644 --- a/client/src/modules/GameCreationStepManager.js +++ b/client/src/modules/GameCreationStepManager.js @@ -462,7 +462,7 @@ function showButtons (back, forward, forwardHandler, backHandler, builtGame = nu // Display a widget for each default card that allows copies of it to be added/removed. Set initial deck state. function showIncludedCards (deckManager) { document.querySelectorAll('.compact-card').forEach((el) => { el.remove(); }); - for (let i = 0; i < deckManager.getCurrentDeck().length; i++) { + for (let i = 0; i < deckManager.getCurrentDeck().length; i ++) { const card = deckManager.getCurrentDeck()[i]; const cardEl = constructCompactDeckBuilderElement(card, deckManager); if (card.team === globals.ALIGNMENT.GOOD) { @@ -487,7 +487,7 @@ function loadDefaultCards (deckManager) { return a.role.localeCompare(b.role); }); const deck = []; - for (let i = 0; i < defaultCards.length; i++) { + for (let i = 0; i < defaultCards.length; i ++) { const card = defaultCards[i]; card.quantity = 0; deck.push(card); @@ -631,7 +631,7 @@ function addOptionsToList (deckManager, selectEl) { } return a.role.localeCompare(b.role); }); - for (let i = 0; i < options.length; i++) { + for (let i = 0; i < options.length; i ++) { const optionEl = document.createElement('div'); optionEl.innerHTML = HTMLFragments.DECK_SELECT_ROLE; optionEl.classList.add('deck-select-role'); diff --git a/client/src/modules/UserUtility.js b/client/src/modules/UserUtility.js index ce1912c..cb6e9eb 100644 --- a/client/src/modules/UserUtility.js +++ b/client/src/modules/UserUtility.js @@ -56,7 +56,7 @@ export const UserUtility = { function createRandomUserId () { let id = ''; - for (let i = 0; i < globals.USER_SIGNATURE_LENGTH; i++) { + for (let i = 0; i < globals.USER_SIGNATURE_LENGTH; i ++) { id += globals.ACCESS_CODE_CHAR_POOL[Math.floor(Math.random() * globals.ACCESS_CODE_CHAR_POOL.length)]; } return id; diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js index 506fa92..95fbe67 100644 --- a/server/modules/GameManager.js +++ b/server/modules/GameManager.js @@ -216,7 +216,7 @@ class GameManager { codeDigits = []; let iterations = globals.ACCESS_CODE_LENGTH; while (iterations > 0) { - iterations--; + iterations --; codeDigits.push(charPool[getRandomInt(charCount)]); } accessCode = codeDigits.join(''); @@ -373,9 +373,9 @@ function initializePeopleForGame (uniqueCards, moderator) { let cards = []; // this will contain copies of each card equal to the quantity. let numberOfRoles = 0; for (const card of uniqueCards) { - for (let i = 0; i < card.quantity; i++) { + for (let i = 0; i < card.quantity; i ++) { cards.push(card); - numberOfRoles++; + numberOfRoles ++; } } @@ -388,7 +388,7 @@ function initializePeopleForGame (uniqueCards, moderator) { moderator.gameRoleDescription = cards[j].description; moderator.alignment = cards[j].team; people.push(moderator); - j++; + j ++; } while (j < numberOfRoles) { @@ -404,14 +404,14 @@ function initializePeopleForGame (uniqueCards, moderator) { person.customRole = cards[j].custom; person.hasEnteredName = false; people.push(person); - j++; + j ++; } return people; } function shuffleArray (array) { - for (let i = 0; i < array.length; i++) { + for (let i = 0; i < array.length; i ++) { const randIndex = Math.floor(Math.random() * i); const temp = array[i]; array[i] = array[randIndex]; @@ -422,7 +422,7 @@ function shuffleArray (array) { function createRandomId () { let id = ''; - for (let i = 0; i < globals.USER_SIGNATURE_LENGTH; i++) { + for (let i = 0; i < globals.USER_SIGNATURE_LENGTH; i ++) { id += globals.ACCESS_CODE_CHAR_POOL[Math.floor(Math.random() * globals.ACCESS_CODE_CHAR_POOL.length)]; } return id; diff --git a/spec/unit/server/modules/GameManager_Spec.js b/spec/unit/server/modules/GameManager_Spec.js index 2f10f01..aaac3ee 100644 --- a/spec/unit/server/modules/GameManager_Spec.js +++ b/spec/unit/server/modules/GameManager_Spec.js @@ -264,7 +264,7 @@ describe('GameManager', () => { describe('#generateAccessCode', () => { it('should continue to generate access codes up to the max attempts when the generated code is already in use by another game', () => { gameManager.activeGameRunner.activeGames = { - 'AAAA': {} + AAAA: {} }; const accessCode = gameManager.generateAccessCode(['A']); @@ -273,11 +273,11 @@ describe('GameManager', () => { it('should generate and return a unique access code', () => { gameManager.activeGameRunner.activeGames = { - 'AAAA': {} + AAAA: {} }; const accessCode = gameManager.generateAccessCode(['B']); expect(accessCode).toEqual('BBBB'); }); - }) + }); });