Resolved merge conflict in Server/index.js

This commit is contained in:
Skorpios committed 2025-02-08 16:39:01 -08:00
commit e9bcf66b29
99 files changed
+5354 -358

No files matched your search

+108
View File
@@ -1,13 +1,121 @@
import mongoose from "mongoose";
import { BaseCheckSchema } from "./Check.js";
// {
// "id": "12123",
// "result": {
// "task_arrived": "2025-01-13T19:21:37.463466602Z",
// "dns_start": "2025-01-14T00:21:33.1801319+05:00",
// "dns_end": "2025-01-14T00:21:33.4582552+05:00",
// "conn_start": "2025-01-14T00:21:33.1801319+05:00",
// "conn_end": "2025-01-14T00:21:33.7076318+05:00",
// "connect_start": "2025-01-14T00:21:33.4582552+05:00",
// "connect_end": "2025-01-14T00:21:33.541899+05:00",
// "tls_hand_shake_start": "2025-01-14T00:21:33.541899+05:00",
// "tls_hand_shake_end": "2025-01-14T00:21:33.7076318+05:00",
// "body_read_start": "2025-01-14T00:21:34.1894707+05:00",
// "body_read_end": "2025-01-14T00:21:34.1894707+05:00",
// "wrote_request": "2025-01-14T00:21:33.7076318+05:00",
// "got_first_response_byte": "2025-01-14T00:21:34.1327652+05:00",
// "first_byte_took": 425133400,
// "body_read_took": 56030000,
// "dns_took": 278123300,
// "conn_took": 527499900,
// "connect_took": 83643800,
// "tls_took": 165732800,
// "sni_name": "uprock.com",
// "status_code": 200,
// "body_size": 19320,
// "request_header_size": 95,
// "response_header_size": 246,
// "response_headers": "X-Vercel-Id: bom1::iad1::sm87v-1736796096856-aec270c01f23\nDate: Mon, 13 Jan 2025 19:21:37 GMT\nServer: Vercel\nStrict-Transport-Security: max-age=63072000\nVary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url\nX-Matched-Path: /\nX-Powered-By: Next.js\nX-Vercel-Cache: MISS\nAge: 0\nCache-Control: private, no-cache, no-store, max-age=0, must-revalidate\nContent-Type: text/html; charset=utf-8",
// "error": "",
// "device_id": "d5f578e143a2cd603dd6bf5f846a86a538bde4a8fbe2ad1fca284ad9f033daf8",
// "ip_address": "223.123.19.0",
// "proof": "",
// "created_at": "2025-01-13T19:21:37.463466912Z",
// "continent": "AS",
// "country_code": "PK",
// "city": "Muzaffargarh",
// "upt_burnt" : "0.01",
// "location": {
// "lat": 71.0968,
// "lng": 30.0208
// },
// "payload": {
// "callback": "https://webhook.site/2a15b0af-545a-4ac2-b913-153b97592d7a",
// "x": "y"
// }
// }
// }
const LocationSchema = new mongoose.Schema(
{
lat: { type: Number, required: true },
lng: { type: Number, required: true },
},
{ _id: false }
);
const DistributedUptimeCheckSchema = mongoose.Schema(
{
...BaseCheckSchema.obj,
first_byte_took: {
type: Number,
required: false,
},
body_read_took: {
type: Number,
required: false,
},
dns_took: {
type: Number,
required: false,
},
conn_took: {
type: Number,
required: false,
},
connect_took: {
type: Number,
required: false,
},
tls_took: {
type: Number,
required: false,
},
location: {
type: LocationSchema,
required: false,
},
continent: {
type: String,
required: false,
},
countryCode: {
type: String,
required: false,
},
city: {
type: String,
required: false,
},
uptBurnt: {
type: mongoose.Schema.Types.Decimal128,
required: false,
},
},
{ timestamps: true }
);
DistributedUptimeCheckSchema.pre("save", function (next) {
if (this.isModified("uptBurnt") && typeof this.uptBurnt === "string") {
this.uptBurnt = mongoose.Types.Decimal128.fromString(this.uptBurnt);
}
next();
});
DistributedUptimeCheckSchema.index({ createdAt: 1 });
DistributedUptimeCheckSchema.index({ monitorId: 1, createdAt: 1 });
DistributedUptimeCheckSchema.index({ monitorId: 1, createdAt: -1 });
+16 -5
View File
@@ -23,11 +23,6 @@ const StatusPageSchema = mongoose.Schema(
required: true,
default: "#4169E1",
},
theme: {
type: String,
required: true,
default: "light",
},
monitors: [
{
type: mongoose.Schema.Types.ObjectId,
@@ -35,6 +30,22 @@ const StatusPageSchema = mongoose.Schema(
required: true,
},
],
logo: {
data: Buffer,
contentType: String,
},
isPublished: {
type: Boolean,
default: false,
},
showCharts: {
type: Boolean,
default: true,
},
showUptimePercentage: {
type: Boolean,
default: true,
},
},
{ timestamps: true }
);
+6
View File
@@ -43,6 +43,11 @@ import * as hardwareCheckModule from "./modules/hardwareCheckModule.js";
import * as checkModule from "./modules/checkModule.js";
//****************************************
// Distributed Checks
//****************************************
import * as distributedCheckModule from "./modules/distributedCheckModule.js";
//****************************************
// Maintenance Window
//****************************************
@@ -74,6 +79,7 @@ class MongoDB {
Object.assign(this, pageSpeedCheckModule);
Object.assign(this, hardwareCheckModule);
Object.assign(this, checkModule);
Object.assign(this, distributedCheckModule);
Object.assign(this, maintenanceWindowModule);
Object.assign(this, notificationModule);
Object.assign(this, settingsModule);
@@ -0,0 +1,15 @@
import DistributedUptimeCheck from "../../models/DistributedUptimeCheck.js";
const SERVICE_NAME = "distributedCheckModule";
const createDistributedCheck = async (checkData) => {
try {
const check = await new DistributedUptimeCheck({ ...checkData }).save();
return check;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "createCheck";
throw error;
}
};
export { createDistributedCheck };
+69
View File
@@ -2,6 +2,7 @@ import Monitor from "../../models/Monitor.js";
import Check from "../../models/Check.js";
import PageSpeedCheck from "../../models/PageSpeedCheck.js";
import HardwareCheck from "../../models/HardwareCheck.js";
import DistributedUptimeCheck from "../../models/DistributedUptimeCheck.js";
import { errorMessages } from "../../../utils/messages.js";
import Notification from "../../models/Notification.js";
import { NormalizeData, NormalizeDataUptimeDetails } from "../../../utils/dataUtils.js";
@@ -11,6 +12,7 @@ import { fileURLToPath } from "url";
import {
buildUptimeDetailsPipeline,
buildHardwareDetailsPipeline,
buildDistributedUptimeDetailsPipeline,
} from "./monitorModuleQueries.js";
import { ObjectId } from "mongodb";
const __filename = fileURLToPath(import.meta.url);
@@ -366,6 +368,48 @@ const getUptimeDetailsById = async (req) => {
}
};
const getDistributedUptimeDetailsById = async (req) => {
try {
const { monitorId } = req.params;
const monitor = await Monitor.findById(monitorId);
if (monitor === null || monitor === undefined) {
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
}
const { dateRange, normalize } = req.query;
const dates = getDateRange(dateRange);
const formatLookup = {
day: "%Y-%m-%dT%H:%M:00Z",
week: "%Y-%m-%dT%H:00:00Z",
month: "%Y-%m-%dT00:00:00Z",
};
const dateString = formatLookup[dateRange];
const results = await DistributedUptimeCheck.aggregate(
buildDistributedUptimeDetailsPipeline(monitor, dates, dateString)
);
const monitorData = results[0];
const normalizedGroupChecks = NormalizeDataUptimeDetails(
monitorData.groupedChecks,
10,
100
);
const monitorStats = {
...monitor.toObject(),
...monitorData,
groupedChecks: normalizedGroupChecks,
};
return monitorStats;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getDistributedUptimeDetailsById";
throw error;
}
};
/**
* Get stats by monitor ID
* @async
@@ -630,6 +674,26 @@ const getMonitorsByTeamId = async (req) => {
},
]
: []),
...(limit
? [
{
$lookup: {
from: "distributeduptimechecks",
let: { monitorId: "$_id" },
pipeline: [
{
$match: {
$expr: { $eq: ["$monitorId", "$$monitorId"] },
},
},
{ $sort: { createdAt: -1 } },
...(limit ? [{ $limit: limit }] : []),
],
as: "distributeduptimechecks",
},
},
]
: []),
{
$addFields: {
@@ -648,6 +712,10 @@ const getMonitorsByTeamId = async (req) => {
case: { $eq: ["$type", "hardware"] },
then: "$hardwarechecks",
},
{
case: { $eq: ["$type", "distributed_http"] },
then: "$distributeduptimechecks",
},
],
default: [],
},
@@ -815,6 +883,7 @@ export {
getMonitorById,
getMonitorsByTeamId,
getUptimeDetailsById,
getDistributedUptimeDetailsById,
createMonitor,
deleteMonitor,
deleteAllMonitors,
+185 -1
View File
@@ -534,4 +534,188 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
];
};
export { buildUptimeDetailsPipeline, buildHardwareDetailsPipeline };
const buildDistributedUptimeDetailsPipeline = (monitor, dates, dateString) => {
return [
{
$match: {
monitorId: monitor._id,
},
},
{
$sort: {
createdAt: 1,
},
},
{
$facet: {
aggregateData: [
{
$group: {
_id: null,
avgResponseTime: {
$avg: "$responseTime",
},
lastCheck: {
$last: "$$ROOT",
},
totalChecks: {
$sum: 1,
},
uptBurnt: {
$sum: "$uptBurnt",
},
},
},
],
// For the response time chart, should return checks for date window
// Grouped by: {day: hour}, {week: day}, {month: day}
groupedMapChecks: [
{
$match: {
createdAt: { $gte: dates.start, $lte: dates.end },
},
},
{
$group: {
_id: {
date: {
$dateToString: {
format: dateString,
date: "$createdAt",
},
},
city: "$city",
lat: "$location.lat",
lng: "$location.lng",
},
city: { $first: "$city" }, // Add this line to include city in output
lat: { $first: "$location.lat" },
lng: { $first: "$location.lng" },
avgResponseTime: {
$avg: "$responseTime",
},
totalChecks: {
$sum: 1,
},
},
},
{
$sort: {
"_id.date": 1,
},
},
],
groupedChecks: [
{
$match: {
createdAt: { $gte: dates.start, $lte: dates.end },
},
},
{
$group: {
_id: {
$dateToString: {
format: dateString,
date: "$createdAt",
},
},
avgResponseTime: {
$avg: "$responseTime",
},
totalChecks: {
$sum: 1,
},
},
},
{
$sort: {
_id: 1,
},
},
],
// Average response time for the date window
groupAvgResponseTime: [
{
$match: {
createdAt: { $gte: dates.start, $lte: dates.end },
},
},
{
$group: {
_id: null,
avgResponseTime: {
$avg: "$responseTime",
},
},
},
],
latestChecks: [
{
$sort: { createdAt: -1 }, // Sort by newest first
},
{
$limit: 5, // Get only the first 5 documents
},
{
$project: {
responseTime: 1,
city: 1,
countryCode: 1,
uptBurnt: { $toString: "$uptBurnt" },
},
},
],
},
},
{
$project: {
totalUptBurnt: {
$toString: {
$arrayElemAt: ["$aggregateData.uptBurnt", 0],
},
},
avgResponseTime: {
$arrayElemAt: ["$aggregateData.avgResponseTime", 0],
},
totalChecks: {
$arrayElemAt: ["$aggregateData.totalChecks", 0],
},
latestResponseTime: {
$arrayElemAt: ["$aggregateData.lastCheck.responseTime", 0],
},
timeSinceLastCheck: {
$let: {
vars: {
lastCheck: {
$arrayElemAt: ["$aggregateData.lastCheck", 0],
},
},
in: {
$cond: [
{
$ifNull: ["$$lastCheck", false],
},
{
$subtract: [new Date(), "$$lastCheck.createdAt"],
},
0,
],
},
},
},
groupedMapChecks: "$groupedMapChecks",
groupedChecks: "$groupedChecks",
groupedAvgResponseTime: {
$arrayElemAt: ["$groupAvgResponseTime", 0],
},
latestChecks: "$latestChecks",
},
},
];
};
export {
buildUptimeDetailsPipeline,
buildHardwareDetailsPipeline,
buildDistributedUptimeDetailsPipeline,
};
+123 -7
View File
@@ -1,11 +1,18 @@
import StatusPage from "../../models/StatusPage.js";
import { errorMessages } from "../../../utils/messages.js";
import { NormalizeData } from "../../../utils/dataUtils.js";
const SERVICE_NAME = "statusPageModule";
const createStatusPage = async (statusPageData) => {
const createStatusPage = async (statusPageData, image) => {
try {
const statusPage = new StatusPage({ ...statusPageData });
if (image) {
statusPage.logo = {
data: image.buffer,
contentType: image.mimetype,
};
}
await statusPage.save();
return statusPage;
} catch (error) {
@@ -20,16 +27,115 @@ const createStatusPage = async (statusPageData) => {
}
};
const getStatusPageByUrl = async (url) => {
const updateStatusPage = async (statusPageData, image) => {
try {
const statusPage = await StatusPage.findOne({ url });
if (statusPage === null || statusPage === undefined) {
if (image) {
statusPageData.logo = {
data: image.buffer,
contentType: image.mimetype,
};
}
const statusPage = await StatusPage.findOneAndUpdate({}, statusPageData, {
new: true,
});
return statusPage;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "updateStatusPage";
throw error;
}
};
const getStatusPage = async () => {
try {
const statusPageQuery = await StatusPage.aggregate([
{ $limit: 1 },
{
$set: {
originalMonitors: "$monitors",
},
},
{
$lookup: {
from: "monitors",
localField: "monitors",
foreignField: "_id",
as: "monitors",
},
},
{
$unwind: "$monitors",
},
{
$lookup: {
from: "checks",
let: { monitorId: "$monitors._id" },
pipeline: [
{
$match: {
$expr: { $eq: ["$monitorId", "$$monitorId"] },
},
},
{ $sort: { createdAt: -1 } },
{ $limit: 25 },
],
as: "monitors.checks",
},
},
{
$addFields: {
"monitors.orderIndex": {
$indexOfArray: ["$originalMonitors", "$monitors._id"],
},
},
},
{
$group: {
_id: "$_id",
statusPage: { $first: "$$ROOT" },
monitors: { $push: "$monitors" },
},
},
{
$project: {
statusPage: {
_id: 1,
color: 1,
companyName: 1,
isPublished: 1,
logo: 1,
originalMonitors: 1,
showCharts: 1,
showUptimePercentage: 1,
timezone: 1,
url: 1,
},
monitors: {
$sortArray: {
input: "$monitors",
sortBy: { orderIndex: 1 },
},
},
},
},
]);
if (!statusPageQuery.length) {
const error = new Error(errorMessages.STATUS_PAGE_NOT_FOUND);
error.status = 404;
throw error;
}
return statusPage;
const { statusPage, monitors } = statusPageQuery[0];
const normalizedMonitors = monitors.map((monitor) => {
return {
...monitor,
checks: NormalizeData(monitor.checks, 10, 100),
};
});
return { statusPage, monitors: normalizedMonitors };
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getStatusPageByUrl";
@@ -37,4 +143,14 @@ const getStatusPageByUrl = async (url) => {
}
};
export { createStatusPage, getStatusPageByUrl };
const deleteStatusPage = async () => {
try {
await StatusPage.deleteOne({});
} catch (error) {
error.service = SERVICE_NAME;
error.method = "createStatusPage";
throw error;
}
};
export { createStatusPage, updateStatusPage, getStatusPage, deleteStatusPage };