feat: 将 demo 项目转化为 HTTP 拨测监控工具
新增 YAML 配置解析(Bun 内置 YAML)、SQLite 数据存储(bun:sqlite)、按 interval 分组并发拨测引擎、REST API(/api/summary、/api/targets、/api/targets/:id/history、/api/targets/:id/trend)、React 前端 Dashboard(统计卡片、目标表格、可展开详情面板、recharts 趋势图)。CLI 简化为仅接受配置文件路径。移除 /api/demo 路由和相关 demo 代码。保留 /health、静态资源服务和 SPA fallback。
This commit is contained in:
65
src/server/checker/fetcher.ts
Normal file
65
src/server/checker/fetcher.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { CheckResult, ExpectConfig, ResolvedTarget } from "./types";
|
||||
|
||||
export async function fetchTarget(target: ResolvedTarget): Promise<CheckResult> {
|
||||
const timestamp = new Date().toISOString();
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), target.timeoutMs);
|
||||
|
||||
try {
|
||||
const start = performance.now();
|
||||
|
||||
const response = await fetch(target.url, {
|
||||
method: target.method,
|
||||
headers: target.headers,
|
||||
body: target.method !== "GET" && target.method !== "HEAD" ? target.body : undefined,
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
const latencyMs = Math.round(performance.now() - start);
|
||||
const body = await response.text();
|
||||
|
||||
const matched = checkExpect(response.status, body, latencyMs, target.expect);
|
||||
|
||||
return {
|
||||
targetName: target.name,
|
||||
timestamp,
|
||||
success: true,
|
||||
statusCode: response.status,
|
||||
latencyMs,
|
||||
error: null,
|
||||
matched,
|
||||
};
|
||||
} catch (error) {
|
||||
const isTimeout = error instanceof DOMException && error.name === "AbortError";
|
||||
|
||||
return {
|
||||
targetName: target.name,
|
||||
timestamp,
|
||||
success: false,
|
||||
statusCode: null,
|
||||
latencyMs: null,
|
||||
error: isTimeout ? `请求超时 (${target.timeoutMs}ms)` : (error instanceof Error ? error.message : String(error)),
|
||||
matched: false,
|
||||
};
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkExpect(statusCode: number, body: string, latencyMs: number, expect?: ExpectConfig): boolean {
|
||||
if (!expect) return true;
|
||||
|
||||
if (expect.status && !expect.status.includes(statusCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expect.bodyContains && !body.includes(expect.bodyContains)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expect.maxLatencyMs !== undefined && latencyMs > expect.maxLatencyMs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user