diff options
Diffstat (limited to 'websocket_client.js')
| -rw-r--r-- | websocket_client.js | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/websocket_client.js b/websocket_client.js new file mode 100644 index 0000000..3cfd1c7 --- /dev/null +++ b/websocket_client.js @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info> +// SPDX-License-Identifier: GPL-3.0-or-later +const AUTO_RECONNECT_INTERVAL = 5000; +export class WuiWebSocketClient { + constructor(opts) { + this.opts = opts; + this.requestQueue = []; + this.reconnect_id = 0; + this.isOpen = false; + this.error = ""; + this.address = opts.address; + if (opts.auto_reconnect) { + if (opts.auto_reconnect_interval <= 0) { + opts.auto_reconnect_interval = AUTO_RECONNECT_INTERVAL; + } + } + this.connect(); + } + // + // Send the request and wait for response similar to HTTP + // request-response. + // + async Send(req) { + return new Promise((resolve) => { + const wuiRes = { + code: 0, + message: "", + }; + const reqQueue = { + req: req, + cbSuccess: (res) => { + wuiRes.code = res.code; + wuiRes.message = res.message; + if (res.code === 200 && res.body.length > 0) { + wuiRes.data = JSON.parse(atob(res.body)); + } + resolve(wuiRes); + }, + cbFail: (err) => { + wuiRes.code = 500; + wuiRes.message = err; + resolve(wuiRes); + }, + }; + this.requestQueue.push(reqQueue); + this.conn.send(JSON.stringify(req)); + }); + } + connect() { + this.conn = new WebSocket(this.address); + this.conn.onclose = () => { + this.onClose(); + }; + this.conn.onerror = () => { + this.onError(); + }; + this.conn.onmessage = (ev) => { + this.onMessage(ev); + }; + this.conn.onopen = () => { + this.onOpen(); + }; + } + // onClose handle connection closed by cleaning up the request + // queue. + onClose() { + this.requestQueue.forEach((reqq) => { + reqq.cbFail("connection closed"); + }); + this.isOpen = false; + this.error = "connection is closed by server"; + if (this.opts.auto_reconnect && !this.reconnect_id) { + this.reconnect_id = setInterval(() => { + this.connect(); + }, this.opts.auto_reconnect_interval); + } + if (this.opts.onDisconnected) { + this.opts.onDisconnected(); + } + } + onError() { + if (this.opts.onError) { + this.opts.onError(); + } + } + onMessage(ev) { + const res = JSON.parse(ev.data); + this.requestQueue.forEach((reqq, x) => { + if (reqq.req.id === res.id) { + reqq.cbSuccess(res); + this.requestQueue.splice(x, 1); + return; + } + }); + if (this.opts.onBroadcast && res.id == 0) { + this.opts.onBroadcast(res); + } + } + onOpen() { + this.isOpen = true; + this.error = ""; + if (this.reconnect_id) { + clearInterval(this.reconnect_id); + this.reconnect_id = 0; + } + if (this.opts.onConnected) { + this.opts.onConnected(); + } + } +} |
