100 lines
3.1 KiB
JavaScript
Executable File
100 lines
3.1 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { Agent, fetch as undiciFetch } from 'undici';
|
|
|
|
function loadEnvFile(filePath) {
|
|
if (!fs.existsSync(filePath)) return;
|
|
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
const idx = trimmed.indexOf('=');
|
|
if (idx < 0) continue;
|
|
const key = trimmed.slice(0, idx).trim();
|
|
const value = trimmed.slice(idx + 1).trim();
|
|
if (!process.env[key]) process.env[key] = value;
|
|
}
|
|
}
|
|
|
|
loadEnvFile(path.join(process.cwd(), '.env'));
|
|
|
|
const insecureDispatcher = new Agent({ connect: { rejectUnauthorized: false } });
|
|
const publicBase = (process.env.H5_PUBLIC_BASE_URL || 'https://mm.tkmind.cn').replace(/\/$/, '');
|
|
const targets = (process.env.TKMIND_API_TARGETS || process.env.TKMIND_API_TARGET || '')
|
|
.split(',')
|
|
.map((value) => value.trim())
|
|
.filter(Boolean);
|
|
|
|
async function fetchText(url, init = {}) {
|
|
const res = await undiciFetch(url, {
|
|
...init,
|
|
dispatcher: url.startsWith('https://127.0.0.1') ? insecureDispatcher : undefined,
|
|
});
|
|
const text = await res.text();
|
|
return { res, text };
|
|
}
|
|
|
|
async function checkJson(pathname) {
|
|
const { res, text } = await fetchText(`${publicBase}${pathname}`);
|
|
let json = null;
|
|
try {
|
|
json = JSON.parse(text);
|
|
} catch {
|
|
json = null;
|
|
}
|
|
return { ok: res.ok, status: res.status, json, text: json ? undefined : text.slice(0, 160) };
|
|
}
|
|
|
|
async function checkSseHeaders(pathname) {
|
|
const { res } = await fetchText(`${publicBase}${pathname}`, {
|
|
method: 'HEAD',
|
|
headers: { Accept: 'text/event-stream' },
|
|
});
|
|
return {
|
|
ok: res.status === 401 || res.ok,
|
|
status: res.status,
|
|
xAccelBuffering: res.headers.get('x-accel-buffering'),
|
|
contentType: res.headers.get('content-type'),
|
|
cacheControl: res.headers.get('cache-control'),
|
|
};
|
|
}
|
|
|
|
async function checkTarget(target) {
|
|
const { res, text } = await fetchText(new URL('/status', target).toString());
|
|
return { target, ok: res.ok, status: res.status, text: text.slice(0, 80) };
|
|
}
|
|
|
|
const result = {
|
|
ok: true,
|
|
publicBase,
|
|
checkedAt: new Date().toISOString(),
|
|
status: await checkJson('/api/status').catch((err) => ({ ok: false, error: err.message })),
|
|
runtime: await checkJson('/api/runtime/status').catch((err) => ({ ok: false, error: err.message })),
|
|
sse: {
|
|
sessions: await checkSseHeaders('/api/sessions/check-stream-runtime/events').catch((err) => ({
|
|
ok: false,
|
|
error: err.message,
|
|
})),
|
|
agentRuns: await checkSseHeaders('/api/agent/runs/check-stream-runtime/events').catch((err) => ({
|
|
ok: false,
|
|
error: err.message,
|
|
})),
|
|
},
|
|
targets: await Promise.all(targets.map((target) => checkTarget(target).catch((err) => ({
|
|
target,
|
|
ok: false,
|
|
error: err.message,
|
|
})))),
|
|
};
|
|
|
|
result.ok = Boolean(
|
|
result.status.ok &&
|
|
result.runtime.ok &&
|
|
result.sse.sessions.ok &&
|
|
result.sse.agentRuns.ok &&
|
|
result.targets.every((target) => target.ok),
|
|
);
|
|
|
|
console.log(JSON.stringify(result, null, 2));
|
|
process.exit(result.ok ? 0 : 1);
|