diff --git a/client/src/Types/Check.ts b/client/src/Types/Check.ts index c69fe7972..68b932267 100644 --- a/client/src/Types/Check.ts +++ b/client/src/Types/Check.ts @@ -160,6 +160,14 @@ export interface PageSpeedGroupedCheck { totalChecks: number; } +export interface GroupedGeoCheck { + bucketDate: string; + continent: string; + avgResponseTime: number; + totalChecks: number; + uptimePercentage: number; +} + export interface LatestCheck { status: boolean; responseTime: number; @@ -236,6 +244,7 @@ export interface UptimeChecksResult { groupedDownChecks: GroupedCheck[]; uptimePercentage: number; avgResponseTime: number; + groupedGeoChecks?: GroupedGeoCheck[]; } export interface ChecksSummary { diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index cec4ee593..c0e2edb12 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -180,7 +180,7 @@ const MonitorSchema = new Schema( }, geoCheckInterval: { type: Number, - default: 5, + default: 300000, }, recentChecks: { type: [checkSnapshotSchema], diff --git a/server/src/repositories/checks/MongoChecksRepistory.ts b/server/src/repositories/checks/MongoChecksRepistory.ts index fe3be0670..12dfcab35 100644 --- a/server/src/repositories/checks/MongoChecksRepistory.ts +++ b/server/src/repositories/checks/MongoChecksRepistory.ts @@ -532,12 +532,41 @@ class MongoChecksRepository implements IChecksRepository { { $sort: { _id: 1 } }, { $project: { bucketDate: "$_id", avgResponseTime: 1, totalChecks: 1, _id: 0 } }, ], + groupedGeoChecks: [ + { $match: { geoResults: { $exists: true, $ne: null, $not: { $size: 0 } } } }, + { $unwind: "$geoResults" }, + { + $group: { + _id: { + date: { $dateToString: { format: dateString, date: "$createdAt" } }, + continent: "$geoResults.continent", + }, + avgResponseTime: { $avg: "$geoResults.timings.total" }, + totalChecks: { $sum: 1 }, + upChecks: { $sum: { $cond: [{ $eq: ["$geoResults.status", true] }, 1, 0] } }, + }, + }, + { + $project: { + _id: 0, + bucketDate: "$_id.date", + continent: "$_id.continent", + avgResponseTime: 1, + totalChecks: 1, + uptimePercentage: { + $cond: [{ $eq: ["$totalChecks", 0] }, 0, { $divide: ["$upChecks", "$totalChecks"] }], + }, + }, + }, + { $sort: { bucketDate: 1, continent: 1 } }, + ], }, }, ]); const uptimePercentage = result?.uptimePercentage?.[0]?.percentage ?? 0; const avgResponseTime = result?.groupedAvgResponseTime?.[0]?.avgResponseTime ?? 0; + const groupedGeoChecks = result?.groupedGeoChecks ?? []; return { monitorType, @@ -546,6 +575,7 @@ class MongoChecksRepository implements IChecksRepository { groupedDownChecks: result?.groupedDownChecks ?? [], uptimePercentage, avgResponseTime, + groupedGeoChecks, }; }; diff --git a/server/src/types/check.ts b/server/src/types/check.ts index 98f8a0c34..34a7d3584 100644 --- a/server/src/types/check.ts +++ b/server/src/types/check.ts @@ -202,6 +202,14 @@ export interface PageSpeedGroupedCheck { totalChecks: number; } +export interface GroupedGeoCheck { + bucketDate: string; + continent: string; + avgResponseTime: number; + totalChecks: number; + uptimePercentage: number; +} + export interface UptimeChecksResult { monitorType: Exclude; groupedChecks: GroupedCheck[]; @@ -209,6 +217,7 @@ export interface UptimeChecksResult { groupedDownChecks: GroupedCheck[]; uptimePercentage: number; avgResponseTime: number; + groupedGeoChecks?: GroupedGeoCheck[]; } export interface ChecksSummary { diff --git a/server/src/validation/joi.ts b/server/src/validation/joi.ts index 912767587..749902e39 100755 --- a/server/src/validation/joi.ts +++ b/server/src/validation/joi.ts @@ -1,5 +1,6 @@ import joi, { type CustomHelpers } from "joi"; import { type UserRole, UserRoles } from "@/types/user.js"; +import { GeoCheckLocations } from "@/types/monitor.js"; //**************************************** // Custom Validators @@ -172,6 +173,12 @@ const createMonitorBodyValidation = joi.object({ gameId: joi.string().allow(""), selectedDisks: joi.array().items(joi.string()).optional(), group: joi.string().max(50).trim().allow(null, "").optional(), + geoCheckEnabled: joi.boolean().optional(), + geoCheckLocations: joi + .array() + .items(joi.string().valid(...GeoCheckLocations)) + .optional(), + geoCheckInterval: joi.number().min(300000).optional(), }); const createMonitorsBodyValidation = joi.array().items( @@ -203,6 +210,12 @@ const editMonitorBodyValidation = joi gameId: joi.string().allow(""), selectedDisks: joi.array().items(joi.string()).optional(), group: joi.string().max(50).trim().allow(null, "").optional(), + geoCheckEnabled: joi.boolean().optional(), + geoCheckLocations: joi + .array() + .items(joi.string().valid(...GeoCheckLocations)) + .optional(), + geoCheckInterval: joi.number().min(5).optional(), }) .options({ stripUnknown: true });