121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
/**
|
|||
|
|
* Map local test domains -> 127.0.0.1 for dev (macOS hosts + per-domain resolver).
|
|||
|
|
*
|
|||
|
|
* Usage:
|
|||
|
|
* sudo node scripts/setup-local-test-dns.mjs
|
|||
|
|
* sudo node scripts/setup-local-test-dns.mjs --remove
|
|||
|
|
*/
|
|||
|
|
import fs from 'node:fs';
|
|||
|
|
import path from 'node:path';
|
|||
|
|
import { execSync } from 'node:child_process';
|
|||
|
|
import { DNS_MARKER, DNS_PORT, LOCAL_IP, TEST_HOSTS } from './local-test-config.mjs';
|
|||
|
|
|
|||
|
|
const remove = process.argv.includes('--remove');
|
|||
|
|
const hostsPath = '/etc/hosts';
|
|||
|
|
const resolverDir = '/etc/resolver';
|
|||
|
|
const resolverBody = `nameserver 127.0.0.1\nport ${DNS_PORT}\n# ${DNS_MARKER}\n`;
|
|||
|
|
|
|||
|
|
function flushDnsCache() {
|
|||
|
|
try {
|
|||
|
|
execSync('dscacheutil -flushcache', { stdio: 'ignore' });
|
|||
|
|
execSync('killall -HUP mDNSResponder', { stdio: 'ignore' });
|
|||
|
|
} catch {
|
|||
|
|
// best effort
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function hostLine(host) {
|
|||
|
|
return `${LOCAL_IP} ${host} # ${DNS_MARKER}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function removeHostLines(lines, host) {
|
|||
|
|
return lines.filter(
|
|||
|
|
(line) =>
|
|||
|
|
!line.includes(DNS_MARKER) &&
|
|||
|
|
!new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function hostReady(lines, host) {
|
|||
|
|
return lines.some(
|
|||
|
|
(line) =>
|
|||
|
|
(line.includes(DNS_MARKER) && line.includes(host)) ||
|
|||
|
|
new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (remove) {
|
|||
|
|
if (process.getuid?.() !== 0) {
|
|||
|
|
console.log('需要 root 权限,请执行:');
|
|||
|
|
console.log(` sudo node ${process.argv[1]} --remove`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let lines = fs.readFileSync(hostsPath, 'utf8').split('\n');
|
|||
|
|
for (const host of TEST_HOSTS) {
|
|||
|
|
lines = removeHostLines(lines, host);
|
|||
|
|
try {
|
|||
|
|
if (fs.existsSync(path.join(resolverDir, host))) fs.unlinkSync(path.join(resolverDir, host));
|
|||
|
|
} catch {
|
|||
|
|
// ignore
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
execSync(`tee ${hostsPath}`, {
|
|||
|
|
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
|
|||
|
|
stdio: ['pipe', 'inherit', 'inherit'],
|
|||
|
|
});
|
|||
|
|
flushDnsCache();
|
|||
|
|
console.log(`已移除本地测试域名:${TEST_HOSTS.join(', ')}`);
|
|||
|
|
process.exit(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const currentLines = fs.readFileSync(hostsPath, 'utf8').split('\n');
|
|||
|
|
const allReady = TEST_HOSTS.every((host) => {
|
|||
|
|
const resolverPath = path.join(resolverDir, host);
|
|||
|
|
const resolverReady =
|
|||
|
|
fs.existsSync(resolverPath) && fs.readFileSync(resolverPath, 'utf8').trim() === resolverBody.trim();
|
|||
|
|
return hostReady(currentLines, host) && resolverReady;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (allReady) {
|
|||
|
|
console.log(`本地测试域名已配置:${TEST_HOSTS.join(', ')}`);
|
|||
|
|
process.exit(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (process.getuid?.() !== 0) {
|
|||
|
|
console.log('需要 root 权限写入 /etc/hosts 和 /etc/resolver,请执行:');
|
|||
|
|
console.log(` sudo pnpm setup:local-dns`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let lines = currentLines;
|
|||
|
|
for (const host of TEST_HOSTS) {
|
|||
|
|
if (!hostReady(lines, host)) {
|
|||
|
|
lines = lines.filter((line) => !line.includes(DNS_MARKER) || !line.includes(host));
|
|||
|
|
lines.push(hostLine(host));
|
|||
|
|
console.log(`已添加 hosts:${hostLine(host)}`);
|
|||
|
|
} else {
|
|||
|
|
console.log(`${host} 已在 /etc/hosts 中指向 ${LOCAL_IP}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
execSync(`tee ${hostsPath}`, {
|
|||
|
|
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
|
|||
|
|
stdio: ['pipe', 'inherit', 'inherit'],
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
fs.mkdirSync(resolverDir, { recursive: true });
|
|||
|
|
for (const host of TEST_HOSTS) {
|
|||
|
|
const resolverPath = path.join(resolverDir, host);
|
|||
|
|
fs.writeFileSync(resolverPath, resolverBody, 'utf8');
|
|||
|
|
console.log(`已添加 resolver:${resolverPath} -> 127.0.0.1:${DNS_PORT}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
flushDnsCache();
|
|||
|
|
console.log('');
|
|||
|
|
console.log('下一步:');
|
|||
|
|
console.log(' sudo pnpm setup:local-tls # 生成本地 HTTPS 证书');
|
|||
|
|
console.log(' pnpm dev # 启动全栈');
|
|||
|
|
console.log(' sudo pnpm dev:local-proxy # HTTPS :443 统一入口');
|