Implement react-hooks-sse library
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,8 @@ | |||||||
| .env | .env | ||||||
| .overnodebundle | .overnodebundle | ||||||
| *.old | *.old | ||||||
| node/node_modules | backend/node_modules | ||||||
|  | frontend/node_modules | ||||||
| nginx-react/node_modules | nginx-react/node_modules | ||||||
| nginx-react/build | nginx-react/build | ||||||
| .vscode | .vscode | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ const mongoUri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/default?rep | |||||||
| // Minio set-up variables | // Minio set-up variables | ||||||
| const minioURI = new URL(process.env.MINIO_URI || 'http://kspace-mugshot:2mSI6HdbJ8@127.0.0.1:9000/kspace-mugshot'); | 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 minioBucket = minioURI.pathname.substring(1); | ||||||
| const historyNumber = process.env.HISTORY_AMOUNT || 10; | const historyNumber = parseInt(process.env.HISTORY_AMOUNT) || 1000; | ||||||
|  |  | ||||||
| // Stream set-up variables | // Stream set-up variables | ||||||
| let changeStream; | let changeStream; | ||||||
| @@ -28,16 +28,15 @@ async function run() { | |||||||
|   console.log('server.js has been launched'); |   console.log('server.js has been launched'); | ||||||
|   const app = express(); |   const app = express(); | ||||||
|  |  | ||||||
|   // Configuring mongoDB connection |  | ||||||
|   await mongoClient.connect(); |   await mongoClient.connect(); | ||||||
|   const collection = mongoClient.db().collection(mongoCollection); |   const collection = mongoClient.db().collection(mongoCollection); | ||||||
|  |  | ||||||
|   let eventArray = []; |   let eventArray = []; | ||||||
|  |  | ||||||
|   // Opening event listener on the database |  | ||||||
|   changeStream = collection.watch(pipeline, options); |   changeStream = collection.watch(pipeline, options); | ||||||
|   console.log("Started watching changes in database"); |   console.log("Started watching changes in database"); | ||||||
|  |  | ||||||
|  |   // Triggers on GET at /event route | ||||||
|   app.get('/events', async function (request, response) { |   app.get('/events', async function (request, response) { | ||||||
|     let minioClient = new minio.Client({ |     let minioClient = new minio.Client({ | ||||||
|       endPoint: minioURI.hostname, |       endPoint: minioURI.hostname, | ||||||
| @@ -47,19 +46,24 @@ async function run() { | |||||||
|       secretKey: minioURI.password |       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' }; |     const header = { 'Content-Type': 'text/event-stream', 'Connection': 'keep-alive' }; | ||||||
|     response.writeHead(200, "OK", header); |     response.writeHead(200, "OK", header); | ||||||
|     response.write('Connection established \n\n'); |     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 => { |     changeStream.on("change", data => { | ||||||
|  |  | ||||||
|       // Retrieves modified document on the db and stores it |  | ||||||
|       let document = JSON.stringify(data.fullDocument); |       let document = JSON.stringify(data.fullDocument); | ||||||
|       eventArray = [document]; |       eventArray = [document]; | ||||||
|  |  | ||||||
|       // Fetch screenshot if there is one |  | ||||||
|       if (data.fullDocument.screenshot_count) { |       if (data.fullDocument.screenshot_count) { | ||||||
|  |  | ||||||
|         for (let i = 1; i <= data.fullDocument.screenshot_count ; i++) { |         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`); |       response.write(`data: [${[...eventArray]}]\n\n`); | ||||||
|  |  | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ x-common: &common | |||||||
|   ME_CONFIG_MONGODB_AUTH_DATABASE: admin |   ME_CONFIG_MONGODB_AUTH_DATABASE: admin | ||||||
|   MONGO_URI: mongodb://127.0.0.1:27017/default?replicaSet=rs0 |   MONGO_URI: mongodb://127.0.0.1:27017/default?replicaSet=rs0 | ||||||
|   MONGO_COLLECTION: eventlog |   MONGO_COLLECTION: eventlog | ||||||
|  |   HISTORY_AMOUNT: 10 | ||||||
|   MINIO_ACCESS_KEY: kspace-mugshot |   MINIO_ACCESS_KEY: kspace-mugshot | ||||||
|   MINIO_SECRET_KEY: 2mSI6HdbJ8 |   MINIO_SECRET_KEY: 2mSI6HdbJ8 | ||||||
|   MINIO_DEFAULT_BUCKETS: kspace-mugshot:download |   MINIO_DEFAULT_BUCKETS: kspace-mugshot:download | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -13,6 +13,7 @@ | |||||||
|         "@testing-library/user-event": "^13.5.0", |         "@testing-library/user-event": "^13.5.0", | ||||||
|         "react": "^17.0.2", |         "react": "^17.0.2", | ||||||
|         "react-dom": "^17.0.2", |         "react-dom": "^17.0.2", | ||||||
|  |         "react-hooks-sse": "^2.0.0", | ||||||
|         "react-scripts": "5.0.0", |         "react-scripts": "5.0.0", | ||||||
|         "web-vitals": "^2.1.3" |         "web-vitals": "^2.1.3" | ||||||
|       } |       } | ||||||
| @@ -12952,6 +12953,17 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", |       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", | ||||||
|       "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" |       "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": { |     "node_modules/react-is": { | ||||||
|       "version": "17.0.2", |       "version": "17.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", | ||||||
|       "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" |       "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": { |     "react-is": { | ||||||
|       "version": "17.0.2", |       "version": "17.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", |       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|     "@testing-library/user-event": "^13.5.0", |     "@testing-library/user-event": "^13.5.0", | ||||||
|     "react": "^17.0.2", |     "react": "^17.0.2", | ||||||
|     "react-dom": "^17.0.2", |     "react-dom": "^17.0.2", | ||||||
|  |     "react-hooks-sse": "^2.0.0", | ||||||
|     "react-scripts": "5.0.0", |     "react-scripts": "5.0.0", | ||||||
|     "web-vitals": "^2.1.3" |     "web-vitals": "^2.1.3" | ||||||
|   }, |   }, | ||||||
|   | |||||||
| @@ -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 './App.css'; | ||||||
| import EventList from '../eventList/EventList.js'; | import EventList from '../eventList/EventList.js'; | ||||||
|  |  | ||||||
| function App(props) { | function SSE() { | ||||||
|   const [events, setEvents] = useState(['EventLog']); // initialises Event state |   const state = useSSE('events'); | ||||||
|   const [sse, setSse] = useState(new EventSource('/events', { withCredentials: true })) // creates eventSource listener in state |   const [events, setEvents] = useState([]); // initialises Event state | ||||||
|  |  | ||||||
|   sse.onerror = (e) => { |   useEffect(() => { | ||||||
|     console.error(); |     console.log('render'); | ||||||
|     sse.close(); |     if (state) { | ||||||
|  |       setEvents([JSON.parse(state.data), ...events]); | ||||||
|     } |     } | ||||||
|  |   }, [state]) | ||||||
|  |  | ||||||
|   sse.onmessage = (e) => { |   return events; | ||||||
|     // parses received data from string to JSON | } | ||||||
|     const message = JSON.parse(e.data); |  | ||||||
|  |  | ||||||
|     // initialises a new array with updated server-side event array | function App() { | ||||||
|     const newEvents = [...message, ...events]; |  | ||||||
|  |  | ||||||
|     // sets the updated event array as state |   return ( | ||||||
|     setEvents(newEvents); |   <SSEProvider endpoint="/events"> | ||||||
|   }; |     <SSE/> | ||||||
|  |   </SSEProvider> | ||||||
|   return <EventList data={events} /> |   ) | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,15 +3,13 @@ import Event from '../event/Event.js'; | |||||||
| import './EventList.css'; | import './EventList.css'; | ||||||
|  |  | ||||||
| function EventList(props) { | function EventList(props) { | ||||||
|     console.log(`FROM LIST: ${props.data}`); |     return ; | ||||||
|  |         // <ul className="eventListUl"> | ||||||
|  |         //     {props.data.map((event) => { | ||||||
|  |         //         return <li className="eventListLi"><Event data={event} /></li> | ||||||
|  |         //     })} | ||||||
|  |         // </ul> | ||||||
|      |      | ||||||
|     return ( |  | ||||||
|         <ul className="eventListUl"> |  | ||||||
|             {props.data.map((event) => { |  | ||||||
|                 return <li className="eventListLi"><Event data={event} /></li> |  | ||||||
|             })} |  | ||||||
|         </ul> |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user