diff --git a/package-lock.json b/package-lock.json index 07bd196..f59a412 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", @@ -6372,7 +6379,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" }, @@ -6722,6 +6728,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", @@ -13948,8 +13976,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", @@ -16552,6 +16579,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", @@ -18360,7 +18415,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" @@ -18393,6 +18447,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", @@ -21053,6 +21115,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", @@ -23262,7 +23329,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" } @@ -23522,6 +23588,23 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "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", @@ -28947,8 +29030,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", @@ -30877,6 +30959,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", @@ -32198,7 +32300,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": { @@ -32213,6 +32314,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", diff --git a/package.json b/package.json index 749ae12..2f5e447 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/common/WiFiSettings/ResetWiFiSettings.js b/src/common/WiFiSettings/ResetWiFiSettings.js index 0c227a3..8bbf586 100644 --- a/src/common/WiFiSettings/ResetWiFiSettings.js +++ b/src/common/WiFiSettings/ResetWiFiSettings.js @@ -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); }); diff --git a/src/utils/forisUrls.js b/src/utils/forisUrls.js index 0232d2a..9f6ab73 100644 --- a/src/utils/forisUrls.js +++ b/src/utils/forisUrls.js @@ -1,11 +1,11 @@ /* - * Copyright (C) 2019-2021 CZ.NIC z.s.p.o. (http://www.nic.cz/) + * Copyright (C) 2019-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. */ -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 = { diff --git a/src/webSockets/WebSockets.js b/src/webSockets/WebSockets.js index cdf4fec..51ad889 100644 --- a/src/webSockets/WebSockets.js +++ b/src/webSockets/WebSockets.js @@ -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; diff --git a/src/webSockets/hooks.js b/src/webSockets/hooks.js index c75e0a8..f6a7a04 100644 --- a/src/webSockets/hooks.js +++ b/src/webSockets/hooks.js @@ -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);