const { fetchPeeringDB } = require("../services/peeringdb"); // Peer Matching endpoint: /api/peers/find?ix=NAME&policy=open&min_speed=10000 async function handlePeersFind(req, res, url) { const ixName = url.searchParams.get("ix") || ""; const policy = url.searchParams.get("policy") || ""; const minSpeed = parseInt(url.searchParams.get("min_speed") || "0"); const netType = url.searchParams.get("type") || ""; if (!ixName) { res.writeHead(400); return res.end(JSON.stringify({ error: "Missing ix parameter (IX name)" })); } const start = Date.now(); try { // Search for IX by name const ixSearch = await fetchPeeringDB("/ix?name__contains=" + encodeURIComponent(ixName)); const ixResults = ixSearch?.data || []; if (ixResults.length === 0) { return res.end(JSON.stringify({ error: "No IX found matching: " + ixName, matches: [] })); } // Use first matching IX const ix = ixResults[0]; const ixId = ix.id; // Get ixlan for this IX const ixlanData = await fetchPeeringDB("/ixlan?ix_id=" + ixId); const ixlans = ixlanData?.data || []; if (ixlans.length === 0) { return res.end(JSON.stringify({ ix: { id: ixId, name: ix.name }, matches: [] })); } const ixlanId = ixlans[0].id; // Get all networks at this IX const netixlanData = await fetchPeeringDB("/netixlan?ixlan_id=" + ixlanId); const netixlans = netixlanData?.data || []; // Get unique net_ids const netIds = [...new Set(netixlans.map(n => n.net_id))]; // Fetch network details in batches const networks = []; const batchSize = 20; for (let i = 0; i < Math.min(netIds.length, 200); i += batchSize) { const batch = netIds.slice(i, i + batchSize); const batchResults = await Promise.all( batch.map(nid => fetchPeeringDB("/net/" + nid)) ); batchResults.forEach(r => { if (r?.data?.[0]) networks.push(r.data[0]); }); } // Filter and rank let filtered = networks.map(net => { const nix = netixlans.filter(n => n.net_id === net.id); const maxSpeed = Math.max(...nix.map(n => n.speed || 0)); return { asn: net.asn, name: net.name || "", policy: net.policy_general || "", type: net.info_type || "", speed_mbps: maxSpeed, speed_gbps: maxSpeed >= 1000 ? (maxSpeed / 1000) + " Gbps" : maxSpeed + " Mbps", traffic: net.info_traffic || "", website: net.website || "", peeringdb_id: net.id, ipv4: nix[0]?.ipaddr4 || null, ipv6: nix[0]?.ipaddr6 || null, }; }); // Apply filters if (policy) { filtered = filtered.filter(n => n.policy.toLowerCase().includes(policy.toLowerCase())); } if (minSpeed > 0) { filtered = filtered.filter(n => n.speed_mbps >= minSpeed); } if (netType) { filtered = filtered.filter(n => n.type.toLowerCase().includes(netType.toLowerCase())); } // Sort by speed desc filtered.sort((a, b) => b.speed_mbps - a.speed_mbps); // Also find common IXPs for each match (check if they share other IXPs) const duration = Date.now() - start; return res.end(JSON.stringify({ meta: { duration_ms: duration, timestamp: new Date().toISOString() }, ix: { id: ixId, name: ix.name, ixlan_id: ixlanId }, total_members: netixlans.length, filtered_count: filtered.length, matches: filtered.slice(0, 50), }, null, 2)); } catch (err) { res.writeHead(500); return res.end(JSON.stringify({ error: "Peer matching failed", message: err.message })); } } module.exports = { handlePeersFind };