Bug fix (agreed pre-existing bug #3 of 3): the .catch() branch of localDb.getLocalDbStats() referenced status/roaAge, both only declared inside the sibling .then() callback's closure -- out of scope in .catch(), so any real DB-stats failure threw ReferenceError with no further catch, hanging the response until client timeout instead of degrading gracefully. Fixed: roaAge computed once before the promise chain (same pattern as the existing aspaAge); the .catch() branch gets its own locally-scoped `status = "degraded"` (a DB-stats fetch failure can't confirm "ok", matching the honest-degradation pattern already used throughout this codebase). Also deduplicated the identical delta_last computation that was repeated verbatim in both branches into one aspaAdoptionDelta() helper. Verified via node --check, eslint no-undef (2 known bugs remain: compare, webhooks), and smoke-test harness (28/28 match). server.js: 3556 -> 3346 lines.
99 lines
3.7 KiB
JavaScript
99 lines
3.7 KiB
JavaScript
const { atlasState } = require("../atlas-probes");
|
|
const { pdbOrgState } = require("../pdb-org-countries");
|
|
const { fetchPeeringDB } = require("../services/peeringdb");
|
|
const { cacheGet, cacheSet } = require("../caches/response-caches");
|
|
|
|
// Lia's Atlas Paradise: Atlas probe coverage endpoint
|
|
function handleAtlasCoverage(req, res) {
|
|
res.setHeader("Content-Type", "application/json");
|
|
if (!atlasState.cache) {
|
|
res.writeHead(503);
|
|
return res.end(JSON.stringify({ error: "Atlas probe data is still loading. Please try again in a minute." }));
|
|
}
|
|
return res.end(JSON.stringify(atlasState.cache, null, 2));
|
|
}
|
|
|
|
// Lia's Paradise: File parsing endpoint (for binary uploads)
|
|
function handleParseFile(req, res) {
|
|
res.setHeader("Content-Type", "application/json");
|
|
let body = "";
|
|
req.on("data", function(chunk) { body += chunk; });
|
|
req.on("end", function() {
|
|
try {
|
|
var parsed = JSON.parse(body);
|
|
var filename = parsed.filename || "";
|
|
var ext = filename.split(".").pop().toLowerCase();
|
|
// For text-based formats, decode base64 and extract text
|
|
if (ext === "csv" || ext === "txt") {
|
|
var text = Buffer.from(parsed.data, "base64").toString("utf8");
|
|
return res.end(JSON.stringify({ text: text }));
|
|
}
|
|
// For binary formats (PDF, XLS, DOC), we can't parse server-side without
|
|
// heavy dependencies. Return helpful error.
|
|
return res.end(JSON.stringify({
|
|
error: "Binary file parsing (" + ext.toUpperCase() + ") requires client-side extraction. Please use CSV or TXT format, or copy-paste the content.",
|
|
suggestion: "Export your spreadsheet as CSV first, then upload the CSV file."
|
|
}));
|
|
} catch(e) {
|
|
return res.end(JSON.stringify({ error: "Parse error: " + e.message }));
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Lia's Paradise: Combined PeeringDB + Atlas coverage data
|
|
function handleLiaCoverage(req, res) {
|
|
res.setHeader("Content-Type", "application/json");
|
|
if (!atlasState.cache) {
|
|
res.writeHead(503);
|
|
return res.end(JSON.stringify({ error: "Atlas probe data is still loading. Please try again in a minute." }));
|
|
}
|
|
|
|
// Cache this expensive response for 30 min
|
|
var liaCacheKey = "lia_coverage";
|
|
var liaCached = cacheGet(liaCacheKey);
|
|
if (liaCached) return res.end(liaCached);
|
|
|
|
// Fetch PeeringDB network list (all networks with status "ok")
|
|
// Use pre-cached org→country map (loaded at startup, 16MB response cached in memory)
|
|
fetchPeeringDB("/net?status=ok&depth=0").then(function(pdbData) {
|
|
if (!pdbData || !pdbData.data) {
|
|
return res.end(JSON.stringify({ error: "Could not fetch PeeringDB networks" }));
|
|
}
|
|
|
|
var probeAsns = new Set(atlasState.cache.asns_with_probes || []);
|
|
|
|
var enriched = pdbData.data.map(function(n) {
|
|
var org = pdbOrgState.map.get(n.org_id) || {};
|
|
var cc = org.country || "";
|
|
return {
|
|
asn: n.asn,
|
|
name: n.name || "",
|
|
org_name: org.name || "",
|
|
country: cc,
|
|
country_name: cc,
|
|
info_type: n.info_type || "",
|
|
has_probe: probeAsns.has(n.asn),
|
|
};
|
|
}).filter(function(n) { return n.asn > 0 && n.country; });
|
|
|
|
var result = JSON.stringify({
|
|
networks: enriched,
|
|
total: enriched.length,
|
|
with_probes: enriched.filter(function(n) { return n.has_probe; }).length,
|
|
without_probes: enriched.filter(function(n) { return !n.has_probe; }).length,
|
|
atlas_unique_asns: probeAsns.size,
|
|
org_countries_loaded: pdbOrgState.map.size,
|
|
fetched_at: new Date().toISOString(),
|
|
});
|
|
|
|
cacheSet(liaCacheKey, result, 30 * 60 * 1000);
|
|
res.end(result);
|
|
}).catch(function(e) {
|
|
res.end(JSON.stringify({ error: "PeeringDB fetch failed: " + e.message }));
|
|
});
|
|
return;
|
|
}
|
|
|
|
module.exports = { handleAtlasCoverage, handleParseFile, handleLiaCoverage };
|