Replace socket.io with plain WebSocket

Replace socket.io with plain WebSocket using the ws library as it
doesn't really provide any useful tools over plain WebSocket when it
comes to implementing reliable communication that works across
reconnects.  The widespread browser support for WebSocket also means
it has little value to add for the web interface over WebSocket.
This commit is contained in:
Hornwitser committed 2020-03-22 02:10:54 +01:00
1 parent 808bd6b453
commit 677512512e
12 files changed
+139 -149

No files matched your search

+31 -48
View File
@@ -1,6 +1,6 @@
"use strict";
const events = require("events");
const io = require("socket.io-client");
const WebSocket = require("ws");
const schema = require("lib/schema");
@@ -8,12 +8,11 @@ const schema = require("lib/schema");
/**
* Connector for master server clients
*/
class SocketIOClientConnector extends events.EventEmitter {
constructor(url, token) {
class WebSocketClientConnector extends events.EventEmitter {
constructor(url) {
super();
this._url = url;
this._token = token;
this._seq = 1;
this._state = "new";
@@ -33,7 +32,7 @@ class SocketIOClientConnector extends events.EventEmitter {
* @returns the sequence number of the message sent
*/
send(type, data) {
this._socket.send({ seq: this._seq, type, data });
this._socket.send(JSON.stringify({ seq: this._seq, type, data }));
return this._seq++;
}
@@ -44,7 +43,7 @@ class SocketIOClientConnector extends events.EventEmitter {
*/
close(reason) {
this.send('close', { reason });
this.disconnect();
this._socket.close();
}
/**
@@ -54,19 +53,13 @@ class SocketIOClientConnector extends events.EventEmitter {
this._check(["new"]);
this._state = "handshake";
// Open socket.io connection to master
console.log(`SOCKET | connecting to ${this._url}`)
let url = new URL(this._url);
url.searchParams.append('token', this._token);
url.pathname += "api/socket";
// I really have to question the choice of having the path connected
// to be passed as separate parameter instead of the namespace.
let urlPath = url.pathname + "socket.io";
url.pathname = "";
this._socket = io(url.href, {
path: urlPath,
reconnectionAttempts: 2,
// Open WebSocket to master
console.log(`SOCKET | connecting to ${url}`)
this._socket = new WebSocket(url, {
// For now we do not verify TLS certificates since the default setup is
// to create a self-signed certificate.
rejectUnauthorized: false,
@@ -79,45 +72,35 @@ class SocketIOClientConnector extends events.EventEmitter {
}
_attachSocketHandlers() {
this._socket.on("close", (code, reason) => {
console.log(`SOCKET | Close (code: ${code}, reason: ${reason})`);
});
this._socket.on("error", err => {
console.error("SOCKET | Error:", err);
this._socket.close();
});
this._socket.on("unexpected-response", (req, res) => {
let data = "";
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
console.error(`SOCKET | Unexpeced Response ${res.statusCode}`);
console.error(data);
});
});
/*this._socket.on("connect_error", err => {
console.log("SOCKET | Connect error:", err);
});*/
this._socket.on("connect_timeout", () => {
console.log("SOCKET | Connect timeout");
this._socket.on("open", () => {
console.log("SOCKET | Open");
});
this._socket.on("reconnect", attempt => {
console.log(`SOCKET | Reconnect no. ${attempt} succeeded`);
this._socket.on("ping", data => {
console.log(`SOCKET | Ping (data: ${data}`);
});
this._socket.on("reconnect_attempt", () => {
console.log("SOCKET | Attempting reconnect");
});
this._socket.on("reconnecting", attempt => {
console.log(`SOCKET | Attempting reconnect no. ${attempt}`);
});
/*this._socket.on("reconnect_error", err => {
console.log("SOCKET | Reconnect error:", err);
});*/
this._socket.on("reconnect_failed", () => {
console.log("SOCKET | Reconnecting failed");
});
/*this._socket.on("ping", () => {
console.log("SOCKET | Ping");
});
this._socket.on("pong", (ms) => {
// XXX Latency might be useful
console.log(`SOCKET | Pong latency ${ms}ms`);
});*/
this._socket.on("connect", () => {
console.log("SOCKET | connected");
this._socket.on("pong", data => {
console.log(`SOCKET | Pong (data: ${data}`);
});
// Handle messages
this._socket.on("message", message => {
this._socket.on("message", data => {
let message = JSON.parse(data);
if (this._state === "handshake") {
this._processHandshake(message);
} else if (this._state === "ready") {
@@ -132,7 +115,7 @@ class SocketIOClientConnector extends events.EventEmitter {
* Immediatly close the connection
*/
disconnect() {
this._socket.close();
this._socket.terminate();
}
_processHandshake(message) {
@@ -155,7 +138,7 @@ class SocketIOClientConnector extends events.EventEmitter {
} else if (type === 'close') {
console.log(`SOCKET | received close from server: ${data.reason}`);
this.emit('error', new Error(`server closed during handshake: ${data.reason}`));
this._socket.close();
this._socket.terminate();
}
}
@@ -224,6 +207,6 @@ class VirtualConnector extends events.EventEmitter {
}
module.exports = {
SocketIOClientConnector,
WebSocketClientConnector,
VirtualConnector,
};
-4
View File
@@ -87,10 +87,6 @@ let downloadList = [
url: "https://fonts.googleapis.com/css?family=Roboto",
file: "static/external/css/Roboto.css",
},
{
url: "https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js",
file: "static/external/socket.io.js",
},
]
// initiate folder creations and downloads
+4 -2
View File
@@ -105,8 +105,9 @@ const clientHandshake = ajv.compile({
"type": { const: "register_slave" },
"data": {
additionalProperties: false,
required: ["agent", "version", "name", "id"],
required: ["token", "agent", "version", "name", "id"],
properties: {
"token": { type: "string" },
"agent": { type: "string" },
"version": { type: "string" },
"name": { type: "string" },
@@ -120,8 +121,9 @@ const clientHandshake = ajv.compile({
"type": { const: "register_control" },
"data": {
additionalProperties: false,
required: ["agent", "version"],
required: ["token", "agent", "version"],
properties: {
"token": { type: "string" },
"agent": { type: "string" },
"version": { type: "string" },
}