Resolved merge conflict in Server/index.js
This commit is contained in:
commit
e9bcf66b29
99 files changed
+5354
-358
No files matched your search
@@ -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 });
|
||||
|
||||
@@ -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 }
|
||||
);
|
||||
|
||||
@@ -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 };
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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 };
|
||||
Reference in new issue
Block a user