const { fetchBgproutesVisibility } = require("../../services/http-helpers"); // Compute routing visibility and prefix size distribution. async function computeRoutingInfo(prefixes, visibilityData, prefixSizeData) { const ipv4Prefixes = prefixes.filter(function(p) { return !p.prefix.includes(":"); }); const ipv6Prefixes = prefixes.filter(function(p) { return p.prefix.includes(":"); }); var ipv4VisAvg = 0, ipv6VisAvg = 0, totalRisPeersV4 = 0, totalRisPeersV6 = 0; // Visibility API returns per-RIS-collector data // Each collector has ipv4_full_table_peer_count and ipv4_full_table_peers_not_seeing[] // Bug 3 fix: visibility API may timeout for large ASNs — handle gracefully var visibilities = (visibilityData && visibilityData.data && visibilityData.data.visibilities) || []; var v4Seeing = 0, v4Total = 0, v6Seeing = 0, v6Total = 0; var visTimedOut = !visibilityData || !visibilityData.data; visibilities.forEach(function(v) { if (!v || !v.probe) return; var v4PeerCount = v.ipv4_full_table_peer_count || 0; var v4NotSeeing = (v.ipv4_full_table_peers_not_seeing || []).length; var v6PeerCount = v.ipv6_full_table_peer_count || 0; var v6NotSeeing = (v.ipv6_full_table_peers_not_seeing || []).length; v4Total += v4PeerCount; v4Seeing += (v4PeerCount - v4NotSeeing); v6Total += v6PeerCount; v6Seeing += (v6PeerCount - v6NotSeeing); }); if (v4Total > 0) ipv4VisAvg = Math.round((v4Seeing / v4Total) * 1000) / 10; if (v6Total > 0) ipv6VisAvg = Math.round((v6Seeing / v6Total) * 1000) / 10; // If visibility API timed out but we have prefixes, try bgproutes.io fallback if (visTimedOut && prefixes.length > 0) { var fallbackPrefix = prefixes.find(function(p) { return !p.prefix.includes(":"); }); if (!fallbackPrefix) fallbackPrefix = prefixes[0]; if (fallbackPrefix) { var bgprFallback = await fetchBgproutesVisibility(fallbackPrefix.prefix); if (bgprFallback && bgprFallback.vps_seeing > 0) { // Estimate visibility: % of VPs seeing the prefix (assume ~300 total RIS-equivalent VPs) var estimatedTotal = Math.max(bgprFallback.vps_seeing, 300); ipv4VisAvg = Math.round((bgprFallback.vps_seeing / estimatedTotal) * 1000) / 10; ipv6VisAvg = -1; // bgproutes fallback is per-prefix, not per-AF aggregate totalRisPeersV4 = bgprFallback.vps_seeing; console.log("[Visibility] RIPE Stat timed out, used bgproutes.io fallback for " + fallbackPrefix.prefix + ": " + bgprFallback.vps_seeing + " VPs seeing it"); } else { ipv4VisAvg = -1; ipv6VisAvg = -1; console.log("[Visibility] RIPE Stat timed out and bgproutes.io fallback returned no data"); } } else { ipv4VisAvg = -1; ipv6VisAvg = -1; } } totalRisPeersV4 = v4Total; totalRisPeersV6 = v6Total; // Prefix size distribution: data.ipv4[] and data.ipv6[] arrays with {size, count} var psdData = (prefixSizeData && prefixSizeData.data) || {}; var psV4 = (psdData.ipv4 || []).map(function(e) { return { size: e.size, count: e.count }; }).sort(function(a,b){ return a.size - b.size; }); var psV6 = (psdData.ipv6 || []).map(function(e) { return { size: e.size, count: e.count }; }).sort(function(a,b){ return a.size - b.size; }); return { ipv4_prefixes: ipv4Prefixes.length, ipv6_prefixes: ipv6Prefixes.length, ipv4_visibility_avg: ipv4VisAvg, ipv6_visibility_avg: ipv6VisAvg, total_ris_peers_v4: totalRisPeersV4, total_ris_peers_v6: totalRisPeersV6, prefix_sizes_v4: psV4, prefix_sizes_v6: psV6, }; } module.exports = { computeRoutingInfo };