qq-bot/lib/network.ts

65 lines
3.1 KiB
TypeScript

import chalk from "chalk";
type CheckTarget = [url: string, expectedStatus: number | ((status: number) => boolean)];
export async function testNetwork() {
const targets: CheckTarget[] = [
["https://www.baidu.com", 200],
["http://www.google.com", (s) => s === 200 || (s >= 300 && s < 400)], // 某些环境会被重定向
["https://www.google.com", (s) => s === 200 || (s >= 300 && s < 400)],
[process.env.OPENAI_BASE_URL || "https://api.openai.com/v1", (s) => s === 200 || (s >= 300 && s < 400) || s === 401 || s === 403 || s === 404 || s === 421], // 允许常见网关/鉴权返回
];
const results: Array<{ url: string; status?: number; ok: boolean; error?: string }> = [];
console.log(chalk.cyan("\n[Network] 开始健康检查..."));
for (const [url, expected] of targets) {
const label = chalk.white(url);
try {
const controller = new AbortController();
const timeoutMs = 5000;
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
const start = Date.now();
const res = await fetch(url, { method: "GET", signal: controller.signal });
const cost = Date.now() - start;
clearTimeout(timeoutId);
const status = res.status;
const pass = typeof expected === "function" ? expected(status) : status === expected;
results.push({ url, status, ok: pass });
const statusStr = pass
? chalk.green.bold(String(status))
: chalk.red.bold(String(status));
const costStr = cost >= 1000 ? `${(cost / 1000).toFixed(2)}s` : `${cost}ms`;
if (pass) {
console.log(`${chalk.green("✔ PASS")} ${label} ${chalk.gray("- status:")} ${statusStr} ${chalk.gray("latency:")} ${chalk.blue(costStr)}`);
} else {
const expectedStr = typeof expected === "function" ? "custom" : String(expected);
console.log(`${chalk.red("✖ FAIL")} ${label} ${chalk.gray("- status:")} ${statusStr} ${chalk.gray("expected:")} ${chalk.yellow(expectedStr)} ${chalk.gray("latency:")} ${chalk.blue(costStr)}`);
}
} catch (error) {
const isTimeout = (error as any)?.name === "AbortError";
const msg = isTimeout ? "timeout" : (error as any)?.message || String(error);
results.push({ url, ok: false, error: msg });
console.log(`${chalk.red("✖ ERROR")} ${label} ${chalk.gray("- ")} ${chalk.red(isTimeout ? "请求超时" : msg)}`);
}
}
// 汇总
const passed = results.filter(r => r.ok).length;
const failed = results.length - passed;
const timeoutCount = results.filter(r => r.error === "timeout").length;
const summary = [
`${chalk.green(`${passed} passed`)}`,
`${failed ? chalk.red(`${failed} failed`) : chalk.gray(`${failed} failed`)}`,
`${timeoutCount ? chalk.yellow(`${timeoutCount} timeout`) : chalk.gray(`${timeoutCount} timeout`)}`,
].join(chalk.gray(" | "));
console.log(chalk.cyan("[Network] 健康检查完成:"), summary, "\n");
}