From 92986cfb23e5760a32d47659e93fa2684ad37c2c Mon Sep 17 00:00:00 2001 From: "DESKTOP-C9V2M01\\Zeeri" Date: Sat, 4 Jun 2022 08:27:42 -0700 Subject: [PATCH] Fixed bugs; Removed caching that would cause problems with spinning up multiple processes. --- app.js | 4 +- routes/ping.js | 121 ++++++++++++++----------------------------------- 2 files changed, 38 insertions(+), 87 deletions(-) diff --git a/app.js b/app.js index 703edeb..1f7ed5e 100644 --- a/app.js +++ b/app.js @@ -10,12 +10,14 @@ var pingRouter = require('./routes/ping'); var app = express(); let port = 3003; +let log = false; if(process.env.PORT) port = process.env.PORT; +if(process.env.LOG) log = process.env.LOG; console.log("Running on port: " + port); -app.use(logger('dev')); +if(log) app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); diff --git a/routes/ping.js b/routes/ping.js index e059ccc..ab40813 100644 --- a/routes/ping.js +++ b/routes/ping.js @@ -13,7 +13,6 @@ if(!uri) { } const client = new MongoClient(uri); let collection; -let records = {}; // We are keeping an in-memory set of current/active records for each Chromebook to reduce the number of reads without _id we perform. // The idea is that each Chromebook pings every 5 minutes when a student is logged in and using the Chromebook. @@ -26,29 +25,16 @@ async function connect() { await client.connect(); const database = client.db("avusd_data_collection"); collection = database.collection('records'); - console.log("Connected to Mongodb server"); + // console.log("Connected to Mongodb server"); } catch(e) { + console.log("error: caught ping.js:31 in Data Collection."); console.log(e); } } -// Load a record for specific Chromebook by serial number (we assume they are unique). -async function loadRecord(serial) { - //Read record with given serial. - let record = await collection.findOne({serial, closed: false}); - - //If we found one then add it to the map. - if(record && !record.closed) { - records[record.serial] = record; - } - else {record = null;} - - return record; -} - // Create a new record for a Chromebook & user. Set it in the cache (replace any existing one for that serial). async function createRecord(record, isInternal) { - record.startTime = new Date().getTime(); + record.startTime = record.endTime = new Date().getTime(); record.count = 1; record.internalCount = isInternal ? 1 : 0; @@ -57,75 +43,35 @@ async function createRecord(record, isInternal) { //Handle errors. if(queryResult.writeConcernError && queryResult.writeConcernError.errmsg) { + console.log("error: caught ping.js:61 in Data Collection."); console.log(queryResult.writeConcernError.errmsg + " ::: " + JSON.stringify(record)); - record = null; } - else { - //Add the map if there were no errors. - records[record.serial] = record; - } - - return record; } -// Update a record. Will create a new record if one doesn't exist for the Chromebook. Will close a record if the user changes, and then create a new one for the new user. async function updateRecord(record, isInternal, clientAddress) { - let existing = records[record.serial]; - - if(!collection) { - await connect(); - } - - //If one is not in the cache, then read it from the db. - if(!existing) { - existing = await loadRecord(record.serial); - } - - //If we couldn't find one for the given serial in the db, then create it. - // Note: We only do this if the connection is on the internal network. - // This prevents attackers from spamming the server with random id's to pollute the data. - if(!existing) { - if(isInternal) { - existing = await createRecord(record, isInternal); + try { + if(!collection) { + await connect(); } - else { - //Log the external attempt to update a 'new' chromebook. - console.log("Ignoring external (" + clientAddress + ") input: " + JSON.stringify(record)); - } - } - else { - let changed = {}; - let inc = {}; - //If the user has changed, then close the record. Create a new record for the new user. - if(existing.email !== record.email) { - changed.closed = existing.closed = true; + //Read record with given serial. + let existing = await collection.findOne({serial: record.serial, closed: {$exists: false}}); + + if(!existing) { await createRecord(record, isInternal); } else { - //Update the time and count for both the db and the in memory data. - changed.endTimestamp = existing.endTimestamp = new Date().getTime(); - // Note: Cannot increment this way because there could be multiple instances of this process running with different cached values. Use MongoDB $inc instead. - // changed.count = existing.count = existing.count + 1; - inc.count = 1; - - //Update the internal count if the Chromebook address is on the internal network. - if(isInternal) { - // Note: Cannot increment this way because there could be multiple instances of this process running with different cached values. Use MongoDB $inc instead. - // changed.internalCount = existing.internalCount = existing.internalCount + 1; - inc.internalCount = 1; - } - } - - //If something changed, then update the db. - if(!_.isEmpty(changed)) { - let result = await collection.updateOne({_id: existing._id}, {$set: changed, $inc: inc}); - - //Error handling. - if(result.modifiedCount !== 1) { - console.log("Failed to update the record: " + JSON.stringify(existing)); + //If the user has changed, then close the record. Create a new record for the new user. + if(existing.email !== record.email) { + await collection.updateOne({_id: existing._id}, {$set: {closed: true}}); + await createRecord(record, isInternal); + } + else { + await collection.updateOne({_id: existing._id}, {$set: {endTime: new Date().getTime()}, $inc: {count: 1, internalCount: isInternal ? 1 : 0}}); } } + } catch(e) { + console.log(e); } } @@ -144,21 +90,24 @@ router.get('/', function(req, res, next) { // console.log("Serial: " + params.serial); // console.log("DeviceId: " + params.deviceId); - let clientAddress = req.header("X-Real-IP"); - if(!clientAddress) clientAddress = req.socket.remoteAddress; - let isLocal = true; - console.log("Found IP: " + clientAddress); + // Ignore any calls without a serial. + if(params.serial) { + let clientAddress = req.header("X-Real-IP"); + if (!clientAddress) clientAddress = req.socket.remoteAddress; + let isLocal = true; + // console.log("Found IP: " + clientAddress); - if(localAddresses) { - isLocal = false; - for(let i = 0; !isLocal && i < localAddresses.length; i++) { - let next = localAddresses[i]; - isLocal = clientAddress.startsWith(next); + if (localAddresses) { + isLocal = false; + for (let i = 0; !isLocal && i < localAddresses.length; i++) { + let next = localAddresses[i]; + isLocal = clientAddress.startsWith(next); + } } - } - //Note: We are not waiting for this to finish. We don't care about the output. - updateRecord({serial, assetId, deviceId, email}, isLocal, clientAddress); + //Note: We are not waiting for this to finish. We don't care about the output. + updateRecord({serial, assetId, deviceId, email}, isLocal, clientAddress); + } //Send response. Nothing for the moment. res.setHeader("Access-Control-Allow-Origin", "*");