diff --git a/src/services/network-diagnostic.ts b/src/services/network-diagnostic.ts index 8f97c1d..f054d4e 100644 --- a/src/services/network-diagnostic.ts +++ b/src/services/network-diagnostic.ts @@ -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 { try { + const location: Record = { country: 'KR' }; + if (req.eyeballOnly) { + location.tags = ['eyeball-network']; + } + const body: Record = { - 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 const SNI_BLOCK_PATTERNS = ['ECONNRESET', 'connection reset', 'socket hang up']; async function checkKoreaProbes(domain: string): Promise { - // 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(); @@ -348,7 +367,7 @@ async function checkKoreaProbes(domain: string): Promise