Merge branch 'develop' into feat/customcss-status-page
This commit is contained in:
107 files changed
+5625
-4569
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { IWorker } from "@/worker/worker.interface.js";
|
||||
import { IJobScheduler } from "@/worker/worker.interface.js";
|
||||
import { getQueueJobsQueryValidation } from "@/api/validation/queueValidation.js";
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
@@ -13,10 +13,7 @@ export interface IJobQueueController {
|
||||
|
||||
class JobQueueController implements IJobQueueController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private worker: IWorker;
|
||||
constructor(worker: IWorker) {
|
||||
this.worker = worker;
|
||||
}
|
||||
constructor(private scheduler: IJobScheduler) {}
|
||||
|
||||
get serviceName() {
|
||||
return JobQueueController.SERVICE_NAME;
|
||||
@@ -24,7 +21,7 @@ class JobQueueController implements IJobQueueController {
|
||||
|
||||
getMetrics = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const metrics = await this.worker.getMetrics();
|
||||
const metrics = await this.scheduler.getMetrics();
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
msg: "Queue metrics fetched successfully",
|
||||
@@ -38,7 +35,7 @@ class JobQueueController implements IJobQueueController {
|
||||
getJobs = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const pagination = getQueueJobsQueryValidation.parse(req.query);
|
||||
const { jobs, count } = await this.worker.getJobs(pagination);
|
||||
const { jobs, count } = await this.scheduler.getJobs(pagination);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Queue jobs fetched successfully",
|
||||
@@ -52,8 +49,8 @@ class JobQueueController implements IJobQueueController {
|
||||
getAllMetrics = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const pagination = getQueueJobsQueryValidation.parse(req.query);
|
||||
const { jobs, count } = await this.worker.getJobs(pagination);
|
||||
const metrics = await this.worker.getMetrics();
|
||||
const { jobs, count } = await this.scheduler.getJobs(pagination);
|
||||
const metrics = await this.scheduler.getMetrics();
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Queue metrics fetched successfully",
|
||||
@@ -66,7 +63,7 @@ class JobQueueController implements IJobQueueController {
|
||||
|
||||
flushQueue = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const result = await this.worker.flushQueues();
|
||||
const result = await this.scheduler.flushQueues();
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: "Queue flushed successfully",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { MulterError } from "multer";
|
||||
import { logger } from "@/utils/logger.js";
|
||||
import type { ILogger } from "@/utils/logger.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
// Multer throws MulterError, send 413 Payload Too Large / 400
|
||||
const multerErrorStatus = (error: MulterError): number => (error.code === "LIMIT_FILE_SIZE" ? 413 : 400);
|
||||
|
||||
const handleErrors = (error: unknown, req: Request, res: Response, _next: NextFunction) => {
|
||||
const handleErrors = (logger: ILogger) => (error: unknown, req: Request, res: Response, _next: NextFunction) => {
|
||||
const status = error instanceof MulterError ? multerErrorStatus(error) : error instanceof AppError ? error.status || 500 : 500;
|
||||
const message = error instanceof AppError ? error.message : error instanceof Error ? error.message : "Server error";
|
||||
const service = error instanceof AppError ? error.service : error instanceof MulterError ? "uploadMiddleware" : "unknownService";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { booleanCoercion, dnsHostnameRegex, dnsServerValidation } from "./shared
|
||||
import { GeoContinents } from "@/domain/geo-checks/geo-check.type.js";
|
||||
import {
|
||||
DnsRecordTypes,
|
||||
HttpMethods,
|
||||
HttpStatusCodeSet,
|
||||
MonitorMatchMethods,
|
||||
MonitorStatuses,
|
||||
@@ -70,6 +71,16 @@ const refineStrategyType = (body: { type?: string; strategy?: string }, ctx: z.R
|
||||
}
|
||||
};
|
||||
|
||||
const refineHeadMatching = (body: { method?: string; useAdvancedMatching?: boolean; jsonPath?: string }, ctx: z.RefinementCtx) => {
|
||||
if (body.method === "HEAD" && (body.useAdvancedMatching === true || (body.jsonPath ?? "") !== "")) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
path: ["method"],
|
||||
message: "HEAD requests have no response body, so they cannot use advanced matching or a JSON path",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const createMonitorBodyValidation = z
|
||||
.object({
|
||||
_id: z.string().optional(),
|
||||
@@ -95,6 +106,7 @@ export const createMonitorBodyValidation = z
|
||||
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
||||
expectedValue: z.union([z.string(), z.literal("")]).optional(),
|
||||
matchMethod: z.union([z.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||
method: z.enum(HttpMethods).optional(),
|
||||
gameId: z.union([z.string(), z.literal("")]).optional(),
|
||||
grpcServiceName: z.union([z.string(), z.literal("")]).default(""),
|
||||
strategy: z.enum(PageSpeedStrategies).optional(),
|
||||
@@ -107,7 +119,8 @@ export const createMonitorBodyValidation = z
|
||||
dnsRecordType: z.enum(DnsRecordTypes).optional(),
|
||||
})
|
||||
.superRefine(refineDnsHostname)
|
||||
.superRefine(refineStrategyType);
|
||||
.superRefine(refineStrategyType)
|
||||
.superRefine(refineHeadMatching);
|
||||
|
||||
export const editMonitorBodyValidation = z
|
||||
.object({
|
||||
@@ -127,6 +140,7 @@ export const editMonitorBodyValidation = z
|
||||
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
||||
expectedValue: z.union([z.string(), z.literal("")]).optional(),
|
||||
matchMethod: z.union([z.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||
method: z.enum(HttpMethods).optional(),
|
||||
port: z.number().min(1).max(65535).optional(),
|
||||
cpuAlertThreshold: z.number().optional(),
|
||||
memoryAlertThreshold: z.number().optional(),
|
||||
@@ -144,7 +158,8 @@ export const editMonitorBodyValidation = z
|
||||
dnsRecordType: z.enum(DnsRecordTypes).optional(),
|
||||
})
|
||||
.superRefine(refineDnsHostname)
|
||||
.superRefine(refineStrategyType);
|
||||
.superRefine(refineStrategyType)
|
||||
.superRefine(refineHeadMatching);
|
||||
|
||||
export const pauseMonitorParamValidation = z.object({
|
||||
monitorId: z.string().min(1, "Monitor ID is required"),
|
||||
@@ -184,6 +199,7 @@ const importedMonitorSchema = z
|
||||
jsonPath: z.union([z.string(), z.literal("")]).optional(),
|
||||
expectedValue: z.union([z.string(), z.literal("")]).optional(),
|
||||
matchMethod: z.union([z.enum(MonitorMatchMethods), z.literal("")]).optional(),
|
||||
method: z.enum(HttpMethods).optional().default("GET"),
|
||||
url: z.string().min(1, "URL is required"),
|
||||
port: z.number().optional(),
|
||||
isActive: z.boolean().default(true),
|
||||
@@ -215,7 +231,8 @@ const importedMonitorSchema = z
|
||||
updatedAt: z.string().optional(),
|
||||
})
|
||||
.superRefine(refineDnsHostname)
|
||||
.superRefine(refineStrategyType);
|
||||
.superRefine(refineStrategyType)
|
||||
.superRefine(refineHeadMatching);
|
||||
|
||||
export const importMonitorsBodyValidation = z.object({
|
||||
monitors: z.array(importedMonitorSchema).min(1, "At least one monitor is required"),
|
||||
@@ -251,6 +268,7 @@ export const monitorResponseSchema = z
|
||||
jsonPath: z.string().optional(),
|
||||
expectedValue: z.string().optional(),
|
||||
matchMethod: z.enum(MonitorMatchMethods).optional(),
|
||||
method: z.enum(HttpMethods),
|
||||
notifications: z.array(z.string()),
|
||||
tags: z.array(z.string()),
|
||||
customUpCodes: z.array(httpStatusCode).optional(),
|
||||
@@ -272,5 +290,6 @@ export const monitorResponseSchema = z
|
||||
userId: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
lastEvaluatedAt: z.number(),
|
||||
})
|
||||
.passthrough();
|
||||
Reference in new issue
Block a user