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.
78 lines
2.7 KiB
JavaScript
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 };
|