diff --git a/server/src/db/models/Check.ts b/server/src/db/models/Check.ts index 7bd1cec6f..d26093be8 100644 --- a/server/src/db/models/Check.ts +++ b/server/src/db/models/Check.ts @@ -11,6 +11,8 @@ import type { CheckMemoryInfo, CheckMetadata, CheckNetworkInterfaceInfo, + GeoCheckResult, + GeoCheckTimings, GotTimings, ILighthouseAudit, } from "@/types/check.js"; @@ -175,6 +177,34 @@ const auditsSchema = new Schema( { _id: false } ); +const geoCheckTimingsSchema = new Schema( + { + total: { type: Number, required: true }, + dns: { type: Number }, + tcp: { type: Number }, + tls: { type: Number }, + firstByte: { type: Number }, + download: { type: Number }, + }, + { _id: false } +); + +const geoCheckResultSchema = new Schema( + { + continent: { type: String, required: true }, + region: { type: String }, + country: { type: String, required: true }, + state: { type: String }, + city: { type: String, required: true }, + longitude: { type: Number, required: true }, + latitude: { type: Number, required: true }, + status: { type: Boolean, required: true }, + statusCode: { type: Number, required: true }, + timings: { type: geoCheckTimingsSchema, required: true }, + }, + { _id: false } +); + const metadataSchema = new Schema( { monitorId: { @@ -281,6 +311,10 @@ const CheckSchema = new Schema( type: auditsSchema, default: undefined, }, + geoResults: { + type: [geoCheckResultSchema], + default: undefined, + }, }, { timestamps: true, diff --git a/server/src/db/models/Monitor.ts b/server/src/db/models/Monitor.ts index a459cdf3e..145189e35 100644 --- a/server/src/db/models/Monitor.ts +++ b/server/src/db/models/Monitor.ts @@ -1,6 +1,6 @@ import { Schema, model, Types, type UpdateQuery } from "mongoose"; import type { Monitor, MonitorMatchMethod, CheckSnapshot } from "@/types/monitor.js"; -import { MonitorTypes, MonitorStatuses } from "@/types/monitor.js"; +import { MonitorTypes, MonitorStatuses, GeoCheckLocations } from "@/types/monitor.js"; type CheckSnapshotDocument = Omit & { createdAt: Date }; @@ -169,6 +169,19 @@ const MonitorSchema = new Schema( return value && value.trim() ? value.trim() : null; }, }, + geoCheckEnabled: { + type: Boolean, + default: false, + }, + geoCheckLocations: { + type: [String], + enum: GeoCheckLocations, + default: [], + }, + geoCheckInterval: { + type: Number, + default: 5, + }, recentChecks: { type: [checkSnapshotSchema], default: [], diff --git a/server/src/repositories/checks/MongoChecksRepistory.ts b/server/src/repositories/checks/MongoChecksRepistory.ts index a03472b4c..fe3be0670 100644 --- a/server/src/repositories/checks/MongoChecksRepistory.ts +++ b/server/src/repositories/checks/MongoChecksRepistory.ts @@ -10,6 +10,8 @@ import type { CheckMemoryInfo, CheckMetadata, CheckNetworkInterfaceInfo, + GeoCheckResult, + GeoCheckTimings, GotTimings, MonitorType, } from "@/types/index.js"; @@ -165,6 +167,33 @@ class MongoChecksRepository implements IChecksRepository { }; }; + const mapGeoTimings = (timings?: GeoCheckTimings): GeoCheckTimings => ({ + total: timings?.total ?? 0, + dns: timings?.dns, + tcp: timings?.tcp, + tls: timings?.tls, + firstByte: timings?.firstByte, + download: timings?.download, + }); + + const mapGeoResults = (geoResults?: GeoCheckResult[]): GeoCheckResult[] | undefined => { + if (!geoResults?.length) { + return undefined; + } + return geoResults.map((result) => ({ + continent: result.continent ?? "", + region: result.region, + country: result.country ?? "", + state: result.state, + city: result.city ?? "", + longitude: result.longitude ?? 0, + latitude: result.latitude ?? 0, + status: result.status ?? false, + statusCode: result.statusCode ?? 0, + timings: mapGeoTimings(result.timings), + })); + }; + const mapMetadata = (metadata: CheckDocument["metadata"]): CheckMetadata => ({ monitorId: toStringId(metadata.monitorId), teamId: toStringId(metadata.teamId), @@ -194,6 +223,7 @@ class MongoChecksRepository implements IChecksRepository { seo: doc.seo, performance: doc.performance, audits: mapAudits(doc.audits), + geoResults: mapGeoResults(doc.geoResults), __v: doc.__v ?? 0, createdAt: toDateString(doc.createdAt), updatedAt: toDateString(doc.updatedAt), diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 4ae4394d4..6fb068484 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -353,6 +353,9 @@ class MongoMonitorsRepository implements IMonitorsRepository { selectedDisks: doc.selectedDisks ?? [], gameId: doc.gameId ?? undefined, group: doc.group ?? null, + geoCheckEnabled: doc.geoCheckEnabled ?? false, + geoCheckLocations: doc.geoCheckLocations ?? [], + geoCheckInterval: doc.geoCheckInterval ?? 5, recentChecks: (doc.recentChecks ?? []).map((check: any) => this.toCheckSnapshot(check)), createdAt: toDateString(doc.createdAt), updatedAt: toDateString(doc.updatedAt), @@ -408,6 +411,9 @@ class MongoMonitorsRepository implements IMonitorsRepository { selectedDisks: doc.selectedDisks ?? [], gameId: doc.gameId ?? undefined, group: doc.group ?? null, + geoCheckEnabled: doc.geoCheckEnabled ?? false, + geoCheckLocations: doc.geoCheckLocations ?? [], + geoCheckInterval: doc.geoCheckInterval ?? 5, recentChecks: (doc.recentChecks ?? []).map((check: any) => this.toCheckSnapshot(check)), createdAt: toDateString(doc.createdAt), updatedAt: toDateString(doc.updatedAt), diff --git a/server/src/types/check.ts b/server/src/types/check.ts index 6c4c26445..98f8a0c34 100644 --- a/server/src/types/check.ts +++ b/server/src/types/check.ts @@ -90,6 +90,28 @@ export interface ILighthouseAudit { numericUnit?: string; } +export interface GeoCheckTimings { + total: number; + dns?: number; + tcp?: number; + tls?: number; + firstByte?: number; + download?: number; +} + +export interface GeoCheckResult { + continent: string; + region?: string; + country: string; + state?: string; + city: string; + longitude: number; + latitude: number; + status: boolean; + statusCode: number; + timings: GeoCheckTimings; +} + export interface Check { id: string; metadata: CheckMetadata; @@ -113,6 +135,7 @@ export interface Check { seo?: number; performance?: number; audits?: CheckAudits; + geoResults?: GeoCheckResult[]; __v: number; createdAt: string; updatedAt: string; diff --git a/server/src/types/monitor.ts b/server/src/types/monitor.ts index ac7ca02d0..9e285a57a 100644 --- a/server/src/types/monitor.ts +++ b/server/src/types/monitor.ts @@ -7,6 +7,9 @@ export type MonitorType = (typeof MonitorTypes)[number]; export const MonitorStatuses = ["up", "down", "paused", "initializing", "maintenance", "breached"] as const; export type MonitorStatus = (typeof MonitorStatuses)[number]; +export const GeoCheckLocations = ["EU", "NA", "AS", "SA", "AF", "OC"] as const; +export type GeoCheckLocation = (typeof GeoCheckLocations)[number]; + export type MonitorMatchMethod = "equal" | "include" | "regex" | ""; export interface Monitor { @@ -43,6 +46,9 @@ export interface Monitor { selectedDisks: string[]; gameId?: string; group: string | null; + geoCheckEnabled?: boolean; + geoCheckLocations?: GeoCheckLocation[]; + geoCheckInterval?: number; recentChecks: CheckSnapshot[]; createdAt: string; updatedAt: string;