This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
SmartWebSocket/SmartWebSocket.js

176 lines
4.0 KiB
JavaScript

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 |", "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(jsonObj.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;
}
}