From aa38493f03bee4c5bb42c71cfb1293fdad321e93 Mon Sep 17 00:00:00 2001 From: ISA Date: Mon, 9 Sep 2024 15:20:00 +0200 Subject: [PATCH] prepair redux --- hooks/useLineData.js | 4 +++ package-lock.json | 55 ++++++++++++++++++++++++++++++++++-- package.json | 6 +++- pages/_app.js | 10 +++++-- pages/api/websocket.js | 27 ++++++++++++++++++ redux/actions.js | 9 ++++++ redux/reducer.js | 18 ++++++++++++ redux/store.js | 8 ++++++ redux/websocketMiddleware.js | 29 +++++++++++++++++++ 9 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 pages/api/websocket.js create mode 100644 redux/actions.js create mode 100644 redux/reducer.js create mode 100644 redux/store.js create mode 100644 redux/websocketMiddleware.js diff --git a/hooks/useLineData.js b/hooks/useLineData.js index b5c7267d7..e89ca06a7 100644 --- a/hooks/useLineData.js +++ b/hooks/useLineData.js @@ -1,8 +1,12 @@ // /hooks/useLineData.js import { useEffect, useState } from "react"; import { SERVER_URL } from "../config/urls"; +import { useDispatch, useSelector } from "react-redux"; +import { connectWebSocket, disconnectWebSocket } from "../redux/actions"; const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => { + const dispatch = useDispatch(); + const messages = useSelector((state) => state.messages); const [lineColors, setLineColors] = useState({}); const [tooltipContents, setTooltipContents] = useState({}); diff --git a/package-lock.json b/package-lock.json index 2c403330d..691d7655d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,9 +23,13 @@ "postcss": "^8.4.40", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-redux": "^9.1.2", "react-toastify": "^10.0.5", "recoil": "^0.7.7", - "tailwindcss": "^3.4.7" + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "tailwindcss": "^3.4.7", + "ws": "^8.18.0" }, "devDependencies": { "@babel/core": "^7.25.2", @@ -3828,6 +3832,11 @@ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -10580,6 +10589,28 @@ "dev": true, "peer": true }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-toastify": { "version": "10.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", @@ -10673,6 +10704,19 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -11818,6 +11862,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -12152,7 +12204,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 971c1fc6d..90097e17d 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,13 @@ "postcss": "^8.4.40", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-redux": "^9.1.2", "react-toastify": "^10.0.5", "recoil": "^0.7.7", - "tailwindcss": "^3.4.7" + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "tailwindcss": "^3.4.7", + "ws": "^8.18.0" }, "scripts": { "dev": "next dev", diff --git a/pages/_app.js b/pages/_app.js index fc74da978..1a2213940 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,13 +1,17 @@ // Pfad: pages/_app.js import React from "react"; import { RecoilRoot } from "recoil"; +import { Provider } from "react-redux"; +import store from "../redux/store"; import "../styles/global.css"; function MyApp({ Component, pageProps }) { return ( - - - + + + + + ); } diff --git a/pages/api/websocket.js b/pages/api/websocket.js new file mode 100644 index 000000000..20b4c6716 --- /dev/null +++ b/pages/api/websocket.js @@ -0,0 +1,27 @@ +// /pages/api/websocket.js +import { Server } from "ws"; + +export default function handler(req, res) { + if (!res.socket.server.ws) { + console.log("Starting WebSocket server"); + const wss = new Server({ server: res.socket.server }); + + wss.on("connection", (ws) => { + console.log("New WebSocket connection"); + + ws.on("message", (message) => { + console.log("Received:", message); + // Beispielnachricht an den Client senden + ws.send(JSON.stringify({ message: "Hallo von WebSocket-Server" })); + }); + + // Schließe die Verbindung + ws.on("close", () => { + console.log("WebSocket connection closed"); + }); + }); + + res.socket.server.ws = wss; + } + res.end(); +} diff --git a/redux/actions.js b/redux/actions.js new file mode 100644 index 000000000..d147d7d35 --- /dev/null +++ b/redux/actions.js @@ -0,0 +1,9 @@ +// /redux/actions.js +export const connectWebSocket = (url) => ({ + type: "WS_CONNECT", + payload: { url }, +}); + +export const disconnectWebSocket = () => ({ + type: "WS_DISCONNECT", +}); diff --git a/redux/reducer.js b/redux/reducer.js new file mode 100644 index 000000000..008b8d138 --- /dev/null +++ b/redux/reducer.js @@ -0,0 +1,18 @@ +// /redux/reducer.js +const initialState = { + messages: [], +}; + +const websocketReducer = (state = initialState, action) => { + switch (action.type) { + case "WS_MESSAGE_RECEIVED": + return { + ...state, + messages: [...state.messages, action.payload], + }; + default: + return state; + } +}; + +export default websocketReducer; diff --git a/redux/store.js b/redux/store.js new file mode 100644 index 000000000..cf3e43428 --- /dev/null +++ b/redux/store.js @@ -0,0 +1,8 @@ +// /redux/store.js +import { createStore, applyMiddleware } from "redux"; +import websocketMiddleware from "./websocketMiddleware"; +import websocketReducer from "./reducer"; + +const store = createStore(websocketReducer, applyMiddleware(websocketMiddleware)); + +export default store; diff --git a/redux/websocketMiddleware.js b/redux/websocketMiddleware.js new file mode 100644 index 000000000..75c39637d --- /dev/null +++ b/redux/websocketMiddleware.js @@ -0,0 +1,29 @@ +// /redux/websocketMiddleware.js +const websocketMiddleware = () => { + let socket; + + return ({ dispatch }) => + (next) => + (action) => { + if (action.type === "WS_CONNECT") { + socket = new WebSocket(action.payload.url); + + socket.onmessage = (event) => { + const data = JSON.parse(event.data); + dispatch({ type: "WS_MESSAGE_RECEIVED", payload: data }); + }; + + socket.onclose = () => { + dispatch({ type: "WS_DISCONNECTED" }); + }; + } + + if (action.type === "WS_DISCONNECT" && socket) { + socket.close(); + } + + return next(action); + }; +}; + +export default websocketMiddleware;