From b0c301bc1b43a9ac98687973ba397bd574f3043b Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Sat, 12 Sep 2020 13:52:42 -0400 Subject: [PATCH] Add client level command listeners --- example/example.js | 4 ++++ lib/client.js | 37 +++++++++++++++++++++++++++++++++++-- lib/clientManager.js | 11 +++++++++++ test/clientManagerTest.js | 11 +++++++++++ test/clientTest.js | 2 +- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/example/example.js b/example/example.js index 71db221..c71fc99 100644 --- a/example/example.js +++ b/example/example.js @@ -21,6 +21,10 @@ gameManager.on('clientAdded', (client) => { }); const server = new GMServer(function (client) { + client.addCommandListener('register', () => { + console.log('Client is registering.'); + }); + gameManager.addClient(client); }); diff --git a/lib/client.js b/lib/client.js index f771dc8..15f9407 100644 --- a/lib/client.js +++ b/lib/client.js @@ -3,12 +3,13 @@ const _ = require('lodash'); const TERMINATING_CHARACTER = '\0'; const DEBUG_MODE = process.env.GM_SERVER_DEBUG === 'true'; -const TERM_STR = '^X|X^'; +const TERM_STR = '\n\t\n'; class Client { constructor (socket) { this.socket = socket; this.dataHandlers = []; + this.commandHandlers = {}; this.clientId = _.uniqueId(); this.created = Date.now(); this.data = {}; @@ -22,13 +23,20 @@ class Client { console.info(this.clientId, ' received: ', JSON.stringify(dataAsObject)); } + // Low level handlers this.dataHandlers.forEach(handler => { handler(dataAsObject); }); + + // Client level command handlers + if (this.commandHandlers[dataAsObject.command]) { + this.commandHandlers[dataAsObject.command].forEach(handler => { + handler(dataAsObject); + }); + } }); socket.on('error', error => { - console.error('oops'); console.error(error); }); } @@ -105,6 +113,31 @@ class Client { this.dataHandlers.push(handler); } + /** + * Registers a callback function for when a given command is sent in by this client + * @param {string} command The command to listen for + * @param {function} handler A callback to run when the command is received + */ + addCommandListener (command, handler) { + // If there is a command listener for this command already, push. + if (this.commandHandlers[command]) { + this.commandHandlers[command].push(handler); + } else { + this.commandHandlers[command] = [handler]; + } + } + + /** + * Removes a registered callback function for when a given command is sent in by this client + * @param {string} command The command to listen for + * @param {function} handler The function to remove + */ + removeCommandListener (command, handler) { + if (this.commandHandlers[command]) { + this.commandHandlers[command] = this.commandHandlers[command].filter(fn => fn !== handler); + } + } + /** * Sets tick mode on or off. * @param {boolean} onOff diff --git a/lib/clientManager.js b/lib/clientManager.js index e73697b..802c701 100644 --- a/lib/clientManager.js +++ b/lib/clientManager.js @@ -140,6 +140,17 @@ class ClientManager { } } + /** + * Removes a registered callback function for when a given command is sent in by a client + * @param {string} command The command to listen for + * @param {function} handler The function to remove + */ + removeCommandListener (command, handler) { + if (this.commandHandlers[command]) { + this.commandHandlers[command] = this.commandHandlers[command].filter(fn => fn !== handler); + } + } + /** * Registers an event handler for ClientManager events * @param {string} eventName The event to listen for diff --git a/test/clientManagerTest.js b/test/clientManagerTest.js index e581ce2..e3940b0 100644 --- a/test/clientManagerTest.js +++ b/test/clientManagerTest.js @@ -99,6 +99,17 @@ describe('Client Manager', function () { }); }); + describe('.removeCommandListener()', function () { + it('removes registered commands', function () { + const handlerStub = sinon.stub(); + clientManager.addCommandListener('test', handlerStub); + clientManager.removeCommandListener('test', handlerStub); + clientManager.handleIncomingCommand(getFakeClient(), { command: 'test' }); + clientManager.handleIncomingCommand(getFakeClient(), { command: 'doNotRun' }); + assert(!handlerStub.called, 'The registered command handler was called'); + }); + }); + describe('.broadcast()', function () { it('can broadcast to all clients', function () { const fakeSocket = getFakeClient(); diff --git a/test/clientTest.js b/test/clientTest.js index 7f663e8..f7d1656 100644 --- a/test/clientTest.js +++ b/test/clientTest.js @@ -7,7 +7,7 @@ const Client = require('../lib/client.js'); const _ = require('lodash'); let client; let fakeSocket; -const TERM_STR = '^X|X^'; +const TERM_STR = '\n\t\n'; function getFakeNetSocket () { return {