add SmartWebSocket.js and documentation
This commit is contained in:
parent
af963b4c81
commit
fc082c45e8
39
README.md
39
README.md
|
@ -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);
|
||||
});
|
||||
```
|
|
@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue