PeerCortex/server/routes/lookup/routing-info.js
Rene Fichtmueller cba7680de0 refactor: decompose /api/lookup into server/routes/lookup/{index,facilities,enrich-neighbours,rir-country,routing-info,cross-check}.js
The 662-line handler (the largest in the file) split into one function
per data-source/merge stage: facility+IX-location coordinate resolution
(facilities.js), neighbour name-resolution + threat-intel enrichment
(enrich-neighbours.js), RIR/country derivation cascade (rir-country.js),
visibility/prefix-size computation (routing-info.js), multi-source
cross-checks + data-quality scoring (cross-check.js), and a slim
orchestrator (index.js) running Phase 0/1 fetch and final result assembly.

Verified via node --check, eslint no-undef (2 known bugs remain: compare,
webhooks), and smoke-test harness (28/28 match, including a byte-for-byte
match on /api/lookup's own large response body -- the strongest possible
confirmation this, the most complex handler in the file, was decomposed
without changing behavior).

server.js: 2917 -> 1734 lines (6838 originally -- 75% reduction so far).
2026-07-17 07:52:22 +02:00

72 lines
3.5 KiB
JavaScript

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 };