Update server.js via upload script - 2026-08-01 17:07:56

This commit is contained in:
mike 2026-08-01 17:08:16 +08:00
parent 907020e12e
commit c656d3bf2a
1 changed files with 24 additions and 18 deletions

View File

@ -178,10 +178,10 @@ function httpStatusCheck(line, timeoutMs = 8000) {
}, (res) => {
res.resume();
const badGateway = [520, 521, 522, 523, 524].includes(res.statusCode);
resolve(!badGateway);
resolve({ ok: !badGateway, detail: `HTTP ${res.statusCode}` });
});
req.on('timeout', () => { req.destroy(); resolve(false); });
req.on('error', () => resolve(false));
req.on('timeout', () => { req.destroy(); resolve({ ok: false, detail: 'HTTP请求超时' }); });
req.on('error', (err) => resolve({ ok: false, detail: `HTTP错误${err.code || err.message}` }));
req.end();
});
}
@ -189,11 +189,11 @@ function wsHandshakeCheck(line, timeoutMs = 8000) {
return new Promise((resolve) => {
let done = false;
let ws;
const finish = (ok) => {
const finish = (ok, detail) => {
if (done) return;
done = true;
try { ws && ws.terminate(); } catch (e) {}
resolve(ok);
resolve({ ok, detail });
};
try {
const port = Number(line.port) || 443;
@ -203,25 +203,31 @@ function wsHandshakeCheck(line, timeoutMs = 8000) {
headers: { Host: routeName },
servername: line.sni || routeName, // TLS SNI
});
ws.on('open', () => finish(true));
ws.on('unexpected-response', () => finish(false));
ws.on('error', () => finish(false));
ws.on('open', () => finish(true, 'WS握手成功'));
ws.on('unexpected-response', (req2, res2) => finish(false, `WS握手被拒绝HTTP ${res2 && res2.statusCode}`));
ws.on('error', (err) => finish(false, `WS错误${err.code || err.message}`));
} catch (e) {
finish(false);
finish(false, `WS异常${e.message}`);
}
setTimeout(() => finish(false), timeoutMs + 500);
setTimeout(() => finish(false, 'WS握手超时'), timeoutMs + 500);
});
}
// 返回 { ok, detail } —— detail只在vless-cdn时有意义http/ws两段各自的失败原因
// 方便"立即检测"排查究竟是端口/Host/SNI哪一环出的问题而不是只有一个"异常"看不出所以然。
async function checkLineConnectivity(line) {
if (line.protocol === 'vless-cdn') {
const [httpOk, wsOk] = await Promise.all([
const [httpResult, wsResult] = await Promise.all([
httpStatusCheck(line),
wsHandshakeCheck(line),
]);
return httpOk && wsOk;
return {
ok: httpResult.ok && wsResult.ok,
detail: `HTTP探测: ${httpResult.detail} | WS握手: ${wsResult.detail}`,
};
}
return tcpCheck(line.addr, line.port);
const tcpOk = await tcpCheck(line.addr, line.port);
return { ok: tcpOk, detail: tcpOk ? 'TCP连通' : 'TCP连接失败/超时' };
}
// 后台定时巡检:每 JMS_CHECK_INTERVAL_MS 跑一轮只在状态发生变化正常↔异常时才发Telegram
@ -237,12 +243,12 @@ async function runJmsMonitorCycle() {
for (const line of lines) {
try {
const ok = await checkLineConnectivity(line);
const { ok, detail } = await checkLineConnectivity(line);
const newStatus = ok ? 'normal' : 'abnormal';
if (line.monitorStatus && line.monitorStatus !== newStatus) {
const name = line.name || line.addr;
const msg = newStatus === 'abnormal'
? `⚠️ <b>${name}</b> 检测异常,无法连接\n协议:${line.protocol}\n地址:${line.addr}:${line.port}`
? `⚠️ <b>${name}</b> 检测异常,无法连接\n协议:${line.protocol}\n地址:${line.addr}:${line.port}\n详情:${detail}`
: `✅ <b>${name}</b> 已恢复正常\n协议:${line.protocol}\n地址:${line.addr}:${line.port}`;
sendTelegramMessage(msg).catch(() => {}); // Telegram没配置/发送失败都不影响检测本身
}
@ -568,16 +574,16 @@ app.post('/api/jms/check-line', requireAuth, jmsCheckLimiter, async (req, res) =
const line = req.body && req.body.line;
if (!line || !line.addr) return res.status(400).json({ error: '线路信息不完整' });
try {
const ok = await checkLineConnectivity(line);
const { ok, detail } = await checkLineConnectivity(line);
const newStatus = ok ? 'normal' : 'abnormal';
if (line.monitorStatus && line.monitorStatus !== newStatus) {
const name = line.name || line.addr;
const msg = newStatus === 'abnormal'
? `⚠️ <b>${name}</b> 检测异常,无法连接\n协议:${line.protocol}\n地址:${line.addr}:${line.port}`
? `⚠️ <b>${name}</b> 检测异常,无法连接\n协议:${line.protocol}\n地址:${line.addr}:${line.port}\n详情:${detail}`
: `✅ <b>${name}</b> 已恢复正常\n协议:${line.protocol}\n地址:${line.addr}:${line.port}`;
sendTelegramMessage(msg).catch(() => {});
}
res.json({ ok: true, status: newStatus, checkedAt: Date.now() });
res.json({ ok: true, status: newStatus, detail, checkedAt: Date.now() });
} catch (e) {
res.status(500).json({ error: e.message });
}