From 33d6a84d474833dfbc57e494ebc4094e6b69512b Mon Sep 17 00:00:00 2001 From: Rene Fichtmueller Date: Fri, 27 Mar 2026 23:31:32 +1300 Subject: [PATCH] fix: map tiles + PeeringDB rate limit resilience - Leaflet map: double requestAnimationFrame after display:none removal ensures container has real dimensions before L.map() init - PeeringDB org cache: 24h disk cache (.pdb-org-cache.json) prevents hammering PeeringDB API on server restarts (was causing 175 restarts) - Check HTTP status before JSON.parse on PDB responses --- public/index.html | 13 ++++++++++++- server.js | 29 ++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/public/index.html b/public/index.html index 24e5b31..658dbba 100644 --- a/public/index.html +++ b/public/index.html @@ -1269,6 +1269,17 @@ function renderNetworkMap(d) { if (markers.length === 0) { mapEl.classList.add('hidden'); return; } mapEl.classList.remove('hidden'); + // Defer map init to next frame so container has real dimensions after display:none removal + window._pcMapMarkers = markers; + window._pcMapFacs = facs; + requestAnimationFrame(function() { + requestAnimationFrame(function() { + _initLeafletMap(mapDiv, window._pcMapMarkers, window._pcMapFacs); + }); + }); +} + +function _initLeafletMap(mapDiv, markers, facs) { if (_pcMap) { _pcMap.remove(); _pcMap = null; } _pcMap = L.map(mapDiv, { scrollWheelZoom: false, attributionControl: false }); L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { @@ -1323,7 +1334,7 @@ function renderNetworkMap(d) { _pcMap.invalidateSize(); _pcMap.fitBounds(bounds, { padding: [30, 30], maxZoom: 6 }); } - }, 200); + }, 500); } diff --git a/server.js b/server.js index e4b77f1..2befb41 100644 --- a/server.js +++ b/server.js @@ -2875,9 +2875,23 @@ function fetchAllAtlasProbes() { let pdbOrgCountryMap = new Map(); // org_id → { country, name } function fetchPdbOrgCountries() { - console.log("[PDB-ORG] Fetching PeeringDB org countries..."); + var cacheFile = require("path").join(__dirname, ".pdb-org-cache.json"); + var fs = require("fs"); + + // Try disk cache first (valid for 24h) + try { + var stat = fs.statSync(cacheFile); + var ageHours = (Date.now() - stat.mtimeMs) / 3600000; + if (ageHours < 24) { + var cached = JSON.parse(fs.readFileSync(cacheFile, "utf8")); + pdbOrgCountryMap = new Map(Object.entries(cached)); + console.log("[PDB-ORG] Loaded " + pdbOrgCountryMap.size + " orgs from disk cache (" + Math.round(ageHours) + "h old)"); + return Promise.resolve(); + } + } catch (_) { /* no cache or invalid */ } + + console.log("[PDB-ORG] Fetching PeeringDB org countries (fresh)..."); return new Promise(function(resolve) { - // Use raw https to handle the large 16MB response with streaming var chunks = []; var req = require("https").get("https://www.peeringdb.com/api/org?status=ok&depth=0", { headers: { @@ -2886,6 +2900,11 @@ function fetchPdbOrgCountries() { }, timeout: 120000, }, function(res) { + if (res.statusCode !== 200) { + console.error("[PDB-ORG] HTTP " + res.statusCode + " — using stale cache or empty"); + resolve(); + return; + } res.on("data", function(chunk) { chunks.push(chunk); }); res.on("end", function() { try { @@ -2893,12 +2912,16 @@ function fetchPdbOrgCountries() { var data = JSON.parse(body); if (data && data.data) { pdbOrgCountryMap = new Map(); + var cacheObj = {}; data.data.forEach(function(o) { if (o.id && o.country) { pdbOrgCountryMap.set(o.id, { country: o.country, name: o.name || "" }); + cacheObj[o.id] = { country: o.country, name: o.name || "" }; } }); - console.log("[PDB-ORG] Loaded " + pdbOrgCountryMap.size + " org→country mappings"); + // Save to disk cache + try { fs.writeFileSync(cacheFile, JSON.stringify(cacheObj)); } catch (_) {} + console.log("[PDB-ORG] Loaded " + pdbOrgCountryMap.size + " org→country mappings (cached to disk)"); } } catch (e) { console.error("[PDB-ORG] Parse error:", e.message);