From 29772471930521f21f12790620f6f97acb332f43 Mon Sep 17 00:00:00 2001 From: rakbaal Date: Tue, 15 Feb 2022 18:34:10 +0200 Subject: [PATCH] Implement react-hooks-sse library --- .gitignore | 3 +- backend/server.js | 20 ++++++---- docker-compose.yml | 1 + frontend/package-lock.json | 20 ++++++++++ frontend/package.json | 1 + frontend/src/components/app/App.js | 37 ++++++++++--------- .../src/components/eventList/EventList.js | 16 ++++---- 7 files changed, 62 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 2d97410..efe5f74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ .env .overnodebundle *.old -node/node_modules +backend/node_modules +frontend/node_modules nginx-react/node_modules nginx-react/build .vscode diff --git a/backend/server.js b/backend/server.js index 163ad2d..a54f67d 100644 --- a/backend/server.js +++ b/backend/server.js @@ -10,7 +10,7 @@ const mongoUri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/default?rep // Minio set-up variables const minioURI = new URL(process.env.MINIO_URI || 'http://kspace-mugshot:2mSI6HdbJ8@127.0.0.1:9000/kspace-mugshot'); const minioBucket = minioURI.pathname.substring(1); -const historyNumber = process.env.HISTORY_AMOUNT || 10; +const historyNumber = parseInt(process.env.HISTORY_AMOUNT) || 1000; // Stream set-up variables let changeStream; @@ -28,16 +28,15 @@ async function run() { console.log('server.js has been launched'); const app = express(); - // Configuring mongoDB connection await mongoClient.connect(); const collection = mongoClient.db().collection(mongoCollection); let eventArray = []; - // Opening event listener on the database changeStream = collection.watch(pipeline, options); console.log("Started watching changes in database"); + // Triggers on GET at /event route app.get('/events', async function (request, response) { let minioClient = new minio.Client({ endPoint: minioURI.hostname, @@ -47,19 +46,24 @@ async function run() { secretKey: minioURI.password }); - // Setting the header to event-stream for Server Sent Events (Eventsource) + // Notify SSE to React const header = { 'Content-Type': 'text/event-stream', 'Connection': 'keep-alive' }; response.writeHead(200, "OK", header); response.write('Connection established \n\n'); - // Triggers callback on every change in collection set up + const historyCursor = collection.find({}).sort({$natural : -1}).limit(historyNumber); + + historyCursor.forEach((document) => { + const stringFormat = JSON.stringify(document); + eventArray = [stringFormat, ...eventArray]; + }) + response.write(`event: events, data: [${[...eventArray]}]\n\n`) + changeStream.on("change", data => { - // Retrieves modified document on the db and stores it let document = JSON.stringify(data.fullDocument); eventArray = [document]; - // Fetch screenshot if there is one if (data.fullDocument.screenshot_count) { for (let i = 1; i <= data.fullDocument.screenshot_count ; i++) { @@ -72,8 +76,8 @@ async function run() { }; - // sends updated array response.write(`data: [${[...eventArray]}]\n\n`); + }); }); diff --git a/docker-compose.yml b/docker-compose.yml index b04b5e1..9550284 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ x-common: &common ME_CONFIG_MONGODB_AUTH_DATABASE: admin MONGO_URI: mongodb://127.0.0.1:27017/default?replicaSet=rs0 MONGO_COLLECTION: eventlog + HISTORY_AMOUNT: 10 MINIO_ACCESS_KEY: kspace-mugshot MINIO_SECRET_KEY: 2mSI6HdbJ8 MINIO_DEFAULT_BUCKETS: kspace-mugshot:download diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c06e736..54466a6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-hooks-sse": "^2.0.0", "react-scripts": "5.0.0", "web-vitals": "^2.1.3" } @@ -12952,6 +12953,17 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "node_modules/react-hooks-sse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-hooks-sse/-/react-hooks-sse-2.0.0.tgz", + "integrity": "sha512-Bv/KYK+QUVS6UWwCyx6nyaOYIvaTMTCjmlXuBK9nATH2DOz+g4PGiIxi5q71ljUTmSPn/q9Cod7xwDA3/gqVQA==", + "dependencies": { + "@babel/runtime": "^7.1.5" + }, + "peerDependencies": { + "react": ">= 16.7.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -25025,6 +25037,14 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "react-hooks-sse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-hooks-sse/-/react-hooks-sse-2.0.0.tgz", + "integrity": "sha512-Bv/KYK+QUVS6UWwCyx6nyaOYIvaTMTCjmlXuBK9nATH2DOz+g4PGiIxi5q71ljUTmSPn/q9Cod7xwDA3/gqVQA==", + "requires": { + "@babel/runtime": "^7.1.5" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 88949f2..47ccb39 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-hooks-sse": "^2.0.0", "react-scripts": "5.0.0", "web-vitals": "^2.1.3" }, diff --git a/frontend/src/components/app/App.js b/frontend/src/components/app/App.js index 71df5d9..262b070 100644 --- a/frontend/src/components/app/App.js +++ b/frontend/src/components/app/App.js @@ -1,28 +1,29 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; +import { useSSE, SSEProvider, createCustomSource } from 'react-hooks-sse'; import './App.css'; import EventList from '../eventList/EventList.js'; -function App(props) { - const [events, setEvents] = useState(['EventLog']); // initialises Event state - const [sse, setSse] = useState(new EventSource('/events', { withCredentials: true })) // creates eventSource listener in state +function SSE() { + const state = useSSE('events'); + const [events, setEvents] = useState([]); // initialises Event state - sse.onerror = (e) => { - console.error(); - sse.close(); - } + useEffect(() => { + console.log('render'); + if (state) { + setEvents([JSON.parse(state.data), ...events]); + } + }, [state]) - sse.onmessage = (e) => { - // parses received data from string to JSON - const message = JSON.parse(e.data); + return events; +} - // initialises a new array with updated server-side event array - const newEvents = [...message, ...events]; +function App() { - // sets the updated event array as state - setEvents(newEvents); - }; - - return + return ( + + + + ) } diff --git a/frontend/src/components/eventList/EventList.js b/frontend/src/components/eventList/EventList.js index 587fb4c..45370fb 100644 --- a/frontend/src/components/eventList/EventList.js +++ b/frontend/src/components/eventList/EventList.js @@ -3,15 +3,13 @@ import Event from '../event/Event.js'; import './EventList.css'; function EventList(props) { - console.log(`FROM LIST: ${props.data}`); - - return ( - - ) + return ; + // + }