From ec82efebb47bd4a34e89c0acc5700b0f29631c83 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 5 Mar 2026 17:54:16 +0000 Subject: [PATCH] pagespeed provider, hardware provider --- server/src/config/services.ts | 9 ++- .../network/HardwareProvider.ts | 29 ++++++++++ .../infrastructure/network/HttpProvider.ts | 4 +- .../network/PageSpeedProvider.ts | 55 +++++++++++++++++++ .../service/infrastructure/networkService.ts | 11 +++- 5 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 server/src/service/infrastructure/network/HardwareProvider.ts create mode 100644 server/src/service/infrastructure/network/PageSpeedProvider.ts diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 485297fe0..11e795feb 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -78,6 +78,8 @@ import { EnvConfig } from "@/service/system/settingsService.js"; import { PingProvider } from "@/service/infrastructure/network/PingProvider.js"; import { HttpProvider } from "@/service/infrastructure/network/HttpProvider.js"; import { AdvancedMatcher } from "@/service/infrastructure/network/AdvancedMatcher.js"; +import { PageSpeedProvider } from "@/service/infrastructure/network/PageSpeedProvider.js"; +import { HardwareProvider } from "@/service/infrastructure/network/HardwareProvider.js"; export type InitializedServices = { settingsService: any; @@ -151,7 +153,8 @@ export const initializeServices = async ({ const pingProvider = new PingProvider(ping); const httpProvider = new HttpProvider(got, new AdvancedMatcher(jmespath)); - + const pageSpeedProvider = new PageSpeedProvider(httpProvider, settingsService, logger); + const hardwareProvider = new HardwareProvider(httpProvider); const networkService = new NetworkService( axios, got, @@ -168,7 +171,9 @@ export const initializeServices = async ({ grpc, protoLoader, pingProvider, - httpProvider + httpProvider, + pageSpeedProvider, + hardwareProvider ); const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger); diff --git a/server/src/service/infrastructure/network/HardwareProvider.ts b/server/src/service/infrastructure/network/HardwareProvider.ts new file mode 100644 index 000000000..a9180381e --- /dev/null +++ b/server/src/service/infrastructure/network/HardwareProvider.ts @@ -0,0 +1,29 @@ +import { IStatusProvider } from "@/service/infrastructure/network/IStatusProvider.js"; +import { HardwareStatusPayload, MonitorStatusResponse } from "@/types/network.js"; +import { Monitor, MonitorType } from "@/types/monitor.js"; +import { HttpProvider } from "@/service/infrastructure/network/HttpProvider.js"; +import { AppError } from "@/utils/AppError.js"; + +export class HardwareProvider implements IStatusProvider { + readonly type = "hardware"; + constructor(private httpProvider: HttpProvider) {} + + supports(type: MonitorType) { + return type === "hardware"; + } + + async handle(monitor: Monitor): Promise> { + const { url } = monitor; + try { + if (!url) throw new Error("URL is required for Hardware monitor"); + return await this.httpProvider.handle(monitor); + } catch (err: unknown) { + throw new AppError({ + message: err instanceof Error ? err.message : "Error performing Hardware request", + service: "HardwareProvider", + method: "handle", + details: { url: monitor.url }, + }); + } + } +} diff --git a/server/src/service/infrastructure/network/HttpProvider.ts b/server/src/service/infrastructure/network/HttpProvider.ts index b47160e06..e373e2cff 100644 --- a/server/src/service/infrastructure/network/HttpProvider.ts +++ b/server/src/service/infrastructure/network/HttpProvider.ts @@ -4,7 +4,7 @@ import { IStatusProvider } from "@/service/infrastructure/network/IStatusProvide import { HttpStatusPayload } from "@/types/network.js"; import { MonitorStatusResponse } from "@/types/network.js"; import { Agent as HttpsAgent } from "https"; -import { Monitor } from "@/types/monitor.js"; +import { Monitor, MonitorType } from "@/types/monitor.js"; import { NETWORK_ERROR } from "@/service/infrastructure/network/utils.js"; export class HttpProvider implements IStatusProvider { @@ -15,7 +15,7 @@ export class HttpProvider implements IStatusProvider { private advancedMatcher: AdvancedMatcher ) {} - supports(type: string) { + supports(type: MonitorType) { return type === "http"; } diff --git a/server/src/service/infrastructure/network/PageSpeedProvider.ts b/server/src/service/infrastructure/network/PageSpeedProvider.ts new file mode 100644 index 000000000..121fe9bf8 --- /dev/null +++ b/server/src/service/infrastructure/network/PageSpeedProvider.ts @@ -0,0 +1,55 @@ +import { IStatusProvider } from "@/service/infrastructure/network/IStatusProvider.js"; +import { MonitorStatusResponse, PageSpeedStatusPayload } from "@/types/network.js"; +import { Monitor, MonitorType } from "@/types/monitor.js"; +import { HttpProvider } from "@/service/infrastructure/network/HttpProvider.js"; +import { ISettingsService } from "@/service/system/settingsService.js"; +import { ILogger } from "@/utils/logger.js"; +import { AppError } from "@/utils/AppError.js"; + +export class PageSpeedProvider implements IStatusProvider { + readonly type = "pagespeed"; + constructor( + private httpProvider: HttpProvider, + private settingsService: ISettingsService, + private logger: ILogger + ) {} + + supports(type: MonitorType) { + return type === "pagespeed"; + } + + async handle(monitor: Monitor): Promise> { + const { url } = monitor; + try { + if (!url) throw new Error("URL is required for PageSpeed monitor"); + const dbSettings = await this.settingsService.getDBSettings(); + const apiKey = dbSettings?.pagespeedApiKey; + let pageSpeedUrl = `https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent( + url + )}&category=seo&category=accessibility&category=best-practices&category=performance`; + + if (apiKey) { + pageSpeedUrl += `&key=${apiKey}`; + } else { + this.logger.warn({ + message: "PageSpeed API key not found, performance may be throttled", + service: "PageSpeedProvider", + method: "handle", + details: { url }, + }); + } + + return await this.httpProvider.handle({ + ...monitor, + url: pageSpeedUrl, + }); + } catch (err: unknown) { + throw new AppError({ + message: err instanceof Error ? err.message : "Error performing PageSpeed request", + service: "PageSpeedProvider", + method: "handle", + details: { url: monitor.url }, + }); + } + } +} diff --git a/server/src/service/infrastructure/networkService.ts b/server/src/service/infrastructure/networkService.ts index 2515b6145..539a1f8c2 100644 --- a/server/src/service/infrastructure/networkService.ts +++ b/server/src/service/infrastructure/networkService.ts @@ -97,6 +97,8 @@ class NetworkService implements INetworkService { // New providers private pingProvider; private httpProvider; + private pageSpeedProvider; + private hardwareProvider; private buildStatusResponse = ({ monitor, @@ -168,7 +170,9 @@ class NetworkService implements INetworkService { // New providers pingProvider: IStatusProvider, - httpProvider: IStatusProvider + httpProvider: IStatusProvider, + pagespeedProvider: IStatusProvider, + hardwareProvider: IStatusProvider ) { this.TYPE_PING = "ping"; this.TYPE_HTTP = "http"; @@ -196,7 +200,8 @@ class NetworkService implements INetworkService { // New providers this.pingProvider = pingProvider; this.httpProvider = httpProvider; - + this.pageSpeedProvider = pagespeedProvider; + this.hardwareProvider = hardwareProvider; const cacheable = new CacheableLookup(); this.got = got.extend({ @@ -247,7 +252,7 @@ class NetworkService implements INetworkService { case this.TYPE_HTTP: return await this.httpProvider.handle(monitor); case this.TYPE_PAGESPEED: - return await this.requestPageSpeed(monitor); + return await this.pageSpeedProvider.handle(monitor); case this.TYPE_HARDWARE: return await this.requestHardware(monitor); case this.TYPE_DOCKER: