1
0

refactor: 项目更名为 DiAL(统一拨测平台)

将 gateway-checker/Gateway Checker 统一替换为 dial-server/DiAL
- 包名、可执行文件名、API service 标识改为 dial-server
- UI 标题改为 DiAL,副标题改为统一拨测平台
- 同步更新测试断言、构建脚本、示例配置和文档
This commit is contained in:
2026-05-11 22:23:17 +08:00
parent 767f26617e
commit 3fa1b3957e
13 changed files with 25 additions and 25 deletions

View File

@@ -1,4 +1,4 @@
# Gateway Checker # DiAL
基于 Bun + TypeScript 的多类型拨测监控工具。通过 YAML 配置文件定义 HTTP 和命令行拨测目标,后端按配置定时并发拨测,结果持久化到本地 SQLite前端 Dashboard 展示各目标实时状态、可用率、耗时趋势等。 基于 Bun + TypeScript 的多类型拨测监控工具。通过 YAML 配置文件定义 HTTP 和命令行拨测目标,后端按配置定时并发拨测,结果持久化到本地 SQLite前端 Dashboard 展示各目标实时状态、可用率、耗时趋势等。
@@ -233,12 +233,12 @@ bun run build
1. 运行 `vite build`,输出前端资源到 `dist/web` 1. 运行 `vite build`,输出前端资源到 `dist/web`
2. 生成临时 `.build/static-assets.ts`,嵌入 Vite 产物 2. 生成临时 `.build/static-assets.ts`,嵌入 Vite 产物
3. 生成临时 `.build/server-entry.ts`,作为生产入口 3. 生成临时 `.build/server-entry.ts`,作为生产入口
4. 运行 `Bun.build({ compile })`,输出 `dist/gateway-checker` 4. 运行 `Bun.build({ compile })`,输出 `dist/dial-server`
运行 executable 运行 executable
```bash ```bash
./dist/gateway-checker probes.yaml ./dist/dial-server probes.yaml
``` ```
## 运行参数 ## 运行参数
@@ -246,7 +246,7 @@ bun run build
CLI 只接受一个参数YAML 配置文件路径。 CLI 只接受一个参数YAML 配置文件路径。
```bash ```bash
./dist/gateway-checker ./probes.yaml ./dist/dial-server ./probes.yaml
``` ```
## 测试 ## 测试

View File

@@ -27,7 +27,7 @@
系统 SHALL 通过单一命令行参数接受 YAML 配置文件路径。 系统 SHALL 通过单一命令行参数接受 YAML 配置文件路径。
#### Scenario: 指定配置文件启动 #### Scenario: 指定配置文件启动
- **WHEN** 用户执行 `./gateway-checker ./probes.yaml` - **WHEN** 用户执行 `./dial-server ./probes.yaml`
- **THEN** 系统 SHALL 读取并解析指定路径的 YAML 文件作为配置 - **THEN** 系统 SHALL 读取并解析指定路径的 YAML 文件作为配置
#### Scenario: 未提供配置文件路径 #### Scenario: 未提供配置文件路径

View File

@@ -1,5 +1,5 @@
{ {
"name": "gateway-checker", "name": "dial-server",
"type": "module", "type": "module",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -99,13 +99,13 @@ targets:
http: http:
url: "https://httpbin.org/headers" url: "https://httpbin.org/headers"
headers: headers:
X-Custom-Header: "gateway-checker" X-Custom-Header: "dial-server"
expect: expect:
status: [200] status: [200]
body: body:
- json: - json:
path: "$.headers.X-Custom-Header" path: "$.headers.X-Custom-Header"
equals: "gateway-checker" equals: "dial-server"
- name: "响应头自定义校验" - name: "响应头自定义校验"
type: http type: http

View File

@@ -5,7 +5,7 @@ import { $ } from "bun";
const buildDir = fileURLToPath(new URL("../.build/", import.meta.url)); const buildDir = fileURLToPath(new URL("../.build/", import.meta.url));
const webDistDir = fileURLToPath(new URL("../dist/web/", import.meta.url)); const webDistDir = fileURLToPath(new URL("../dist/web/", import.meta.url));
const executablePath = fileURLToPath(new URL("../dist/gateway-checker", import.meta.url)); const executablePath = fileURLToPath(new URL("../dist/dial-server", import.meta.url));
const generatedAssetsPath = fileURLToPath(new URL("../.build/static-assets.ts", import.meta.url)); const generatedAssetsPath = fileURLToPath(new URL("../.build/static-assets.ts", import.meta.url));
const generatedEntryPath = fileURLToPath(new URL("../.build/server-entry.ts", import.meta.url)); const generatedEntryPath = fileURLToPath(new URL("../.build/server-entry.ts", import.meta.url));

View File

@@ -5,11 +5,11 @@ import { join } from "node:path";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import type { HealthResponse, SummaryResponse } from "../src/shared/api"; import type { HealthResponse, SummaryResponse } from "../src/shared/api";
const executablePath = process.argv[2] ?? fileURLToPath(new URL("../dist/gateway-checker", import.meta.url)); const executablePath = process.argv[2] ?? fileURLToPath(new URL("../dist/dial-server", import.meta.url));
await assertExecutableExists(executablePath); await assertExecutableExists(executablePath);
const tempDir = mkdtempSync(join(tmpdir(), "gc-smoke-")); const tempDir = mkdtempSync(join(tmpdir(), "dial-smoke-"));
const configPath = join(tempDir, "probes.yaml"); const configPath = join(tempDir, "probes.yaml");
const port = await getFreePort(); const port = await getFreePort();
@@ -61,11 +61,11 @@ try {
assert(missingTarget.status === 404, "不存在的目标应返回 404"); assert(missingTarget.status === 404, "不存在的目标应返回 404");
const { body: rootHtml, response: rootResponse } = await expectText(`${baseUrl}/`, 200); const { body: rootHtml, response: rootResponse } = await expectText(`${baseUrl}/`, 200);
assert(rootHtml.includes("Gateway Checker"), "前端根页面缺少标题"); assert(rootHtml.includes("DiAL"), "前端根页面缺少标题");
assert(rootResponse.headers.get("cache-control") === "no-cache", "前端根页面应使用 no-cache"); assert(rootResponse.headers.get("cache-control") === "no-cache", "前端根页面应使用 no-cache");
const { body: fallbackHtml } = await expectText(`${baseUrl}/dashboard`, 200); const { body: fallbackHtml } = await expectText(`${baseUrl}/dashboard`, 200);
assert(fallbackHtml.includes("Gateway Checker"), "SPA fallback 未返回前端入口页面"); assert(fallbackHtml.includes("DiAL"), "SPA fallback 未返回前端入口页面");
const assetPath = rootHtml.match(/(?:src|href)="(\/assets\/[^"]+)"/)?.[1]; const assetPath = rootHtml.match(/(?:src|href)="(\/assets\/[^"]+)"/)?.[1];
assert(assetPath !== undefined, "前端入口页面未引用 /assets/* 资源"); assert(assetPath !== undefined, "前端入口页面未引用 /assets/* 资源");
@@ -74,7 +74,7 @@ try {
assert(asset.status === 200, `静态资源 ${assetPath} 未返回 200`); assert(asset.status === 200, `静态资源 ${assetPath} 未返回 200`);
const missingAsset = await expectText(`${baseUrl}/assets/not-found.js`, 404); const missingAsset = await expectText(`${baseUrl}/assets/not-found.js`, 404);
assert(!missingAsset.body.includes("Gateway Checker"), "未知静态资源不应返回前端入口页面"); assert(!missingAsset.body.includes("DiAL"), "未知静态资源不应返回前端入口页面");
console.log(`Smoke test passed: ${baseUrl}`); console.log(`Smoke test passed: ${baseUrl}`);
} catch (error) { } catch (error) {

View File

@@ -244,7 +244,7 @@ function formatDuration(ms: number): string {
function createHealthResponse(): HealthResponse { function createHealthResponse(): HealthResponse {
return { return {
ok: true, ok: true,
service: "gateway-checker", service: "dial-server",
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
} }

View File

@@ -1,6 +1,6 @@
export function readRuntimeConfig(argv: string[] = process.argv.slice(2)): { configPath: string } { export function readRuntimeConfig(argv: string[] = process.argv.slice(2)): { configPath: string } {
if (argv.length === 0) { if (argv.length === 0) {
throw new Error("需要指定 YAML 配置文件路径\n用法: gateway-checker <config.yaml>"); throw new Error("需要指定 YAML 配置文件路径\n用法: dial-server <config.yaml>");
} }
return { configPath: argv[0]! }; return { configPath: argv[0]! };

View File

@@ -23,7 +23,7 @@ export function startServer(options: StartServerOptions) {
}), }),
}); });
console.log(`Gateway Checker listening on ${server.url}`); console.log(`DiAL listening on ${server.url}`);
return server; return server;
} }

View File

@@ -2,7 +2,7 @@ export type RuntimeMode = "development" | "production" | "test";
export interface HealthResponse { export interface HealthResponse {
ok: true; ok: true;
service: "gateway-checker"; service: "dial-server";
timestamp: string; timestamp: string;
} }

View File

@@ -39,8 +39,8 @@ export function App() {
return ( return (
<main className="dashboard"> <main className="dashboard">
<header className="dashboard-header"> <header className="dashboard-header">
<h1>Gateway Checker</h1> <h1>DiAL</h1>
<p className="dashboard-subtitle">HTTP </p> <p className="dashboard-subtitle"></p>
</header> </header>
{error && <div className="error-banner">: {error}</div>} {error && <div className="error-banner">: {error}</div>}

View File

@@ -3,8 +3,8 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Gateway Checker - HTTP 拨测监控面板" /> <meta name="description" content="DiAL - 统一拨测平台" />
<title>Gateway Checker</title> <title>DiAL</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -7,7 +7,7 @@ import { join } from "node:path";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
const staticAssets: StaticAssets = { const staticAssets: StaticAssets = {
indexHtml: new Blob(['<!doctype html><title>Gateway Checker</title><div id="root"></div>'], { indexHtml: new Blob(['<!doctype html><title>DiAL</title><div id="root"></div>'], {
type: "text/html", type: "text/html",
}), }),
files: { files: {
@@ -21,7 +21,7 @@ describe("API 路由", () => {
let fetchHandler: ReturnType<typeof createFetchHandler>; let fetchHandler: ReturnType<typeof createFetchHandler>;
beforeAll(async () => { beforeAll(async () => {
tempDir = join(tmpdir(), `gc-api-test-${Date.now()}`); tempDir = join(tmpdir(), `dial-api-test-${Date.now()}`);
await mkdir(tempDir, { recursive: true }); await mkdir(tempDir, { recursive: true });
store = new ProbeStore(join(tempDir, "test.db")); store = new ProbeStore(join(tempDir, "test.db"));
store.syncTargets([ store.syncTargets([
@@ -93,7 +93,7 @@ describe("API 路由", () => {
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(body.ok).toBe(true); expect(body.ok).toBe(true);
expect(body.service).toBe("gateway-checker"); expect(body.service).toBe("dial-server");
}); });
test("/api/summary 返回总览统计", async () => { test("/api/summary 返回总览统计", async () => {