From d9fe49de318659ab5dd6ed149ed19aee6e40864b Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Fri, 19 Nov 2021 17:29:21 +0100 Subject: [PATCH 01/17] answererd Q1 Added connectionDelay to demonstrate Q2 Added reverse functionality --- vehicle-data-generator/index.js | 42 ++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/vehicle-data-generator/index.js b/vehicle-data-generator/index.js index 97db849..eb63e25 100644 --- a/vehicle-data-generator/index.js +++ b/vehicle-data-generator/index.js @@ -32,7 +32,15 @@ const readOutLoud = (vehicleName) => { // What's the difference betweeen fs.createReadStream, fs.readFileSync, and fs.readFileAsync? // And when to use one or the others // ========================= - + // Answer: + // fs.createReadStream will process data in chunks of a set size. + // This keeps the memory load smaller. Since it deals with data in small chunks you can start processing the data early. + // Freeing up memory for a readStream is more complex (for the system, that is). + // fs.readFileAsync will asynchronously add the entire file to memory. + // fs.readFileSync will synchronously add the entire file to memory, and thus will block the eventloop. This is less ideal for larger files. + // fs.readFileSync and fs.readFileAsync will put the entire file in memory. This makes it easy for Node to remove them from memory, but it will also take a lot of memory. + // Because fs.createReadStream works with smaller chunks of data your data will most likely be available for use quicker. + // fs.createReadStream is best used with more frequent requests and larger files. fs.readFile // Now comes the interesting part, // Handling this filestream requires us to create pipeline that will transform the raw string // to object and sent out to nats @@ -53,8 +61,8 @@ const readOutLoud = (vehicleName) => { // setTimeout in this case is there to emulate real life situation // data that came out of the vehicle came in with irregular interval // Hence the Math.random() on the second parameter + const connectionDelay = Math.ceil(Math.random()*10) setTimeout(() => { - i++ if((i % 100) === 0) console.log(`vehicle ${vehicleName} sent have sent ${i} messages`) @@ -63,8 +71,9 @@ const readOutLoud = (vehicleName) => { // it also includes the vehicle name to seggregate data between different vehicle nats.publish(`vehicle.${vehicleName}`, obj, cb) - - }, Math.ceil(Math.random() * 150)) + obj.vehicleName = vehicleName; + routeArray.push(obj) + }, Math.ceil(Math.random() * 150) * connectionDelay) } }))) // ========================= @@ -72,12 +81,33 @@ const readOutLoud = (vehicleName) => { // What would happend if it failed to publish to nats or connection to nats is slow? // Maybe you can try to emulate those slow connection // ========================= + // } // This next few lines simulate Henk's (our favorite driver) shift console.log("Henk checks in on test-bus-1 starting his shift...") readOutLoud("test-bus-1") .once("finish", () => { - console.log("henk is on the last stop and he is taking a cigarrete while waiting for his next trip") + console.log("Henk is on the last stop and he is taking a cigarrete while waiting for his next trip") + console.log("Henk is ready to go again!") + if(routeArray.length){ + const reversedRoute = routeArray.reverse() + readReverse(reversedRoute) + } }) -// To make your presentation interesting maybe you can make henk drive again in reverse \ No newline at end of file +// To make your presentation interesting maybe you can make henk drive again in reverse +let routeArray = [] +const readReverse = (array) =>{ + const publishRouteInfo = (i)=>{ + const data = array[i] + setTimeout( + function(){ + nats.publish(`vehicle.${data.vehicleName}`, data) + if((i % 100) === 0) + console.log(`vehicle ${data.vehicleName} sent have sent ${i} reversed messages`) + }, (i*100) + Math.ceil(Math.random() * 150)) + } + for (let i = 1; i < array.length; i++) { + publishRouteInfo(i) + } +} \ No newline at end of file From 6e652888cfd146a6baf39c0a388260f8edd9a23d Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Fri, 19 Nov 2021 17:29:42 +0100 Subject: [PATCH 02/17] added packages for database, routing, sockets and NATS --- package.json | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index a8ac472..461bff1 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,21 @@ { - "name": "nodejs-assignment", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start-nats": "sh ./start-nats", - "start-broadcast": "node vehicle-data-generator/index.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "csv-parse": "^3.2.0", - "nats": "^1.0.1" - } + "name": "nodejs-assignment", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start-nats": "sh ./start-nats", + "start-broadcast": "node vehicle-data-generator/index.js", + "connect-db": "node mongoServer/server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "csv-parse": "^3.2.0", + "ejs": "^3.1.6", + "express": "^4.17.1", + "mongoose": "^6.0.13", + "nats": "^1.0.1", + "socket.io": "^4.3.2" + } } From 912281ed1a1139a3a8895c511627efdc66d12cb3 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Fri, 19 Nov 2021 17:30:00 +0100 Subject: [PATCH 03/17] init commit of db server and routing --- mongoServer/server.js | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 mongoServer/server.js diff --git a/mongoServer/server.js b/mongoServer/server.js new file mode 100644 index 0000000..9cb9899 --- /dev/null +++ b/mongoServer/server.js @@ -0,0 +1,72 @@ +// Database logic +const mongoose = require('mongoose') +const RouteInformationEntry = require('./dbModels/routeInformationModel.js') +const IncidentEntry = require('./dbModels/incidentModel.js') +const dbLocation = "mongodb://localhost/viricitiTech" +/* Note: +In production app we would hide locations like these and portinformation in enviroment variables stored in seperate files. +The elements of the server: Database logic, socket logic, routing logic and NATS logic would also be seperated. +*/ +mongoose.connect(dbLocation, async (err,res)=>{ + if(err){ + throw(err) + }else{ + console.log('Succesfully connected to database') + // Clean up collection if it gets too big + const routeInformationCount = await RouteInformationEntry.count() + if(routeInformationCount > 40000){ + RouteInformationEntry.collection.drop() + IncidentEntry.collection.drop() + console.log('Emptied the RouteInformation and Incident Collection') + } + } +}) + + +// REST Logic +const express = require('express') +const app = express() +app.set("view engine", "ejs"); +const http = require('http').createServer(app) +const port = 2021 +http.listen(port, ()=>{ + console.log(`Listening on *:${port}`); +}); + +app.get("/", async(req,res)=>{ + res.render('../mongoServer/views/routeInformation.ejs') +}) +app.get("/incidents", async(req,res)=>{ + const incidents = await IncidentEntry.find() + res.render('../mongoServer/views/incidents.ejs', {incidents : incidents}) +}) +// Websocket Logic +const io = require('socket.io')(http); +io.on('connection', (socket) => { + let date = new Date (socket.handshake.time) + console.log(`Connection to socket made at ${date} with ${socket.handshake.headers["x-real-ip"]}. ${io.engine.clientsCount} open connection(s).`) + socket.emit('connectedToServer', true) +}) + +// Recieving and dealing with incoming data +const NATS = require('nats') +const nats = NATS.connect({json : true}) + +const listenForVehicleData = (vehicleName) => { + nats.subscribe(`vehicle.${vehicleName}`, async (data)=>{ + data.vehicleName = vehicleName + try{ + let addNewEntry = await RouteInformationEntry.create(data) + io.emit('vehicleMessage', data) + }catch(err){ + incidentHandling(err) + } + }) + } + +const incidentHandling = (data) =>{ + data.error = true + io.emit('vehicleError', data) + IncidentEntry.create({data : data}) +} +listenForVehicleData('test-bus-1') \ No newline at end of file From 8ef94a7a000ae329db4d4ae7f261089bc47d72c9 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Fri, 19 Nov 2021 17:30:06 +0100 Subject: [PATCH 04/17] init commit --- mongoServer/dbModels/incidentModel.js | 8 ++++++++ mongoServer/dbModels/routeInformationModel.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 mongoServer/dbModels/incidentModel.js create mode 100644 mongoServer/dbModels/routeInformationModel.js diff --git a/mongoServer/dbModels/incidentModel.js b/mongoServer/dbModels/incidentModel.js new file mode 100644 index 0000000..0cebe18 --- /dev/null +++ b/mongoServer/dbModels/incidentModel.js @@ -0,0 +1,8 @@ +const mongoose = require("mongoose"); +const incidentEntry = new mongoose.Schema({ + data : {} + } +,{timestamps : true}); +const IncidentEntry = mongoose.model("Incident", incidentEntry); + +module.exports = IncidentEntry; \ No newline at end of file diff --git a/mongoServer/dbModels/routeInformationModel.js b/mongoServer/dbModels/routeInformationModel.js new file mode 100644 index 0000000..57e7dcb --- /dev/null +++ b/mongoServer/dbModels/routeInformationModel.js @@ -0,0 +1,15 @@ +const mongoose = require("mongoose"); +const routeInformationEntry = new mongoose.Schema({ + time: {type : Date, required: true}, + energy: {type : mongoose.Decimal128, required : true}, + gps: {type : [String], required : true}, + odo: {type : mongoose.Decimal128, required : true}, + speed: {type : Number, required : true}, + soc: {type : mongoose.Decimal128, required : true}, + vehicleName : {type : String, required : true}, + error : {} + } +,{timestamps : true}); +const RouteInformationEntry = mongoose.model("RouteInformation", routeInformationEntry); + +module.exports = RouteInformationEntry; \ No newline at end of file From 063b563bedea3e5c9734783a7a9cc18b2e08309e Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Fri, 19 Nov 2021 17:30:12 +0100 Subject: [PATCH 05/17] init commit --- mongoServer/views/incidents.ejs | 110 +++++++++++++++++++++++ mongoServer/views/routeInformation.ejs | 117 +++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 mongoServer/views/incidents.ejs create mode 100644 mongoServer/views/routeInformation.ejs diff --git a/mongoServer/views/incidents.ejs b/mongoServer/views/incidents.ejs new file mode 100644 index 0000000..f259dc9 --- /dev/null +++ b/mongoServer/views/incidents.ejs @@ -0,0 +1,110 @@ + + + + + + + + Incident Report - Viriciti Tech Assesment Robbert-Jan Sebregts + + + + + +
+
+
Incident Report
+ +
*New Incident
+
+ + + + + + + + + + + + + + <%if(incidents){ + incidents.forEach((incident,index) =>{%> + + + + + + + + + + <%})}%> + +
🕑 Time🚌 Vehicle Name🔌 Energy Usage🌎 GPS📏 Distance🏁 Speed🔋 Soc
+ <% + const date = new Date(incident.data.time) + const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + %> + <%=dateString%> + + <%=incident.data.vehicleName%> + + <%=incident.data.energy%> + + <%=incident.data.gps%> + + <%=incident.data.odo%> + + <%=incident.data.speed%> + + <%=incident.data.soc%> +
+
+ + + + + + + + + \ No newline at end of file diff --git a/mongoServer/views/routeInformation.ejs b/mongoServer/views/routeInformation.ejs new file mode 100644 index 0000000..1c7aece --- /dev/null +++ b/mongoServer/views/routeInformation.ejs @@ -0,0 +1,117 @@ + + + + + + + + Route Information - Viriciti Tech Assesment Robbert-Jan Sebregts + + + + + +
+
+
+
Latest Route Information
+ + +
+
+
+
+ +
+ + + + + + + + + + + + + +
🕑 Time🔌 Energy Usage🌎 GPS📏 Distance🏁 Speed🔋 Soc
+
+
+ +
+ + + + + + + + \ No newline at end of file From c60d72cd94dfd9ca1b88b6b96071d0101476441d Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:34:47 +0100 Subject: [PATCH 06/17] added incidint lookup --- mongoServer/server.js | 68 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/mongoServer/server.js b/mongoServer/server.js index 9cb9899..f2ebff6 100644 --- a/mongoServer/server.js +++ b/mongoServer/server.js @@ -14,7 +14,7 @@ mongoose.connect(dbLocation, async (err,res)=>{ console.log('Succesfully connected to database') // Clean up collection if it gets too big const routeInformationCount = await RouteInformationEntry.count() - if(routeInformationCount > 40000){ + if(routeInformationCount > 3000){ RouteInformationEntry.collection.drop() IncidentEntry.collection.drop() console.log('Emptied the RouteInformation and Incident Collection') @@ -26,13 +26,14 @@ mongoose.connect(dbLocation, async (err,res)=>{ // REST Logic const express = require('express') const app = express() +app.use(express.json()); +app.use(express.urlencoded({extended:true})); app.set("view engine", "ejs"); const http = require('http').createServer(app) const port = 2021 http.listen(port, ()=>{ console.log(`Listening on *:${port}`); }); - app.get("/", async(req,res)=>{ res.render('../mongoServer/views/routeInformation.ejs') }) @@ -40,6 +41,22 @@ app.get("/incidents", async(req,res)=>{ const incidents = await IncidentEntry.find() res.render('../mongoServer/views/incidents.ejs', {incidents : incidents}) }) +app.get("/incidentLookup", async (req,res)=>{ + res.render('../mongoServer/views/incidentLookup.ejs', {incidents : null}) +}) +app.post("/findIncidents", async (req,res)=>{ + const dbFilter = getRouteFilter(req.body, true) + const foundIncidents = await IncidentEntry.find(dbFilter).catch((err)=>{console.log(err)}) + res.render('../mongoServer/views/incidents.ejs', {incidents : foundIncidents}) +}) +app.get("/routeInformationLookup", async (req,res)=>{ + res.render('../mongoServer/views/routeInformationLookup.ejs', {routeEntries : null}) +}) +app.post("/findRouteEntries", async (req,res)=>{ + const dbFilter = getRouteFilter(req.body) + const foundRouteInformation = await RouteInformationEntry.find(dbFilter).catch((err)=>{console.log(err)}) + res.render('../mongoServer/views/viewRouteInformation.ejs', {routeEntries : foundRouteInformation}) +}) // Websocket Logic const io = require('socket.io')(http); io.on('connection', (socket) => { @@ -48,7 +65,7 @@ io.on('connection', (socket) => { socket.emit('connectedToServer', true) }) -// Recieving and dealing with incoming data +// Recieving and dealing with incoming data from NATS const NATS = require('nats') const nats = NATS.connect({json : true}) @@ -59,14 +76,47 @@ const listenForVehicleData = (vehicleName) => { let addNewEntry = await RouteInformationEntry.create(data) io.emit('vehicleMessage', data) }catch(err){ - incidentHandling(err) + incidentHandling(err, data) } }) - } +} -const incidentHandling = (data) =>{ +const incidentHandling = (data, dataEntered) =>{ data.error = true - io.emit('vehicleError', data) - IncidentEntry.create({data : data}) + io.emit('vehicleError', dataEntered) + IncidentEntry.create({data : dataEntered}) +} +const getRouteFilter = (routeCriteria, lookForIncident)=>{ + let queryKeys = Object.keys(routeCriteria) + let dbFilter = {} + if(routeCriteria.time[0] !== 'ignore'){ + let newDate = new Date(routeCriteria.time[1]) + routeCriteria.time[1] = newDate.getTime() + } + queryKeys.forEach(key=>{ + let queryItem = routeCriteria[key] + let dbKey = key + if(lookForIncident){ + dbKey = `data.${key}` + } + if(queryItem[2]){ + dbFilter[`data.${key}`] = {$eq : ''} + }else if(queryItem[0] === 'ignore'){ + return + }else if(queryItem[0]=== 'gt'){ + dbFilter[dbKey] = {$gt : parseFloat(queryItem[1])} + }else if(queryItem[0]=== 'lt'){ + dbFilter[dbKey] = {$lt : parseFloat(queryItem[1])} + }else if(queryItem[0]=== '=='){ + dbFilter[dbKey] = {$eq : parseFloat(queryItem[1])} + } + }) + return dbFilter } -listenForVehicleData('test-bus-1') \ No newline at end of file + +// +// ================================= +// + +listenForVehicleData('test-bus-1') + From 7eeec7510d002bcd3e5bb0cd4bfbd6039fc57ee7 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:34:57 +0100 Subject: [PATCH 07/17] init commit --- mongoServer/views/incidentLookup.ejs | 176 +++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 mongoServer/views/incidentLookup.ejs diff --git a/mongoServer/views/incidentLookup.ejs b/mongoServer/views/incidentLookup.ejs new file mode 100644 index 0000000..4a8b249 --- /dev/null +++ b/mongoServer/views/incidentLookup.ejs @@ -0,0 +1,176 @@ + + + + + + + + Incident Report - Viriciti Tech Assesment Robbert-Jan Sebregts + + + + + +
+ +
+
+ Find Incidents +
+
+
+ + + + +
+ +
+
+
+ + + + +
+ +
+
+
+ + + + +
+ +
+
+
+ + + + +
+ +
+
+
+ + + + +
+ +
+
+ +
+
+ + <%if(incidents){%> + + + + + + + + + + + + + + <%if(incidents){ + incidents.forEach((incident,index) =>{%> + + + + + + + + + + <%})}%> + +
🕑 Time🚌 Vehicle Name🔌 Energy Usage🌎 GPS📏 Distance🏁 Speed🔋 Soc
+ <% + const date = new Date(incident.data.time) + const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + %> + <%=dateString%> + + <%=incident.data.vehicleName%> + + <%=incident.data.energy%> + + <%=incident.data.gps%> + + <%=incident.data.odo%> + + <%=incident.data.speed%> + + <%=incident.data.soc%> +
+ <%}%> + +
+ + + + + + + + \ No newline at end of file From f4f45719471e4d5ca6b59b5ba9eef7bf96c00b42 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:35:14 +0100 Subject: [PATCH 08/17] updated date, months are +1 because of indexing --- mongoServer/views/incidents.ejs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mongoServer/views/incidents.ejs b/mongoServer/views/incidents.ejs index f259dc9..0c9c9ad 100644 --- a/mongoServer/views/incidents.ejs +++ b/mongoServer/views/incidents.ejs @@ -36,13 +36,13 @@ - <%if(incidents){ + <%if(incidents && incidents.length){ incidents.forEach((incident,index) =>{%> <% const date = new Date(incident.data.time) - const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + const dateString = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` %> <%=dateString%> @@ -96,7 +96,7 @@ break; case 'time': const date = new Date(data[key]) - const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + const dateString = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` newCell.textContent = dateString; break; default: From ba204b4936875245125818d4d124944c3f09bce0 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:35:23 +0100 Subject: [PATCH 09/17] updated links --- mongoServer/views/routeInformation.ejs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mongoServer/views/routeInformation.ejs b/mongoServer/views/routeInformation.ejs index 1c7aece..fb81a17 100644 --- a/mongoServer/views/routeInformation.ejs +++ b/mongoServer/views/routeInformation.ejs @@ -21,7 +21,12 @@ From 78ca71b4c3ee82b9637c12312415bd3901ce929d Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:35:30 +0100 Subject: [PATCH 10/17] init commit --- mongoServer/views/routeInformationLookup.ejs | 110 +++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 mongoServer/views/routeInformationLookup.ejs diff --git a/mongoServer/views/routeInformationLookup.ejs b/mongoServer/views/routeInformationLookup.ejs new file mode 100644 index 0000000..65031da --- /dev/null +++ b/mongoServer/views/routeInformationLookup.ejs @@ -0,0 +1,110 @@ + + + + + + + + Incident Report - Viriciti Tech Assesment Robbert-Jan Sebregts + + + + + +
+ +
+
+ Find Route Information +
+
+
+ + + +
+
+ + + + +
+
+ + + + +
+
+ + + +
+
+ + + +
+ +
+
+ +
+ + + + + + + + \ No newline at end of file From 7a185996e0053312ef95684f8a2493643661b281 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 14:35:35 +0100 Subject: [PATCH 11/17] init commit --- mongoServer/views/viewRouteInformation.ejs | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 mongoServer/views/viewRouteInformation.ejs diff --git a/mongoServer/views/viewRouteInformation.ejs b/mongoServer/views/viewRouteInformation.ejs new file mode 100644 index 0000000..d410dad --- /dev/null +++ b/mongoServer/views/viewRouteInformation.ejs @@ -0,0 +1,88 @@ + + + + + + + + Route Information - Viriciti Tech Assesment Robbert-Jan Sebregts + + + + + +
+
+
+
You asked for this Route Information
+
We found + <%=routeEntries.length%> entries
+ + +
+
+
+
+ +
+ + + + + + + + + + + + + + <%if(routeEntries && routeEntries.length){ + routeEntries.forEach((route,index) =>{%> + + + + + + + + + + <%})}%> + +
🕑 Time🚌 Vehicle Name🔌 Energy Usage🌎 GPS📏 Distance🏁 Speed🔋 Soc
+ <% + const date = new Date(route.time) + const dateString = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + %> + <%=dateString%> + + <%=route.vehicleName%> + + <%=route.energy%> + + <%=route.gps%> + + <%=route.odo%> + + <%=route.speed%> + + <%=route.soc%> +
+
+
+ +
+ + + + \ No newline at end of file From fba793763a02a6640001c9c14bd7603e63e3a800 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 15:14:51 +0100 Subject: [PATCH 12/17] moved mongoServer to app folder --- {mongoServer => app}/dbModels/incidentModel.js | 0 .../dbModels/routeInformationModel.js | 0 {mongoServer => app}/server.js | 13 +++++++------ {mongoServer => app}/views/incidentLookup.ejs | 0 {mongoServer => app}/views/incidents.ejs | 0 {mongoServer => app}/views/routeInformation.ejs | 0 .../views/routeInformationLookup.ejs | 0 {mongoServer => app}/views/viewRouteInformation.ejs | 0 8 files changed, 7 insertions(+), 6 deletions(-) rename {mongoServer => app}/dbModels/incidentModel.js (100%) rename {mongoServer => app}/dbModels/routeInformationModel.js (100%) rename {mongoServer => app}/server.js (86%) rename {mongoServer => app}/views/incidentLookup.ejs (100%) rename {mongoServer => app}/views/incidents.ejs (100%) rename {mongoServer => app}/views/routeInformation.ejs (100%) rename {mongoServer => app}/views/routeInformationLookup.ejs (100%) rename {mongoServer => app}/views/viewRouteInformation.ejs (100%) diff --git a/mongoServer/dbModels/incidentModel.js b/app/dbModels/incidentModel.js similarity index 100% rename from mongoServer/dbModels/incidentModel.js rename to app/dbModels/incidentModel.js diff --git a/mongoServer/dbModels/routeInformationModel.js b/app/dbModels/routeInformationModel.js similarity index 100% rename from mongoServer/dbModels/routeInformationModel.js rename to app/dbModels/routeInformationModel.js diff --git a/mongoServer/server.js b/app/server.js similarity index 86% rename from mongoServer/server.js rename to app/server.js index f2ebff6..1599e07 100644 --- a/mongoServer/server.js +++ b/app/server.js @@ -35,27 +35,27 @@ http.listen(port, ()=>{ console.log(`Listening on *:${port}`); }); app.get("/", async(req,res)=>{ - res.render('../mongoServer/views/routeInformation.ejs') + res.render('../app/views/routeInformation.ejs') }) app.get("/incidents", async(req,res)=>{ const incidents = await IncidentEntry.find() - res.render('../mongoServer/views/incidents.ejs', {incidents : incidents}) + res.render('../app/views/incidents.ejs', {incidents : incidents}) }) app.get("/incidentLookup", async (req,res)=>{ - res.render('../mongoServer/views/incidentLookup.ejs', {incidents : null}) + res.render('../app/views/incidentLookup.ejs', {incidents : null}) }) app.post("/findIncidents", async (req,res)=>{ const dbFilter = getRouteFilter(req.body, true) const foundIncidents = await IncidentEntry.find(dbFilter).catch((err)=>{console.log(err)}) - res.render('../mongoServer/views/incidents.ejs', {incidents : foundIncidents}) + res.render('../app/views/incidents.ejs', {incidents : foundIncidents}) }) app.get("/routeInformationLookup", async (req,res)=>{ - res.render('../mongoServer/views/routeInformationLookup.ejs', {routeEntries : null}) + res.render('../app/views/routeInformationLookup.ejs', {routeEntries : null}) }) app.post("/findRouteEntries", async (req,res)=>{ const dbFilter = getRouteFilter(req.body) const foundRouteInformation = await RouteInformationEntry.find(dbFilter).catch((err)=>{console.log(err)}) - res.render('../mongoServer/views/viewRouteInformation.ejs', {routeEntries : foundRouteInformation}) + res.render('../app/views/viewRouteInformation.ejs', {routeEntries : foundRouteInformation}) }) // Websocket Logic const io = require('socket.io')(http); @@ -120,3 +120,4 @@ const getRouteFilter = (routeCriteria, lookForIncident)=>{ listenForVehicleData('test-bus-1') +module.exports = app.listen(2022) \ No newline at end of file diff --git a/mongoServer/views/incidentLookup.ejs b/app/views/incidentLookup.ejs similarity index 100% rename from mongoServer/views/incidentLookup.ejs rename to app/views/incidentLookup.ejs diff --git a/mongoServer/views/incidents.ejs b/app/views/incidents.ejs similarity index 100% rename from mongoServer/views/incidents.ejs rename to app/views/incidents.ejs diff --git a/mongoServer/views/routeInformation.ejs b/app/views/routeInformation.ejs similarity index 100% rename from mongoServer/views/routeInformation.ejs rename to app/views/routeInformation.ejs diff --git a/mongoServer/views/routeInformationLookup.ejs b/app/views/routeInformationLookup.ejs similarity index 100% rename from mongoServer/views/routeInformationLookup.ejs rename to app/views/routeInformationLookup.ejs diff --git a/mongoServer/views/viewRouteInformation.ejs b/app/views/viewRouteInformation.ejs similarity index 100% rename from mongoServer/views/viewRouteInformation.ejs rename to app/views/viewRouteInformation.ejs From 9c89669d85c931011f92000b7a6e18591a57f959 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 16:56:36 +0100 Subject: [PATCH 13/17] init commit --- spec/server.js | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 spec/server.js diff --git a/spec/server.js b/spec/server.js new file mode 100644 index 0000000..e6bced1 --- /dev/null +++ b/spec/server.js @@ -0,0 +1,215 @@ +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const server = require('../app/server'); +// Assertion Style +chai.should() +chai.use(chaiHttp) + + +// Server Test +describe('http server is running', ()=>{ + it('should return status OK', (done)=>{ + chai + .request(server) + .get('/') + .end((err,res)=>{ + res.should.have.status(200) + done() + }) + }) + it('should return 404', (done)=>{ + chai + .request(server) + .get('/asdfasdfasf') + .end((err,res)=>{ + res.should.have.status(404) + }) + done() + }) +}) + + +// Post Route Entries Test +describe('Posting /findRouteEntries', ()=>{ + it('should not return any route documents for absurd values', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'gt', 100000000 ], + odo: [ 'gt', 1000000000 ], + speed: [ 'gt', 1000 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findRouteEntries/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('routeEntries').lengthOf(0) + done() + }) + }) + it('should return only route documents speed > 20', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ 'gt', 20 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findRouteEntries/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('routeEntries') + res.body.routeEntries.forEach(entry =>{ + entry.should.have.property('speed').above(20) + }) + done() + }) + }) + it('should return only route documents speed < 20', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ 'lt', 20 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findRouteEntries/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('routeEntries') + res.body.routeEntries.forEach(entry =>{ + entry.should.have.property('speed').below(20) + }) + done() + }) + }) + it('should return only route documents speed = 12', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ '==', 12 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findRouteEntries/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('routeEntries') + res.body.routeEntries.forEach(entry =>{ + entry.should.have.property('speed').equals(12) + }) + done() + }) + }) +}) +// Post Incidents Test +describe('Posting /findIncidents', ()=>{ + it('should not return any incident documents for absurd values', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'gt', 100000000 ], + odo: [ 'gt', 1000000000 ], + speed: [ 'gt', 1000 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findIncidents/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('incidents').lengthOf(0) + done() + }) + }) + it('should return only incident documents speed > 20', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ 'gt', 20 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findIncidents/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('incidents') + res.body.incidents.forEach(entry =>{ + entry.should.have.property('speed').above(20) + }) + done() + }) + }) + it('should return only incident documents speed < 20', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ 'lt', 20 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findIncidents/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('incidents') + res.body.incidents.forEach(entry =>{ + entry.should.have.property('speed').below(20) + }) + done() + }) + }) + it('should return only incident documents speed = 12', (done)=>{ + const postBody = { + time: [ 'ignore', '2017-11-23T12:20' ], + energy: [ 'ignore', '' ], + odo: [ 'ignore', '' ], + speed: [ '==', 12 ], + soc: [ 'ignore', '' ], + type : 'api' + } + chai + .request(server) + .post('/findIncidents/') + .send(postBody) + .end((err,res)=>{ + res.should.have.status(200) + res.body.should.be.a('object') + res.body.should.have.property('incidents') + res.body.incidents.forEach(entry =>{ + entry.should.have.property('speed').equals(12) + }) + done() + }) + }) +}) \ No newline at end of file From 53fd4ebd06f77d15d0bff132d034cd0a5533bb0a Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 16:57:21 +0100 Subject: [PATCH 14/17] added testing libraries --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 461bff1..a1025fc 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,18 @@ "scripts": { "start-nats": "sh ./start-nats", "start-broadcast": "node vehicle-data-generator/index.js", - "connect-db": "node mongoServer/server.js" + "connect-db": "node app/server.js", + "test": "mocha spec/*.js --exit -t 15000" }, "author": "", "license": "ISC", "dependencies": { + "chai": "^4.3.4", + "chai-http": "^4.3.0", "csv-parse": "^3.2.0", "ejs": "^3.1.6", "express": "^4.17.1", + "mocha": "^9.1.3", "mongoose": "^6.0.13", "nats": "^1.0.1", "socket.io": "^4.3.2" From b91e6d6689bb39d37a392edc026fcc138cef7227 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 16:57:51 +0100 Subject: [PATCH 15/17] send dbData as simple response for testing --- app/server.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/server.js b/app/server.js index 1599e07..00d059d 100644 --- a/app/server.js +++ b/app/server.js @@ -47,7 +47,11 @@ app.get("/incidentLookup", async (req,res)=>{ app.post("/findIncidents", async (req,res)=>{ const dbFilter = getRouteFilter(req.body, true) const foundIncidents = await IncidentEntry.find(dbFilter).catch((err)=>{console.log(err)}) - res.render('../app/views/incidents.ejs', {incidents : foundIncidents}) + if(req.body.type === 'api'){ + res.send({incidents : foundIncidents}) + }else{ + res.render('../app/views/incidents.ejs', {incidents : foundIncidents}) + } }) app.get("/routeInformationLookup", async (req,res)=>{ res.render('../app/views/routeInformationLookup.ejs', {routeEntries : null}) @@ -55,7 +59,11 @@ app.get("/routeInformationLookup", async (req,res)=>{ app.post("/findRouteEntries", async (req,res)=>{ const dbFilter = getRouteFilter(req.body) const foundRouteInformation = await RouteInformationEntry.find(dbFilter).catch((err)=>{console.log(err)}) - res.render('../app/views/viewRouteInformation.ejs', {routeEntries : foundRouteInformation}) + if(req.body.type === 'api'){ + res.send({routeEntries : foundRouteInformation}) + }else{ + res.render('../app/views/viewRouteInformation.ejs', {routeEntries : foundRouteInformation}) + } }) // Websocket Logic const io = require('socket.io')(http); @@ -96,13 +104,15 @@ const getRouteFilter = (routeCriteria, lookForIncident)=>{ queryKeys.forEach(key=>{ let queryItem = routeCriteria[key] let dbKey = key + if(dbKey.type === 'api'){ + return + } if(lookForIncident){ dbKey = `data.${key}` } if(queryItem[2]){ dbFilter[`data.${key}`] = {$eq : ''} }else if(queryItem[0] === 'ignore'){ - return }else if(queryItem[0]=== 'gt'){ dbFilter[dbKey] = {$gt : parseFloat(queryItem[1])} }else if(queryItem[0]=== 'lt'){ From a2b14268bcf4fe005e52b0dfcbd2e4337b9d4bc0 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 16:58:33 +0100 Subject: [PATCH 16/17] added some testing --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bfe220d..8b2e494 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,11 @@ The first rectangle on the left is the vehicle data broadcast server, it's alrea ### Data Storage (To be build) After data is pushed to NATS it will be available for other services to listen. Now comes the part where you will have to start develop. Data that is broadcast-ed to NATS is not persisted, it means that we can not access historical data (such as data from past weeks) your task is to build a data storage server that will store all data in [MongoDB](https://www.mongodb.com/) and then serve it via an HTTP REST API and a WebSocket server for live data. So to summarize it here by the checklist of task you need to do: - - [ ] Create MongoDB database - - [ ] Push data from NATS to MongoDB - - [ ] Create REST API - - [ ] Create WebSocket API - - [ ] Test all APIs + - [x] Create MongoDB database + - [x] Push data from NATS to MongoDB + - [x] Create REST API + - [x] Create WebSocket API + - [x] Test ~~all~~ some APIs - [ ] Create Docker container for app (Optional) ### Incident Reporting (Optional) From 582c87b19eabeb4bde4af857d4cbde8ea564e162 Mon Sep 17 00:00:00 2001 From: RHSebregts Date: Wed, 1 Dec 2021 17:15:02 +0100 Subject: [PATCH 17/17] changed buttons --- app/views/routeInformation.ejs | 3 +-- app/views/viewRouteInformation.ejs | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/routeInformation.ejs b/app/views/routeInformation.ejs index fb81a17..c158b7d 100644 --- a/app/views/routeInformation.ejs +++ b/app/views/routeInformation.ejs @@ -21,8 +21,7 @@
Latest Route Information
See All Incidents diff --git a/app/views/viewRouteInformation.ejs b/app/views/viewRouteInformation.ejs index d410dad..10206d1 100644 --- a/app/views/viewRouteInformation.ejs +++ b/app/views/viewRouteInformation.ejs @@ -23,6 +23,7 @@
We found <%=routeEntries.length%> entries