From ceca822f974086eab7e927d78079012305386433 Mon Sep 17 00:00:00 2001 From: binaryDiv Date: Sun, 20 Jan 2019 21:12:41 +0100 Subject: [PATCH] Client: Implement event system (#4) --- public_html/index.html | 1 + public_html/js/client.js | 28 ++++++++++++++++++++------- public_html/js/events.js | 42 ++++++++++++++++++++++++++++++++++++++++ public_html/js/ui.js | 17 ++++++++++++++++ 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 public_html/js/events.js diff --git a/public_html/index.html b/public_html/index.html index 0c9aec9..743795d 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -12,6 +12,7 @@

InstantChat

+ diff --git a/public_html/js/client.js b/public_html/js/client.js index 5b90372..51b6869 100644 --- a/public_html/js/client.js +++ b/public_html/js/client.js @@ -1,7 +1,18 @@ "use strict"; -class Client { +/** + * Client class that implements the InstantChat protocol using WebSockets. + * + * Dispatches the following events which can be subscribed/unsubscribed using .on() and .off(): + * - initialized: Connection to server has been established and initialized, ready to send messages. + * - disconnected: Connection has been closed. + * - connectionError: Some connection error occurred. + * - receivedMessage: Chat message has been received. Data: object {from: 'username', text: 'text'} + */ +class Client extends EventDispatcher { constructor(wsUri) { + super(); + this.wsUri = wsUri; // Create WebSocket and set internal callbacks @@ -16,17 +27,17 @@ class Client { // Internal WebSocket event handlers _onSocketOpen(evt) { console.log("Connected to " + this.wsUri); - - // Send init command containing chat ID and nickname this.sendInit(); } _onSocketClose(evt) { console.log("Connection closed (code " + evt.code + ")."); + this.dispatch("disconnected"); } _onSocketError(evt) { console.error("Connection error: ", evt); + this.dispatch("connectionError"); } _onSocketMessage(evt) { @@ -76,16 +87,19 @@ class Client { const msg = JSON.parse(msgString); switch (msg.type) { - // Response to "init" command + // Response to 'init' command (doesn't have much content, I guess) case "init": - // TODO console.log("Got init response: ", msg); + this.dispatch("initialized"); break; // Incoming chat message case "message": - // TODO - console.log("Got message event: from '" + msg.from + "', text '" + msg.text + "'"); + console.log("Received chat message from '" + msg.from + "', text '" + msg.text + "'"); + this.dispatch("receivedMessage", { + from: msg.from, + text: msg.text, + }); break; // TODO Topic change, user join/leave, error, ... diff --git a/public_html/js/events.js b/public_html/js/events.js new file mode 100644 index 0000000..7662ff7 --- /dev/null +++ b/public_html/js/events.js @@ -0,0 +1,42 @@ +"use strict"; + +/** + * Base class to implement an event system in any class. Events can be dispatched and + * subscribed/unsubscribed. Events can have multiple registered callbacks. + */ +class EventDispatcher { + constructor() { + this._events = {}; + } + + /** + * Dispatch a named event. Calls all callbacks that are subscribed to this event. + */ + dispatch(eventName, data = null) { + if (this._events[eventName]) { + this._events[eventName].forEach((callback) => { + callback(data); + }); + } + } + + /** + * Subscribe to an event. + */ + on(eventName, callback) { + if (!this._events[eventName]) { + this._events[eventName] = []; + } + this._events[eventName].push(callback); + } + + /** + * Unsubscribe from an event. Not sure how to unsubscribe anonymous functions though. + * If callback is not found, nothing happens. + */ + off(eventName, callback) { + if (this._events[eventName]) { + this._events[eventName] = this._events[eventName].filter(item => item !== callback); + } + } +} diff --git a/public_html/js/ui.js b/public_html/js/ui.js index 1afd0d0..5411255 100644 --- a/public_html/js/ui.js +++ b/public_html/js/ui.js @@ -7,4 +7,21 @@ let client; (function() { const wsUri = AppSettings.serverWsUri; client = new Client(wsUri); + + // Test events + client.on("initialized", () => { + console.log("UI: Connection initialized!"); + + // Send a test message + client.sendChatMessage("Meow meow! :3"); + }); + client.on("disconnected", () => { + console.log("UI: Connection closed!"); + }); + client.on("connectionError", () => { + console.log("UI: Connection error! :()"); + }); + client.on("receivedMessage", (msg) => { + console.log("UI: Message from '" + msg.from + "', text: '" + msg.text + "'"); + }); })();