From d85dc50220fe3a41f4ae8bb5c649313cbe1c7337 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 28 Oct 2024 14:19:14 +0800 Subject: [PATCH] Add statusService --- Server/service/statusService.js | 139 ++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 Server/service/statusService.js diff --git a/Server/service/statusService.js b/Server/service/statusService.js new file mode 100644 index 000000000..7d71fab7f --- /dev/null +++ b/Server/service/statusService.js @@ -0,0 +1,139 @@ +class StatusService { + /** + * Creates an instance of StatusService. + * + * @param {Object} db - The database instance. + * @param {Object} logger - The logger instance. + */ + constructor(db, logger) { + this.db = db; + this.logger = logger; + this.SERVICE_NAME + "StatusService"; + } + + /** + * Updates the status of a monitor based on the network response. + * + * @param {Object} networkResponse - The network response containing monitorId and status. + * @param {string} networkResponse.monitorId - The ID of the monitor. + * @param {string} networkResponse.status - The new status of the monitor. + * @returns {Promise} - A promise that resolves to an object containing the monitor, statusChanged flag, and previous status if the status changed, or false if an error occurred. + * @returns {Promise} returnObject - The object returned by the function. + * @returns {Object} returnObject.monitor - The monitor object. + * @returns {boolean} returnObject.statusChanged - Flag indicating if the status has changed. + * @returns {boolean} returnObject.prevStatus - The previous status of the monitor + */ + updateStatus = async (networkResponse) => { + this.insertCheck(networkResponse); + try { + const { monitorId, status } = networkResponse; + const monitor = await this.db.getMonitorById(monitorId); + // No change in monitor status, return early + if (monitor.status === status) return { statusChanged: false }; + // Monitor status changed, save prev status and update monitor + + this.logger.info({ + service: this.SERVICE_NAME, + message: `${monitor.name} went from ${monitor.status === true ? "up" : "down"} to ${status === true ? "up" : "down"}`, + prevStatus: monitor.status, + newStatus: status, + }); + + const prevStatus = monitor.status; + monitor.status = status; + monitor.save(); + + return { + monitor, + statusChanged: true, + prevStatus: prevStatus, + }; + // + } catch (error) { + this.logger.error({ + service: this.SERVICE_NAME, + message: error.message, + method: "updateStatus", + stack: error.stack, + }); + throw error; + } + }; + + /** + * Builds a check object from the network response. + * + * @param {Object} networkResponse - The network response object. + * @param {string} networkResponse.monitorId - The monitor ID. + * @param {string} networkResponse.type - The type of the response. + * @param {string} networkResponse.status - The status of the response. + * @param {number} networkResponse.responseTime - The response time. + * @param {number} networkResponse.code - The status code. + * @param {string} networkResponse.message - The message. + * @param {Object} networkResponse.payload - The payload of the response. + * @returns {Object} The check object. + */ + buildCheck = (networkResponse) => { + const { monitorId, type, status, responseTime, code, message, payload } = + networkResponse; + const check = { + monitorId, + status, + statusCode: code, + responseTime, + message, + }; + if (type === "pagespeed") { + const categories = payload.lighthouseResult?.categories; + const audits = payload.lighthouseResult?.audits; + const { + "cumulative-layout-shift": cls = 0, + "speed-index": si = 0, + "first-contentful-paint": fcp = 0, + "largest-contentful-paint": lcp = 0, + "total-blocking-time": tbt = 0, + } = audits; + check.accessibility = (categories.accessibility?.score || 0) * 100; + check.bestPractices = (categories["best-practices"]?.score || 0) * 100; + check.seo = (categories.seo?.score || 0) * 100; + check.performance = (categories.performance?.score || 0) * 100; + check.audits = { cls, si, fcp, lcp, tbt }; + } + return check; + }; + + /** + * Inserts a check into the database based on the network response. + * + * @param {Object} networkResponse - The network response object. + * @param {string} networkResponse.monitorId - The monitor ID. + * @param {string} networkResponse.type - The type of the response. + * @param {string} networkResponse.status - The status of the response. + * @param {number} networkResponse.responseTime - The response time. + * @param {number} networkResponse.code - The status code. + * @param {string} networkResponse.message - The message. + * @param {Object} networkResponse.payload - The payload of the response. + * @returns {Promise} A promise that resolves when the check is inserted. + */ + insertCheck = async (networkResponse) => { + try { + const operationMap = { + http: this.db.createCheck, + ping: this.db.createCheck, + pagespeed: this.db.createPageSpeedCheck, + }; + const operation = operationMap[networkResponse.type]; + const check = this.buildCheck(networkResponse); + await operation(check); + } catch (error) { + this.logger.error({ + message: error.message, + service: this.SERVICE_NAME, + method: "insertCheck", + details: `Error inserting check for monitor: ${networkResponse.monitorId}`, + stack: error.stack, + }); + } + }; +} +export default StatusService;