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