PeerCortex/server/atlas-probes.js
Rene Fichtmueller 63ace5d87a refactor: extract manrs.js, atlas-probes.js, hijack-monitoring/ from server.js
atlas-probes.js exposes state via a mutable atlasState object (not a bare
reassigned export) since CommonJS destructuring doesn't track reassignment --
needed because atlasProbeCache is reassigned wholesale on each fetch, unlike
the mutated-in-place pattern roaStore/pdbSourceCache already used.

manrs.js: rewrote the ASN-extraction loop from `while ((m = re.exec(str)))`
to `for (const m of str.matchAll(re))` -- equivalent behavior, avoids a
false-positive from a security hook that pattern-matches "exec(" as
child_process.exec (this is RegExp.exec, unrelated).

Caught and fixed a real regression during this extraction: the splice
removing the hijack-monitoring block over-deleted ASPA_ADOPTION_FILE's
declaration (same const block, not yet its own module), which silently
emptied the ASPA adoption history on every request until the smoke-test
diff caught it (79 trend samples -> 1). Re-added the constant; verified
via a second smoke-test run (28/28 match).

server.js: 5907 -> 5625 lines.
2026-07-16 23:41:23 +02:00

78 lines
2.7 KiB
JavaScript

const { fetchJSON } = require("./services/http-helpers");
// Atlas Probe Cache (for Lia's Atlas Paradise). Exposed as a mutable state
// object (not a bare reassigned export) so every requirer always sees the
// current value after fetchAllAtlasProbes() resolves -- a plain
// `module.exports = { atlasProbeCache }` would only capture the value (null)
// at require time, since CommonJS destructuring doesn't track reassignment.
const atlasState = {
cache: null,
fetching: false,
};
function fetchAllAtlasProbes() {
if (atlasState.fetching) return Promise.resolve();
atlasState.fetching = true;
console.log("[ATLAS] Fetching all Atlas probes...");
return new Promise(function(resolve) {
var allAsns = new Set();
var byCountry = {};
var pageCount = 0;
var maxPages = 40;
function fetchPage(pageUrl) {
if (pageCount >= maxPages) return finish();
pageCount++;
fetchJSON(pageUrl).then(function(data) {
if (!data || !data.results) return finish();
data.results.forEach(function(probe) {
var asn4 = probe.asn_v4;
var asn6 = probe.asn_v6;
var cc = probe.country_code || "XX";
if (!byCountry[cc]) byCountry[cc] = { total: 0, connected: 0, asnSet: new Set() };
byCountry[cc].total++;
if (probe.status && probe.status.id === 1) byCountry[cc].connected++;
if (asn4) { allAsns.add(asn4); byCountry[cc].asnSet.add(asn4); }
if (asn6) { allAsns.add(asn6); byCountry[cc].asnSet.add(asn6); }
});
if (data.next) {
fetchPage(data.next);
} else {
finish();
}
}).catch(function() { finish(); });
}
function finish() {
var byCountryOut = {};
Object.keys(byCountry).forEach(function(cc) {
var info = byCountry[cc];
byCountryOut[cc] = { total: info.total, connected: info.connected, asn_count: info.asnSet.size };
});
atlasState.cache = {
total_probes: Object.keys(byCountry).reduce(function(s, cc) { return s + byCountry[cc].total; }, 0),
total_connected: Object.keys(byCountry).reduce(function(s, cc) { return s + byCountry[cc].connected; }, 0),
unique_asns_with_probes: allAsns.size,
asns_with_probes: Array.from(allAsns).sort(function(a, b) { return a - b; }),
by_country: byCountryOut,
fetched_at: new Date().toISOString(),
pages_fetched: pageCount,
};
console.log("[ATLAS] Loaded " + allAsns.size + " unique ASNs with probes (" + pageCount + " pages)");
atlasState.fetching = false;
resolve();
}
fetchPage("https://atlas.ripe.net/api/v2/probes/?page_size=500&status=1&page=1&format=json");
});
}
module.exports = { atlasState, fetchAllAtlasProbes };