mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
feat(layers): GNSS interference layer from ADS-B NIC/NACp integrity
Bins airborne ADS-B v1/v2 aircraft that report degraded navigation integrity (NIC < 7, NACp < 8, or readsb's GPS-loss flag) into 0.5 degree cells over a rolling 30-minute window, coloured with the gpsjam.org bands. Keyless: reads the capped adsb.lol point snapshot around the view through /api/gnss-integrity, which returns integrity fields only, caches 60 s per whole-degree anchor, backs off on upstream 429 and serves the last snapshot on failure. Adds scripts/qa-gnss.mjs. Built by the Hex project (Crew Leo Agile dev team). Co-Authored-By: Claude <[email protected]>
This commit is contained in:
1 parent
f71da95e91
commit
eefcb338b3
26 files changed
+1389
-4
No files matched your search
@@ -0,0 +1,59 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { createAdsbGnssSource } from './source.js';
|
||||
|
||||
test('the source asks the same-origin proxy for the view anchor', async () => {
|
||||
const calls = [];
|
||||
const source = createAdsbGnssSource({
|
||||
fetchImpl: async (url, options) => {
|
||||
calls.push(url);
|
||||
assert.ok(options.signal instanceof AbortSignal);
|
||||
return Response.json({ fetchedAt: 5, rows: [{ hex: 'abc123' }] });
|
||||
},
|
||||
});
|
||||
const snapshot = await source.getSnapshot(
|
||||
{ latitude: 50.06143, longitude: 19.93658 },
|
||||
{ signal: new AbortController().signal },
|
||||
);
|
||||
assert.deepEqual(calls, ['/api/gnss-integrity?lat=50.06&lon=19.94']);
|
||||
assert.deepEqual(snapshot, {
|
||||
rows: [{ hex: 'abc123' }],
|
||||
fetchedAt: 5,
|
||||
stale: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('the source reports stale proxy data and rejects bad input or responses', async () => {
|
||||
const reply = (body, init) => async () => Response.json(body, init);
|
||||
const stale = await createAdsbGnssSource({
|
||||
fetchImpl: reply({ rows: [], stale: true }),
|
||||
}).getSnapshot({ latitude: 1, longitude: 2 });
|
||||
assert.equal(stale.stale, true);
|
||||
assert.equal(stale.fetchedAt, null);
|
||||
|
||||
await assert.rejects(
|
||||
createAdsbGnssSource({ fetchImpl: reply({}) }).getSnapshot({}),
|
||||
/view anchor/,
|
||||
);
|
||||
await assert.rejects(
|
||||
createAdsbGnssSource({
|
||||
fetchImpl: reply({ error: 'x' }, { status: 502 }),
|
||||
}).getSnapshot({ latitude: 1, longitude: 2 }),
|
||||
/HTTP 502/,
|
||||
);
|
||||
await assert.rejects(
|
||||
createAdsbGnssSource({ fetchImpl: reply({ rows: 'no' }) }).getSnapshot({
|
||||
latitude: 1,
|
||||
longitude: 2,
|
||||
}),
|
||||
/Malformed/,
|
||||
);
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
await assert.rejects(
|
||||
createAdsbGnssSource({ fetchImpl: reply({ rows: [] }) }).getSnapshot(
|
||||
{ latitude: 1, longitude: 2 },
|
||||
{ signal: controller.signal },
|
||||
),
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user