87 lines
2.4 KiB
JavaScript
87 lines
2.4 KiB
JavaScript
// Утилиты для получения названия ASN с кэшем в localStorage
|
|
|
|
const CACHE_KEY = 'asnNameCache.v1';
|
|
const DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 дней
|
|
|
|
function readCache() {
|
|
try {
|
|
const raw = localStorage.getItem(CACHE_KEY);
|
|
if (!raw) return {};
|
|
const data = JSON.parse(raw);
|
|
return typeof data === 'object' && data ? data : {};
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function writeCache(cache) {
|
|
try {
|
|
localStorage.setItem(CACHE_KEY, JSON.stringify(cache));
|
|
} catch { /* no-op */ }
|
|
}
|
|
|
|
function getCached(asn) {
|
|
const cache = readCache();
|
|
const entry = cache[String(asn)];
|
|
if (!entry) return null;
|
|
if (Date.now() > (entry.ts || 0)) return null;
|
|
return entry.name || null;
|
|
}
|
|
|
|
function setCached(asn, name, ttlMs = DEFAULT_TTL_MS) {
|
|
const cache = readCache();
|
|
cache[String(asn)] = { name: String(name || '').trim(), ts: Date.now() + ttlMs };
|
|
writeCache(cache);
|
|
}
|
|
|
|
async function fetchFromBGPView(asn) {
|
|
try {
|
|
const url = `https://api.bgpview.io/asn/AS${asn}`;
|
|
const res = await fetch(url, { method: 'GET' });
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
const json = await res.json();
|
|
const name = json?.data?.name || json?.data?.description || '';
|
|
return String(name || '').trim() || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function fetchFromRIPE(asn) {
|
|
try {
|
|
const url = `https://stat.ripe.net/data/as-overview/data.json?resource=AS${asn}`;
|
|
const res = await fetch(url, { method: 'GET' });
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
const json = await res.json();
|
|
const name = json?.data?.holder || json?.data?.name || '';
|
|
return String(name || '').trim() || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function getAsnName(asn, { ttlMs = DEFAULT_TTL_MS } = {}) {
|
|
const key = String(asn).trim();
|
|
if (!/^[0-9]+$/.test(key)) return null;
|
|
const cached = getCached(key);
|
|
if (cached) return cached;
|
|
// попытаемся получить из провайдеров
|
|
const providers = [fetchFromBGPView, fetchFromRIPE];
|
|
for (const p of providers) {
|
|
const name = await p(key);
|
|
if (name) {
|
|
setCached(key, name, ttlMs);
|
|
return name;
|
|
}
|
|
}
|
|
// Закэшируем пустой ответ на короткое время, чтобы не долбить API
|
|
setCached(key, '', 60 * 60 * 1000); // 1 час
|
|
return null;
|
|
}
|
|
|
|
export function getAsnNameSync(asn) {
|
|
return getCached(asn);
|
|
}
|
|
|
|
|