add SmartWebSocket.js and documentation

This commit is contained in:
Luca Conte 2024-08-21 16:57:49 +02:00
parent af963b4c81
commit fc082c45e8
2 changed files with 214 additions and 1 deletions

View File

@ -1 +1,38 @@
# Smart WebSocket # Smart WebSocket
```js
// constructor(socketAddress, options = [], autoReconnect = true, debugName = null)
let socket = SmartWebSocket("ws://127.0.0.1:8080", [], true, "sock");
// close if connection is open, then re-open connection
socket.reconnect()
// close socket and disable auto-reconnect
socket.close()
// is socket connection open
if (socket.isReady()) {
// sends
// {"event" : "myEvent", "data" : { "abc" : "def" }}
// to server
// data is stringified using JSON before sending
socket.send("myEvent", { "abc" : "def"});
// sends
// abcdef
// to server. Same as calling socket.send on a regular WebSocket
socket.sendRaw("abcdef");
}
// is called when a JSON of the kind {"event" : "anotherEvent", "data" : {}} is received
socket.on("anotherEvent", (data) => {
console.log(data);
});
// same as calling socket.addEventListener("open") on a regular WebSocket
// same behaviour applies to events "close", "error" and "message"
socket.on("open", (event) => {
console.log(event);
});
```

176
SmartWebSocket.js Normal file
View File

@ -0,0 +1,176 @@
class SmartWebSocket{
socket;
url;
protocols;
debugName;
autoreconnect;
#events;
#reconnecting;
constructor(url, protocols = [], autoreconnect = true, debugName = null) {
this.url = url;
this.protocols = protocols;
this.autoreconnect = autoreconnect;
this.debugName = debugName;
this.#events = {};
this.#reconnecting = false;
this.#connect();
}
#formatedConsole(method, message, color) {
if (color && typeof message == "string") {
console[method]("%c%s\t | %c%s", "font-weight: bold; color: cyan;", this.debugName ?? this.url, `color: ${color};`, message);
} else {
console[method]("%c%s\t | %c%s", "font-weight: bold; color: cyan;", this.debugName ?? this.url, "", message);
}
}
#log(message, color = null) {
this.#formatedConsole("log", message, color);
}
#error(message) {
this.#formatedConsole("error", message);
}
#warn(message) {
this.#formatedConsole("warn", message);
}
#info(message, color = null) {
this.#formatedConsole("info", message, color);
}
#connect() {
this.#info("Connecting socket...", "yellow");
this.socket = new WebSocket(this.url, this.protocols);
this.socket.addEventListener("open", (eventData) => this.#openHandler(eventData));
this.socket.addEventListener("close", (eventData) => this.#closeHandler(eventData));
this.socket.addEventListener("error", (eventData) => this.#errorHandler(eventData));
this.socket.addEventListener("message", (eventData) => this.#messageHandler(eventData));
}
#eventHandler(event, data = null) {
if (!(event in this.#events)) {
return;
}
for (let i = 0; i < this.#events[event].length; i++) {
this.#events[event][i](data);
}
}
#openHandler(eventData) {
this.#info("Socket connected.", "lime");
this.#reconnecting = false;
this.#eventHandler("open", eventData);
}
#closeHandler(eventData) {
if (eventData.wasClean) {
this.#info("Socket disconnected cleanly.");
} else {
if (!this.#reconnecting) {
this.#warn("Socket disconnected apruptly!");
if (!this.autoreconnect) {
this.#warn("autoreconnect is set to false! Socket will not automatically reconnect in case of an unexpected loss of connection.");
}
}
}
if (this.autoreconnect) {
if (!this.#reconnecting) {
this.#info("Automatically reconnecting.");
this.#reconnecting = true;
}
this.reconnect();
}
this.#eventHandler("close", eventData);
}
#errorHandler(eventData) {
if (!this.#reconnecting) {
this.#error(eventData);
}
this.#eventHandler("error", eventData);
}
#messageHandler(eventData) {
let jsonObj = false;
try {
jsonObj = JSON.parse(eventData.data);
} catch (err) {
this.#warn("received non-JSON data from WebSocket");
jsonObj = false;
}
if (jsonObj && "event" in jsonObj) {
if ("data" in jsonObj) {
this.#eventHandler(jsonObj.event, jsonObj.data);
} else {
this.#eventHandler(jdonObj.event);
}
}
this.#eventHandler("message", eventData);
}
reconnect() {
if (this.socket != undefined && this.socket.readyState < 3) {
if (!this.autoreconnect) {
this.socket.addEventListener("close", () => this.#connect());
}
this.socket.close();
this.#info("Closing socket.", "lime")
} else {
this.#connect();
}
}
close() {
if (this.socket.readyState == 4) {
throw "socket already closed";
}
this.autoreconnect = false;
this.socket.close();
}
isReady() {
return this.socket.readyState == 1;
}
on(event, handler) {
if (typeof event != "string") {
throw "argument event is expected to be of type string";
}
if (typeof handler != "function") {
throw "argument handler is expected to be of type function";
}
if (event in this.#events) {
this.#events[event].push(handler);
} else {
this.#events[event] = [handler];
}
}
send(event, data = null) {
if (typeof event != "string") {
throw "argument event is expected to be of type string";
}
this.socket.send(JSON.stringify({event: event, data: data}));
}
sendRaw(data) {
this.socket.send(data);
}
get events() {
return this.#events;
}
}