mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-09 04:44:01 +00:00
fix(satellites): a current SATCAT read is kept six hours instead of re-reading eleven groups every update; the tracking regression serves SATCAT locally
This commit is contained in:
1 parent
3bb742ae7e
commit
cc24da165b
4 files changed
+71
-2
No files matched your search
@@ -409,6 +409,15 @@ async function main() {
|
||||
status: 'ready',
|
||||
}));
|
||||
}
|
||||
// CelesTrak SATCAT, which the satellite classes read beside the TLEs.
|
||||
// An empty CSV (header only) keeps the run hermetic: the classes fall
|
||||
// back to names and groups, as they do when SATCAT is unavailable.
|
||||
if (isAppRequest && url.pathname.startsWith('/api/celestrak-satcat/')) {
|
||||
return Promise.resolve(new Response(
|
||||
'OBJECT_NAME,OBJECT_ID,NORAD_CAT_ID,OBJECT_TYPE,OPS_STATUS_CODE,LAUNCH_DATE\n',
|
||||
{ status: 200, headers: { 'Content-Type': 'text/csv' } },
|
||||
));
|
||||
}
|
||||
// CelesTrak TLE groups. Served from a fixed two-satellite catalog so
|
||||
// the satellite assertions are deterministic and the run never depends
|
||||
// on an upstream that rate-limits (it was answering 403 the night this
|
||||
|
||||
@@ -12,6 +12,13 @@ import { classifySatellite, parseSatcatCsv } from './classes.js';
|
||||
*/
|
||||
export const SATCAT_WAIT_MS = 3000;
|
||||
|
||||
/**
|
||||
* How long a complete, current SATCAT read is kept before the layer asks
|
||||
* again, ms. SATCAT changes daily and the proxy caches it a day, so the
|
||||
* five-minute TLE update does not read all eleven groups each time.
|
||||
*/
|
||||
export const SATCAT_KEEP_MS = 6 * 60 * 60 * 1000;
|
||||
|
||||
export function createIngestion({
|
||||
state: layerState,
|
||||
services,
|
||||
@@ -42,6 +49,12 @@ export function createIngestion({
|
||||
*/
|
||||
function _readSatcat(signal) {
|
||||
if (typeof source.readSatcat !== 'function') return Promise.resolve([]);
|
||||
// A complete, current read is kept; a stale or failed one is asked again.
|
||||
if (
|
||||
layerState._satcatState === 'current' &&
|
||||
Date.now() - layerState._satcatReadAtMs < SATCAT_KEEP_MS
|
||||
)
|
||||
return Promise.resolve([]);
|
||||
return Promise.all(
|
||||
CATALOG_GROUPS.map((groupDef) =>
|
||||
source
|
||||
@@ -86,6 +99,7 @@ export function createIngestion({
|
||||
if (!groups.length) return;
|
||||
const changed = layerState._satcatState !== satcatState;
|
||||
layerState._satcatState = satcatState;
|
||||
layerState._satcatReadAtMs = Date.now();
|
||||
if (satcatState !== 'current')
|
||||
console.warn(`[Data:Satellites] SATCAT ${satcatState}: classes may lag`);
|
||||
// The row's info line says so (getRowControls).
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { parseTleText, tleLineLaunchYear } from '../../sources/tle.js';
|
||||
import { SATCAT_WAIT_MS, createIngestion } from './ingestion.js';
|
||||
import {
|
||||
SATCAT_KEEP_MS,
|
||||
SATCAT_WAIT_MS,
|
||||
createIngestion,
|
||||
} from './ingestion.js';
|
||||
import { createOrbits } from './orbits.js';
|
||||
import { createControls } from './controls.js';
|
||||
|
||||
@@ -178,7 +182,9 @@ test('a satellite in visual and resource is imaging, whichever group shows it',
|
||||
t.mock.method(console, 'warn', () => {});
|
||||
// A name no pattern knows, no UCS record and no SATCAT: only its groups.
|
||||
const { state, update } = ingestionFor((path) =>
|
||||
path === 'visual' || path === 'resource' ? tleSet('ZZ TESTSAT', '50001') : '',
|
||||
path === 'visual' || path === 'resource'
|
||||
? tleSet('ZZ TESTSAT', '50001')
|
||||
: '',
|
||||
);
|
||||
await update();
|
||||
const sat = state._catalog.get(50001);
|
||||
@@ -247,3 +253,40 @@ test('a failed SATCAT read is told on the layer row, not only the console', asyn
|
||||
});
|
||||
assert.equal(current.methods.getRowControls().info, '');
|
||||
});
|
||||
|
||||
test('a current SATCAT read is kept between updates; a failed one is asked again', async (t) => {
|
||||
t.mock.method(console, 'log', () => {});
|
||||
t.mock.method(console, 'warn', () => {});
|
||||
const header =
|
||||
'OBJECT_NAME,OBJECT_ID,NORAD_CAT_ID,OBJECT_TYPE,OPS_STATUS_CODE\n';
|
||||
let reads = 0;
|
||||
let ok = true;
|
||||
const { state, update } = ingestionFor(tleSet('ZZ TESTSAT', '50003'), {
|
||||
source: {
|
||||
readSatcat: async () => {
|
||||
reads++;
|
||||
return ok
|
||||
? { ok: true, text: `${header}ZZ TESTSAT,2015-001A,50003,PAY,-` }
|
||||
: { ok: false, text: '' };
|
||||
},
|
||||
},
|
||||
});
|
||||
await update();
|
||||
const perUpdate = reads;
|
||||
assert.ok(perUpdate > 0);
|
||||
await update();
|
||||
assert.equal(reads, perUpdate, 'a fresh read is not asked again');
|
||||
assert.equal(
|
||||
state._catalog.get(50003).satelliteClass,
|
||||
'debris',
|
||||
'the held records still class the rebuilt catalog',
|
||||
);
|
||||
|
||||
state._satcatReadAtMs -= SATCAT_KEEP_MS;
|
||||
ok = false;
|
||||
await update();
|
||||
assert.equal(reads, 2 * perUpdate, 'an old read is asked again');
|
||||
assert.equal(state._satcatState, 'unavailable');
|
||||
await update();
|
||||
assert.equal(reads, 3 * perUpdate, 'a failed read is asked again');
|
||||
});
|
||||
@@ -48,6 +48,9 @@ export function createState({ services }) {
|
||||
// How current the SATCAT records behind the classes are: null before any
|
||||
// read, then 'current' | 'stale' | 'unavailable' (see ingestion.js).
|
||||
state._satcatState = null;
|
||||
// When _satcatState was last set (Date.now()); a current read is kept
|
||||
// SATCAT_KEEP_MS (src/layers/satellites/ingestion.js).
|
||||
state._satcatReadAtMs = Number.NEGATIVE_INFINITY;
|
||||
state._denseStale = false;
|
||||
|
||||
state._activeUpdateControllers = new Set();
|
||||
|
||||
Reference in new issue
Block a user