1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2024-12-26 00:21:36 +01:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Štěpán Henek
6d70eef2fb Merge branch 'feature/ws-included' into 'dev'
Using socket.io for websocket handling and make reforis configurable

See merge request turris/reforis/foris-js!201
2024-09-27 22:44:39 +02:00
Aleksandr Gumroian
cc1389536e
Fix tests 2024-09-05 13:02:14 +02:00
Aleksandr Gumroian
499be46588
Using socket.io for websocket handling and make reforis configurable
Socket.io wrapper is used to handle websockets now,
this means that websocket logic had to be redone.

Also it is necessary to set `REFORIS_PREFIX` env variable
during the build process. To set the path of backend url.
It was previously fixed to `/reforis`.
2024-09-05 13:02:13 +02:00
8 changed files with 145 additions and 77 deletions

124
package-lock.json generated
View File

@ -18,7 +18,8 @@
"moment": "^2.30.1",
"qrcode.react": "^3.1.0",
"react-datetime": "^3.2.0",
"react-uid": "^2.3.3"
"react-uid": "^2.3.3",
"socket.io-client": "^4.6.1"
},
"devDependencies": {
"@babel/cli": "^7.24.7",
@ -3583,6 +3584,12 @@
"@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@testing-library/dom": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.1.tgz",
@ -6377,7 +6384,6 @@
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
@ -6731,6 +6737,28 @@
"node": ">= 0.8"
}
},
"node_modules/engine.io-client": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
@ -13972,8 +14000,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/multicast-dns": {
"version": "7.2.5",
@ -16597,6 +16624,34 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"dev": true
},
"node_modules/socket.io-client": {
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -18409,7 +18464,6 @@
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@ -18442,6 +18496,14 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@ -21102,6 +21164,11 @@
"@sinonjs/commons": "^3.0.0"
}
},
"@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
},
"@testing-library/dom": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.1.tgz",
@ -23311,7 +23378,6 @@
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
@ -23571,6 +23637,23 @@
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true
},
"engine.io-client": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
},
"enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
@ -28996,8 +29079,7 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"multicast-dns": {
"version": "7.2.5",
@ -30932,6 +31014,26 @@
}
}
},
"socket.io-client": {
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
}
},
"socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
}
},
"sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -32253,7 +32355,6 @@
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"requires": {}
},
"xml-name-validator": {
@ -32268,6 +32369,11 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@ -23,7 +23,8 @@
"moment": "^2.30.1",
"qrcode.react": "^3.1.0",
"react-datetime": "^3.2.0",
"react-uid": "^2.3.3"
"react-uid": "^2.3.3",
"socket.io-client": "^4.6.1"
},
"peerDependencies": {
"bootstrap": "^5.3.3",

View File

@ -26,7 +26,7 @@ function ResetWiFiSettings({ ws, endpoint }) {
useEffect(() => {
const module = "wifi";
ws.subscribe(module).bind(module, "reset", () => {
ws.bind(module, "reset", () => {
// eslint-disable-next-line no-restricted-globals
setTimeout(() => location.reload(), 1000);
});

View File

@ -46,7 +46,7 @@ describe("<RebootButton/>", () => {
fireEvent.click(getByText(componentContainer, "Reboot"));
fireEvent.click(getByText(componentContainer, "Confirm reboot"));
expect(mockAxios.post).toHaveBeenCalledWith(
"/reforis/api/reboot",
"/api/reboot",
undefined,
expect.anything()
);

View File

@ -10,3 +10,4 @@ global._ = (str) => str;
global.ngettext = (str) => str;
global.babel = { format: (str) => str };
global.ForisTranslations = { locale: "en" };
global.setImmediate = (fn) => setTimeout(fn, 0);

View File

@ -5,7 +5,7 @@
* See /LICENSE for more information.
*/
export const REFORIS_URL_PREFIX = "/reforis";
export const REFORIS_URL_PREFIX = process.env.REFORIS_PREFIX || "";
export const REFORIS_API_URL_PREFIX = `${REFORIS_URL_PREFIX}/api`;
export const ForisURLs = {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2022 CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright (C) 2020-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
*
* This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information.
@ -7,47 +7,33 @@
/* eslint no-console: "off" */
const PROTOCOL = window.location.protocol === "http:" ? "ws" : "wss";
import { io } from "socket.io-client";
const URL = process.env.LIGHTTPD
? `${PROTOCOL}://${window.location.host}/${process.env.WSPATH || "foris-ws"}`
: `${PROTOCOL}://${window.location.hostname}:9081`;
const WAITING_FOR_CONNECTION_TIMEOUT = 500;
import { REFORIS_URL_PREFIX } from "../utils/forisUrls";
class WebSockets {
constructor() {
this.ws = new WebSocket(URL);
this.ws.onerror = (e) => {
console.error("WS: Error:", e);
};
this.ws.onmessage = (e) => {
console.debug(`WS: Received Message: ${e.data}`);
const data = JSON.parse(e.data);
this.dispatch(data);
};
this.ws.onopen = () => {
console.debug("WS: Connection open.");
};
this.ws.onclose = () => {
console.debug("WS: Connection closed.");
};
this.socket = io("/notifications", {
path: `${REFORIS_URL_PREFIX}/reforis-ws`,
});
this.connection = null;
this.socket.on("disconnect", (reason) => {
this.connection = null;
console.debug(`SocketIO disconnected (${reason})`);
});
this.socket.on("notification", (message) => {
console.debug("WS: Received Message:", message);
this.dispatch(message);
});
this.socket.on("connect", (connection) => {
this.connection = connection;
console.debug(`SocketIO connected.`);
});
// callbacks[module][action]
this.callbacks = {};
}
waitForConnection(callback) {
if (this.ws.readyState === 1) {
callback();
} else {
const that = this;
setTimeout(() => {
that.waitForConnection(callback);
}, WAITING_FOR_CONNECTION_TIMEOUT);
}
}
bind(module, action, callback) {
this.callbacks[module] = this.callbacks[module] || {};
this.callbacks[module][action] = this.callbacks[module][action] || [];
@ -55,13 +41,6 @@ class WebSockets {
return this;
}
subscribe(module) {
this.waitForConnection(() => {
this.send("subscribe", module);
});
return this;
}
unbind(module, action, callback) {
const callbacks = this.callbacks[module][action];
@ -75,28 +54,12 @@ class WebSockets {
}
if (Object.keys(this.callbacks[module]).length === 0) {
this.unsubscribe(module);
delete this.callbacks[module];
}
return this;
}
unsubscribe(module) {
this.waitForConnection(() => {
this.send("unsubscribe", module);
delete this.callbacks[module];
});
return this;
}
send(action, params) {
const payload = JSON.stringify({ action, params });
this.waitForConnection(() => {
this.ws.send(payload);
});
return this;
}
dispatch(json) {
if (!json.module) return;
@ -105,20 +68,17 @@ class WebSockets {
chain = this.callbacks[json.module][json.action];
} catch (error) {
if (error instanceof TypeError) {
console.warn(
`Callback for this message wasn't found:${error.data}`
console.debug(
`Callbacks for this module wasn't found: ${json.module}`
);
} else throw error;
}
if (typeof chain === "undefined") return;
console.debug("Handling WS message", json);
chain.forEach((callback) => callback(json));
}
close() {
this.ws.close();
}
}
export default WebSockets;

View File

@ -33,7 +33,7 @@ function useWSForisModule(
setData(message.data);
}
ws.subscribe(module).bind(module, action, callback);
ws.bind(module, action, callback);
return () => {
ws.unbind(module, action, callback);