Files

124 lines
4.0 KiB
JavaScript
Raw Permalink Normal View History

#!/usr/bin/env node
/**
* Diagnose local Plaza setup and print fix hints.
*/
import fs from 'node:fs';
import net from 'node:net';
import dns from 'node:dns';
import { promisify } from 'node:util';
import https from 'node:https';
const host = process.env.PLAZA_LOCAL_HOST ?? 'plaza.tkmind.cn';
const dnsPort = Number(process.env.PLAZA_LOCAL_DNS_PORT ?? 5533);
const plazaPort = Number(process.env.PLAZA_PORT ?? 3001);
const portalPort = Number(process.env.H5_PORT ?? 8081);
const lookup = promisify(dns.lookup);
const resolve4 = promisify(dns.resolve4);
function tcpOpen(port, bind = '127.0.0.1') {
return new Promise((resolve) => {
const s = net.connect(port, bind, () => {
s.end();
resolve(true);
});
s.on('error', () => resolve(false));
s.setTimeout(2000, () => {
s.destroy();
resolve(false);
});
});
}
function httpsPlaza() {
return new Promise((resolve) => {
const req = https.request(
{
hostname: host,
port: 443,
path: '/plaza',
rejectUnauthorized: false,
timeout: 3000,
},
(res) => resolve({ ok: res.statusCode === 200, code: res.statusCode }),
);
req.on('error', (err) => resolve({ ok: false, error: err.message }));
req.on('timeout', () => {
req.destroy();
resolve({ ok: false, error: 'timeout' });
});
req.end();
});
}
const issues = [];
const ok = [];
// hosts
try {
const hosts = fs.readFileSync('/etc/hosts', 'utf8');
if (new RegExp(`127\\.0\\.0\\.1\\s+${host.replace('.', '\\.')}`).test(hosts)) ok.push('hosts 已指向 127.0.0.1');
else issues.push(`执行:sudo pnpm setup:plaza-dns`);
} catch {
issues.push('无法读取 /etc/hosts');
}
// resolver
try {
const body = fs.readFileSync(`/etc/resolver/${host}`, 'utf8');
if (body.includes(`port ${dnsPort}`)) ok.push(`resolver -> 127.0.0.1:${dnsPort}`);
else issues.push(`resolver 端口不对,执行:sudo pnpm setup:plaza-dns`);
} catch {
issues.push(`缺少 /etc/resolver/${host},执行:sudo pnpm setup:plaza-dns`);
}
// services
if (await tcpOpen(dnsPort)) ok.push(`本地 DNS :${dnsPort} 运行中`);
else issues.push(`本地 DNS 未运行,执行:pnpm dev:plaza-dns(或 pnpm dev:plaza)`);
if (await tcpOpen(plazaPort)) ok.push(`Plaza Next.js :${plazaPort} 运行中`);
else issues.push(`Plaza 未运行,执行:pnpm dev:plaza`);
if (await tcpOpen(portalPort)) ok.push(`Portal :${portalPort} 运行中`);
else issues.push(`Portal 未运行(dev:plaza 会自动启动)`);
if (await tcpOpen(443)) ok.push('HTTPS 代理 :443 运行中');
else issues.push('HTTPS 代理未运行,执行:sudo pnpm dev:plaza-proxy');
// DNS resolution
const looked = await lookup(host, { all: true });
const addrs = looked.map((x) => x.address);
if (addrs.every((a) => a === '127.0.0.1' || a.startsWith('::ffff:127.'))) {
ok.push(`系统 DNS lookup -> ${addrs.join(', ')}`);
} else {
issues.push(`系统 DNS 仍含非本地地址:${addrs.join(', ')}(Tailscale fake-ip)`);
}
try {
const r4 = await resolve4(host);
if (r4.some((a) => a !== '127.0.0.1')) {
issues.push(`resolve4 -> ${r4.join(', ')}(浏览器 Secure DNS 可能走线上 Cloudflare)`);
}
} catch {
// ignore
}
const httpsResult = await httpsPlaza();
if (httpsResult.ok) ok.push(`终端 HTTPS ${host}/plaza -> ${httpsResult.code}`);
else issues.push(`终端 HTTPS 失败:${httpsResult.error ?? httpsResult.code}`);
console.log('\n=== Plaza 本地诊断 ===\n');
for (const line of ok) console.log(`✓ ${line}`);
for (const line of issues) console.log(`✗ ${line}`);
console.log('\n--- 浏览器仍失败?---');
console.log('Chrome/Cursor 内置浏览器默认走「安全 DNS」,会绕过 /etc/hosts 连到线上 Cloudflare。');
console.log('');
console.log('解决:');
console.log(' 1. pnpm open:plaza # 用 Chrome 强制解析到本机');
console.log(' 2. 或关闭浏览器「安全 DNS / Secure DNS」后刷新');
console.log(' 3. 或临时访问 http://127.0.0.1:3001/plaza');
console.log('');
process.exit(issues.length ? 1 : 0);