From 59562b10c949d2c3981ddc0c62dbc9e54bb93ae8 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 18 Jun 2024 11:42:25 -0700 Subject: [PATCH] Improved network service error handling --- Server/controllers/monitorController.js | 13 ++++++ Server/db/MongoDB.js | 16 ++++++- Server/middleware/verifyJWT.js | 38 +++++++++-------- Server/routes/monitorRoute.js | 2 + Server/service/networkService.js | 55 +++++++++++++++++++------ 5 files changed, 91 insertions(+), 33 deletions(-) diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index a8ef8aecc..800ec994c 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -180,6 +180,18 @@ const deleteMonitor = async (req, res, next) => { } }; +const deleteAllMonitors = async (req, res) => { + try { + const deleteCount = await req.db.deleteAllMonitors(); + return res + .status(200) + .json({ success: true, msg: `Deleted ${deleteCount} monitors` }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } +}; + /** * Edit a monitor by ID * @async @@ -219,5 +231,6 @@ module.exports = { getMonitorsByUserId, createMonitor, deleteMonitor, + deleteAllMonitors, editMonitor, }; diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index ad37ee084..40db3c5e2 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -254,7 +254,19 @@ const deleteMonitor = async (req, res) => { } return monitor; } catch (error) { - console.log("CATHCING DELETE MONITOR ERROR"); + throw error; + } +}; + +/** + * DELETE ALL MONITORS (TEMP) + */ + +const deleteAllMonitors = async (req, res) => { + try { + const deletedCount = await Monitor.deleteMany({}); + return deletedCount.deletedCount; + } catch (error) { throw error; } }; @@ -320,7 +332,6 @@ const createCheck = async (checkData) => { const getChecks = async (monitorId) => { try { const checks = await Check.find({ monitorId }); - console.log(checks); return checks; } catch (error) { throw error; @@ -483,6 +494,7 @@ module.exports = { getMonitorsByUserId, createMonitor, deleteMonitor, + deleteAllMonitors, editMonitor, createCheck, getChecks, diff --git a/Server/middleware/verifyJWT.js b/Server/middleware/verifyJWT.js index 9c9a3759a..1dbbe8d99 100644 --- a/Server/middleware/verifyJWT.js +++ b/Server/middleware/verifyJWT.js @@ -15,34 +15,36 @@ const verifyJWT = (req, res, next) => { const token = req.headers["authorization"]; // Make sure a token is provided if (!token) { - const error = new Error(error.errorMessages.NO_AUTH_TOKEN); + const error = new Error(errorMessages.NO_AUTH_TOKEN); error.status = 401; error.service = SERVICE_NAME; next(error); return; } // Make sure it is properly formatted - if (token.startsWith(TOKEN_PREFIX)) { - const parsedToken = token.slice(TOKEN_PREFIX.length, token.length); - // Verify the token's authenticity - jwt.verify(parsedToken, process.env.JWT_SECRET, (err, decoded) => { - if (err) { - logger.error(errorMessages.INVALID_AUTH_TOKEN, { - service: SERVICE_NAME, - }); - return res - .status(401) - .json({ success: false, msg: errorMessages.INVALID_AUTH_TOKEN }); - } - //Add the user to the request object for use in the route - req.user = decoded; - next(); - }); - } else { + if (!token.startsWith(TOKEN_PREFIX)) { + const error = new Error(errorMessages.INVALID_AUTH_TOKEN); // Instantiate a new Error object for improperly formatted token error.status = 400; error.service = SERVICE_NAME; next(error); + return; } + + const parsedToken = token.slice(TOKEN_PREFIX.length, token.length); + // Verify the token's authenticity + jwt.verify(parsedToken, process.env.JWT_SECRET, (err, decoded) => { + if (err) { + logger.error(errorMessages.INVALID_AUTH_TOKEN, { + service: SERVICE_NAME, + }); + return res + .status(401) + .json({ success: false, msg: errorMessages.INVALID_AUTH_TOKEN }); + } + //Add the user to the request object for use in the route + req.user = decoded; + next(); + }); }; module.exports = { verifyJWT }; diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index ffdce1d4d..ae7a5852e 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -18,4 +18,6 @@ router.post( verifyOwnership(Monitor, "monitorId"), monitorController.editMonitor ); + +router.delete("/delete/all", monitorController.deleteAllMonitors); module.exports = router; diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 1fa2daac4..f3f40999d 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -9,6 +9,7 @@ class NetworkService { this.TYPE_PING = "ping"; this.TYPE_HTTP = "http"; this.SERVICE_NAME = "NetworkService"; + this.NETWORK_ERROR = 5000; } /** @@ -46,9 +47,20 @@ class NetworkService { operation ); const isAlive = response.alive; - return await this.logAndStoreCheck(job, isAlive, responseTime); + + const check = new Check({ + monitorId: job.data._id, + status: isAlive, + responseTime, + }); + return await this.logAndStoreCheck(check); } catch (error) { - return await this.logAndStoreCheck(job, false, error.responseTime, error); + const check = new Check({ + monitorId: job.data._id, + status: false, + responseTime: error.responseTime, + }); + return await this.logAndStoreCheck(check); } } @@ -58,20 +70,45 @@ class NetworkService { * @returns {Promise<{boolean}} The result of logging and storing the check */ async handleHttp(job) { + // Define operation for timing const operation = async () => { const response = await axios.get(job.data.url); return response; }; + + // attempt connection try { const { responseTime, response } = await this.measureResponseTime( operation ); + + // check if response is in the 200 range, if so, service is up const isAlive = response.status >= 200 && response.status < 300; - return await this.logAndStoreCheck(job, isAlive, responseTime); + + //Create a check with relevant data + const check = new Check({ + monitorId: job.data._id, + status: isAlive, + responseTime, + statusCode: response.status, + }); + return await this.logAndStoreCheck(check); } catch (error) { - return await this.logAndStoreCheck(job, false, error.responseTime, error); + const check = new Check({ + monitorId: job.data._id, + status: false, + responseTime: error.responseTime, + }); + // The server returned a response + if (error.response) { + check.statusCode = error.response.status; + } else { + check.statusCode = this.NETWORK_ERROR; + } + return await this.logAndStoreCheck(check); } } + /** * Retrieves the status of a given job based on its type. * For unsupported job types, it logs an error and returns false. @@ -107,15 +144,7 @@ class NetworkService { * @param {Error} [error=null] - Optional error object if an error occurred during the check. * @returns {Promise} The status of the inserted check if successful, otherwise false. */ - async logAndStoreCheck(job, isAlive, responseTime, error = null) { - const check = new Check({ - monitorId: job.data._id, - status: isAlive, - responseTime, - statusCode: 0, - message: error ? error.message : "", - }); - + async logAndStoreCheck(check) { try { const insertedCheck = await check.save(); return insertedCheck.status;