mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(space): respect provider cooldowns and bound TLE groups
This commit is contained in:
1 parent
de2138e84c
commit
9d3d5164fe
7 files changed
+196
-16
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import path from 'node:path';
|
||||
import { providerCooldownMs } from './cooldown.js';
|
||||
import { promises as fsp } from 'node:fs';
|
||||
import {
|
||||
readResponseTextCapped,
|
||||
@@ -30,6 +31,8 @@ export function rocketLaunchesProxy() {
|
||||
'launch-library-2-v2.3.json',
|
||||
);
|
||||
let cache = null;
|
||||
let cooldownUntil = 0;
|
||||
let cooldownStatus = 502;
|
||||
let diskLoaded = false;
|
||||
const inFlight = new Map();
|
||||
|
||||
@@ -62,7 +65,18 @@ export function rocketLaunchesProxy() {
|
||||
function send(res, status, body, cacheState) {
|
||||
res.writeHead(status, {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': status === 200 ? 'public, max-age=900' : 'no-store',
|
||||
'Cache-Control':
|
||||
status === 200 && cacheState !== 'STALE-ERROR'
|
||||
? 'public, max-age=900'
|
||||
: 'no-store',
|
||||
...(cache ? { 'X-GEV-Cached-At': new Date(cache.at).toISOString() } : {}),
|
||||
...(Date.now() < cooldownUntil
|
||||
? {
|
||||
'Retry-After': String(
|
||||
Math.ceil((cooldownUntil - Date.now()) / 1000),
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
'X-GEV-Cache': cacheState,
|
||||
});
|
||||
res.end(body);
|
||||
@@ -75,17 +89,21 @@ export function rocketLaunchesProxy() {
|
||||
signal: AbortSignal.timeout(20000),
|
||||
headers: launchLibraryRequestHeaders(),
|
||||
});
|
||||
const body = await readResponseTextCapped(upstream, maxResponseBytes);
|
||||
if (!upstream.ok) {
|
||||
cooldownUntil = Date.now() + providerCooldownMs(upstream);
|
||||
cooldownStatus = upstream.status;
|
||||
void upstream.body?.cancel().catch(() => {});
|
||||
const error = new Error(`upstream HTTP ${upstream.status}`);
|
||||
error.upstreamStatus = upstream.status;
|
||||
throw error;
|
||||
}
|
||||
const body = await readResponseTextCapped(upstream, maxResponseBytes);
|
||||
const parsed = JSON.parse(body);
|
||||
if (!Array.isArray(parsed?.results))
|
||||
throw new Error('malformed upstream response');
|
||||
const fresh = { at: Date.now(), body };
|
||||
cache = fresh;
|
||||
cooldownUntil = 0;
|
||||
void saveDiskCache(fresh);
|
||||
return fresh;
|
||||
}
|
||||
@@ -103,6 +121,16 @@ export function rocketLaunchesProxy() {
|
||||
return;
|
||||
}
|
||||
const stale = cache;
|
||||
if (now < cooldownUntil) {
|
||||
send(
|
||||
res,
|
||||
stale ? 200 : cooldownStatus,
|
||||
stale?.body ||
|
||||
JSON.stringify({ error: 'Launch Library 2 unavailable' }),
|
||||
stale ? 'STALE-ERROR' : 'NONE',
|
||||
);
|
||||
return;
|
||||
}
|
||||
const request = coalesceProxyRequest(
|
||||
inFlight,
|
||||
'recent-launches',
|
||||
@@ -112,6 +140,10 @@ export function rocketLaunchesProxy() {
|
||||
const fresh = await request.promise;
|
||||
send(res, 200, fresh.body, request.shared ? 'INFLIGHT' : 'MISS');
|
||||
} catch (error) {
|
||||
if (Date.now() >= cooldownUntil) {
|
||||
cooldownUntil = Date.now() + 60000;
|
||||
cooldownStatus = 502;
|
||||
}
|
||||
// Log only a bounded status, never upstream bodies, URLs, or credentials.
|
||||
const status = Number.isInteger(error?.upstreamStatus)
|
||||
? error.upstreamStatus
|
||||
|
||||
Reference in new issue
Block a user