Client: Implement event system (#4)

This commit is contained in:
Lexi / Zoe 2019-01-20 21:12:41 +01:00
parent 36ba716ad8
commit ceca822f97
Signed by: binaryDiv
GPG Key ID: F8D4956E224DA232
4 changed files with 81 additions and 7 deletions

View File

@ -12,6 +12,7 @@
<h1>InstantChat</h1>
<script src="js/settings.js"></script>
<script src="js/events.js"></script>
<script src="js/client.js"></script>
<script src="js/ui.js"></script>

View File

@ -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, ...

42
public_html/js/events.js Normal file
View File

@ -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);
}
}
}

View File

@ -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 + "'");
});
})();