mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-16 14:49:48 -06:00
300 lines
6.5 KiB
JavaScript
300 lines
6.5 KiB
JavaScript
import Check from "../../models/Check.js";
|
|
import Monitor from "../../models/Monitor.js";
|
|
import User from "../../models/User.js";
|
|
import logger from "../../../utils/logger.js";
|
|
import { ObjectId } from "mongodb";
|
|
|
|
const SERVICE_NAME = "checkModule";
|
|
const dateRangeLookup = {
|
|
hour: new Date(new Date().setHours(new Date().getHours() - 1)),
|
|
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
|
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
|
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
|
all: undefined,
|
|
};
|
|
|
|
/**
|
|
* Create a check for a monitor
|
|
* @async
|
|
* @param {Object} checkData
|
|
* @param {string} checkData.monitorId
|
|
* @param {boolean} checkData.status
|
|
* @param {number} checkData.responseTime
|
|
* @param {number} checkData.statusCode
|
|
* @param {string} checkData.message
|
|
* @returns {Promise<Check>}
|
|
* @throws {Error}
|
|
*/
|
|
|
|
const createCheck = async (checkData) => {
|
|
try {
|
|
const { monitorId, status } = checkData;
|
|
const n = (await Check.countDocuments({ monitorId })) + 1;
|
|
const check = await new Check({ ...checkData }).save();
|
|
const monitor = await Monitor.findById(monitorId);
|
|
|
|
if (!monitor) {
|
|
logger.error({
|
|
message: "Monitor not found",
|
|
service: SERVICE_NAME,
|
|
method: "createCheck",
|
|
details: `monitor ID: ${monitorId}`,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Update uptime percentage
|
|
if (monitor.uptimePercentage === undefined) {
|
|
monitor.uptimePercentage = status === true ? 1 : 0;
|
|
} else {
|
|
monitor.uptimePercentage =
|
|
(monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
|
|
}
|
|
|
|
await monitor.save();
|
|
return check;
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "createCheck";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get all checks for a monitor
|
|
* @async
|
|
* @param {string} monitorId
|
|
* @returns {Promise<Array<Check>>}
|
|
* @throws {Error}
|
|
*/
|
|
const getChecksByMonitor = async (req) => {
|
|
try {
|
|
const { monitorId } = req.params;
|
|
let { sortOrder, dateRange, filter, page, rowsPerPage } = req.query;
|
|
page = parseInt(page);
|
|
rowsPerPage = parseInt(rowsPerPage);
|
|
// Match
|
|
const matchStage = {
|
|
monitorId: ObjectId.createFromHexString(monitorId),
|
|
status: false,
|
|
...(dateRangeLookup[dateRange] && {
|
|
createdAt: {
|
|
$gte: dateRangeLookup[dateRange],
|
|
},
|
|
}),
|
|
};
|
|
|
|
if (filter !== undefined) {
|
|
switch (filter) {
|
|
case "all":
|
|
break;
|
|
case "down":
|
|
break;
|
|
case "resolve":
|
|
matchStage.statusCode = 5000;
|
|
break;
|
|
default:
|
|
logger.warn({
|
|
message: "invalid filter",
|
|
service: SERVICE_NAME,
|
|
method: "getChecks",
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Sort
|
|
sortOrder = sortOrder === "asc" ? 1 : -1;
|
|
|
|
// Pagination
|
|
let skip = 0;
|
|
if (page && rowsPerPage) {
|
|
skip = page * rowsPerPage;
|
|
}
|
|
|
|
const checks = await Check.aggregate([
|
|
{ $match: matchStage },
|
|
{ $sort: { createdAt: sortOrder } },
|
|
{
|
|
$facet: {
|
|
summary: [{ $count: "checksCount" }],
|
|
checks: [{ $skip: skip }, { $limit: rowsPerPage }],
|
|
},
|
|
},
|
|
{
|
|
$project: {
|
|
checksCount: { $arrayElemAt: ["$summary.checksCount", 0] },
|
|
checks: "$checks",
|
|
},
|
|
},
|
|
]);
|
|
|
|
return checks[0];
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "getChecks";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const getChecksByTeam = async (req) => {
|
|
try {
|
|
let { sortOrder, dateRange, filter, page, rowsPerPage } = req.query;
|
|
page = parseInt(page);
|
|
rowsPerPage = parseInt(rowsPerPage);
|
|
console.log(dateRangeLookup[dateRange]);
|
|
const { teamId } = req.params;
|
|
const matchStage = {
|
|
teamId: ObjectId.createFromHexString(teamId),
|
|
status: false,
|
|
...(dateRangeLookup[dateRange] && {
|
|
createdAt: {
|
|
$gte: dateRangeLookup[dateRange],
|
|
},
|
|
}),
|
|
};
|
|
console.log(matchStage);
|
|
// Add filter to match stage
|
|
if (filter !== undefined) {
|
|
switch (filter) {
|
|
case "all":
|
|
break;
|
|
case "down":
|
|
break;
|
|
case "resolve":
|
|
matchStage.statusCode = 5000;
|
|
break;
|
|
default:
|
|
logger.warn({
|
|
message: "invalid filter",
|
|
service: SERVICE_NAME,
|
|
method: "getChecksByTeam",
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
sortOrder = sortOrder === "asc" ? 1 : -1;
|
|
|
|
// pagination
|
|
let skip = 0;
|
|
if (page && rowsPerPage) {
|
|
skip = page * rowsPerPage;
|
|
}
|
|
|
|
const checks = await Check.aggregate([
|
|
{ $match: matchStage },
|
|
{ $sort: { createdAt: sortOrder } },
|
|
|
|
{
|
|
$facet: {
|
|
summary: [{ $count: "checksCount" }],
|
|
checks: [{ $skip: skip }, { $limit: rowsPerPage }],
|
|
},
|
|
},
|
|
{
|
|
$project: {
|
|
checksCount: { $arrayElemAt: ["$summary.checksCount", 0] },
|
|
checks: "$checks",
|
|
},
|
|
},
|
|
]);
|
|
|
|
return checks[0];
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "getChecksByTeam";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Delete all checks for a monitor
|
|
* @async
|
|
* @param {string} monitorId
|
|
* @returns {number}
|
|
* @throws {Error}
|
|
*/
|
|
|
|
const deleteChecks = async (monitorId) => {
|
|
try {
|
|
const result = await Check.deleteMany({ monitorId });
|
|
return result.deletedCount;
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "deleteChecks";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Delete all checks for a team
|
|
* @async
|
|
* @param {string} monitorId
|
|
* @returns {number}
|
|
* @throws {Error}
|
|
*/
|
|
|
|
const deleteChecksByTeamId = async (teamId) => {
|
|
try {
|
|
const teamMonitors = await Monitor.find({ teamId: teamId });
|
|
let totalDeletedCount = 0;
|
|
|
|
await Promise.all(
|
|
teamMonitors.map(async (monitor) => {
|
|
const result = await Check.deleteMany({ monitorId: monitor._id });
|
|
totalDeletedCount += result.deletedCount;
|
|
monitor.status = true;
|
|
await monitor.save();
|
|
})
|
|
);
|
|
|
|
return totalDeletedCount;
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "deleteChecksByTeamId";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const updateChecksTTL = async (teamId, ttl) => {
|
|
try {
|
|
await Check.collection.dropIndex("expiry_1");
|
|
} catch (error) {
|
|
logger.error({
|
|
message: error.message,
|
|
service: SERVICE_NAME,
|
|
method: "updateChecksTTL",
|
|
stack: error.stack,
|
|
});
|
|
}
|
|
|
|
try {
|
|
await Check.collection.createIndex(
|
|
{ expiry: 1 },
|
|
{ expireAfterSeconds: ttl } // TTL in seconds, adjust as necessary
|
|
);
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "updateChecksTTL";
|
|
throw error;
|
|
}
|
|
// Update user
|
|
try {
|
|
await User.updateMany({ teamId: teamId }, { checkTTL: ttl });
|
|
} catch (error) {
|
|
error.service = SERVICE_NAME;
|
|
error.method = "updateChecksTTL";
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
export {
|
|
createCheck,
|
|
getChecksByMonitor,
|
|
getChecksByTeam,
|
|
deleteChecks,
|
|
deleteChecksByTeamId,
|
|
updateChecksTTL,
|
|
};
|