katproxy/backend/checker.js

93 lines
2.1 KiB
JavaScript

const net = require('net');
/**
* Probe a single proxy host:port via TCP socket to check if open and measure round-trip latency (ms)
*/
function probeProxy(host, port, timeoutMs = 2000) {
return new Promise((resolve) => {
const startTime = Date.now();
const socket = new net.Socket();
let resolved = false;
const cleanup = () => {
socket.removeAllListeners();
socket.destroy();
};
socket.setTimeout(timeoutMs);
socket.connect(port, host, () => {
if (!resolved) {
resolved = true;
const latency = Date.now() - startTime;
cleanup();
resolve({ alive: true, latency });
}
});
socket.on('timeout', () => {
if (!resolved) {
resolved = true;
cleanup();
resolve({ alive: false, latency: null, reason: 'timeout' });
}
});
socket.on('error', (err) => {
if (!resolved) {
resolved = true;
cleanup();
resolve({ alive: false, latency: null, reason: err.code || 'error' });
}
});
});
}
/**
* Check a batch of proxies with concurrency limit
*/
async function batchCheckProxies(proxies, concurrency = 50, timeoutMs = 2000, onProgress = null) {
let index = 0;
let active = 0;
let completed = 0;
const total = proxies.length;
return new Promise((resolve) => {
if (total === 0) return resolve();
function next() {
while (active < concurrency && index < total) {
const currentIndex = index++;
const proxy = proxies[currentIndex];
active++;
probeProxy(proxy.host, proxy.port, timeoutMs).then((res) => {
proxy.alive = res.alive;
if (res.alive) {
proxy.latency = res.latency;
}
proxy.lastChecked = Date.now();
active--;
completed++;
if (onProgress && completed % 25 === 0) {
onProgress(completed, total);
}
if (completed === total) {
resolve();
} else {
next();
}
});
}
}
next();
});
}
module.exports = {
probeProxy,
batchCheckProxies
};