Request eyeball probes separately for reliable ISP block detection

Split HTTP measurements: general probes for performance + eyeball-only
probes (KT, LG U+) for SNI blocking detection. Ensures ISP probes are
always included regardless of random probe selection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-02-12 08:49:21 +09:00
parent 8eb89da6c0
commit 04b322b378

View File

@@ -244,19 +244,29 @@ interface GlobalpingRawResult {
};
}
interface MeasurementRequest {
type: 'ping' | 'http';
target: string;
eyeballOnly?: boolean;
}
async function createGlobalpingMeasurement(
type: 'ping' | 'http',
target: string
req: MeasurementRequest
): Promise<string | null> {
try {
const location: Record<string, unknown> = { country: 'KR' };
if (req.eyeballOnly) {
location.tags = ['eyeball-network'];
}
const body: Record<string, unknown> = {
type,
target,
locations: [{ country: 'KR' }],
limit: 5,
type: req.type,
target: req.target,
locations: [location],
limit: req.eyeballOnly ? 5 : 5,
};
if (type === 'ping') {
if (req.type === 'ping') {
body.measurementOptions = { packets: 3 };
} else {
body.measurementOptions = {
@@ -273,7 +283,8 @@ async function createGlobalpingMeasurement(
if (!response.ok) {
logger.warn('Globalping measurement creation failed', {
type,
type: req.type,
eyeballOnly: req.eyeballOnly,
status: response.status,
});
return null;
@@ -314,20 +325,28 @@ async function pollGlobalpingResult(id: string): Promise<GlobalpingRawResult[]>
const SNI_BLOCK_PATTERNS = ['ECONNRESET', 'connection reset', 'socket hang up'];
async function checkKoreaProbes(domain: string): Promise<GlobalpingProbeResult[]> {
// Create ping and HTTP measurements in parallel
const [pingId, httpId] = await Promise.all([
createGlobalpingMeasurement('ping', domain),
createGlobalpingMeasurement('http', domain),
// Create 3 measurements in parallel:
// - ping: general probes for latency
// - HTTP general: datacenter probes for performance baseline
// - HTTP eyeball: ISP probes (KT, LG) for SNI block detection
const [pingId, httpId, httpEyeballId] = await Promise.all([
createGlobalpingMeasurement({ type: 'ping', target: domain }),
createGlobalpingMeasurement({ type: 'http', target: domain }),
createGlobalpingMeasurement({ type: 'http', target: domain, eyeballOnly: true }),
]);
if (!pingId && !httpId) return [];
if (!pingId && !httpId && !httpEyeballId) return [];
// Poll both results in parallel
const [pingResults, httpResults] = await Promise.all([
// Poll all results in parallel
const [pingResults, httpResults, httpEyeballResults] = await Promise.all([
pingId ? pollGlobalpingResult(pingId) : Promise.resolve([]),
httpId ? pollGlobalpingResult(httpId) : Promise.resolve([]),
httpEyeballId ? pollGlobalpingResult(httpEyeballId) : Promise.resolve([]),
]);
// Combine HTTP results (eyeball + general, dedup by key)
const allHttpResults = [...httpEyeballResults, ...httpResults];
// Merge ping and HTTP results by probe city+network
const probeMap = new Map<string, GlobalpingProbeResult>();
@@ -348,7 +367,7 @@ async function checkKoreaProbes(domain: string): Promise<GlobalpingProbeResult[]
});
}
for (const r of httpResults) {
for (const r of allHttpResults) {
const key = `${r.probe.city}:${r.probe.network}`;
const isEyeball = (r.probe.tags || []).includes('eyeball-network');
const existing = probeMap.get(key) || {