mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(cctv): give Tarktee's slow DATEX feeds 30 s instead of the shared 15 s
The Estonian Transpordiamet feeds answered in 2 to 16.6 s across ten
requests (120 and 160 KB), and both must arrive for any camera to load,
so the shared 15 s catalog timeout dropped the whole pack on about a
third of loads ("Tarktee DATEX download error: The operation was aborted
due to timeout"), for the 15 minutes until the next catalog refresh.
TARKTEE_FETCH_TIMEOUT_MS gives the two requests 30 s; other packs keep
15 s.
Live: 175 cameras in 3.3 s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
93ea088f45
commit
6b3f7a3ec1
3 files changed
+33
-2
No files matched your search
@@ -439,6 +439,10 @@ export const CCTV_SOURCE_CACHE_MS = 15 * 60 * 1000;
|
|||||||
* pending forever — a hung fetch aborts, the loader returns [], and
|
* pending forever — a hung fetch aborts, the loader returns [], and
|
||||||
* serve-stale/other packs take over. */
|
* serve-stale/other packs take over. */
|
||||||
export const CCTV_SOURCE_FETCH_TIMEOUT_MS = 15 * 1000;
|
export const CCTV_SOURCE_FETCH_TIMEOUT_MS = 15 * 1000;
|
||||||
|
/** Tarktee's two DATEX feeds (120 and 160 KB) answered in 2 to 16.6 s across
|
||||||
|
* ten requests on 2026-10-18, so the shared 15 s timeout dropped the Estonian
|
||||||
|
* pack on about a third of loads. Both must arrive for any camera to load. */
|
||||||
|
export const TARKTEE_FETCH_TIMEOUT_MS = 30 * 1000;
|
||||||
/** Individual CCTV image fetches must settle before the active 10-second
|
/** Individual CCTV image fetches must settle before the active 10-second
|
||||||
* client refresh cadence. A bounded miss can fall through to Street View or
|
* client refresh cadence. A bounded miss can fall through to Street View or
|
||||||
* the synthetic frame instead of leaving the browser preview pending. */
|
* the synthetic frame instead of leaving the browser preview pending. */
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import {
|
|||||||
TORONTO_GROUND_ELEVATION_M,
|
TORONTO_GROUND_ELEVATION_M,
|
||||||
TORONTO_MAX_CATALOG_BYTES,
|
TORONTO_MAX_CATALOG_BYTES,
|
||||||
CCTV_SOURCE_FETCH_TIMEOUT_MS,
|
CCTV_SOURCE_FETCH_TIMEOUT_MS,
|
||||||
|
TARKTEE_FETCH_TIMEOUT_MS,
|
||||||
DELDOT_CCTV_URL,
|
DELDOT_CCTV_URL,
|
||||||
DEFAULT_DELDOT_MAX_SOURCES,
|
DEFAULT_DELDOT_MAX_SOURCES,
|
||||||
DELDOT_ANCHORS,
|
DELDOT_ANCHORS,
|
||||||
@@ -1194,11 +1195,11 @@ export async function loadTarkteeSourcesFromDatex() {
|
|||||||
const [locResp, imgResp] = await Promise.all([
|
const [locResp, imgResp] = await Promise.all([
|
||||||
fetch(TARKTEE_LOCATIONS_URL, {
|
fetch(TARKTEE_LOCATIONS_URL, {
|
||||||
headers: { Accept: 'application/xml,text/xml,*/*' },
|
headers: { Accept: 'application/xml,text/xml,*/*' },
|
||||||
signal: AbortSignal.timeout(CCTV_SOURCE_FETCH_TIMEOUT_MS),
|
signal: AbortSignal.timeout(TARKTEE_FETCH_TIMEOUT_MS),
|
||||||
}),
|
}),
|
||||||
fetch(TARKTEE_IMAGES_URL, {
|
fetch(TARKTEE_IMAGES_URL, {
|
||||||
headers: { Accept: 'application/xml,text/xml,*/*' },
|
headers: { Accept: 'application/xml,text/xml,*/*' },
|
||||||
signal: AbortSignal.timeout(CCTV_SOURCE_FETCH_TIMEOUT_MS),
|
signal: AbortSignal.timeout(TARKTEE_FETCH_TIMEOUT_MS),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
if (!locResp.ok) {
|
if (!locResp.ok) {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { test } from 'node:test';
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import {
|
import {
|
||||||
loadTallinnSourcesFromCatalog,
|
loadTallinnSourcesFromCatalog,
|
||||||
|
loadTarkteeSourcesFromDatex,
|
||||||
parseTarkteeDatexImages,
|
parseTarkteeDatexImages,
|
||||||
parseTarkteeDatexLocations,
|
parseTarkteeDatexLocations,
|
||||||
} from '../../server/providers/cctv/sources.js';
|
} from '../../server/providers/cctv/sources.js';
|
||||||
|
import { TARKTEE_FETCH_TIMEOUT_MS } from '../../server/providers/cctv/constants.js';
|
||||||
|
|
||||||
const SAMPLE_LOCATIONS_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
const SAMPLE_LOCATIONS_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<d2LogicalModel xmlns="http://datex2.eu/schema/2/2_0">
|
<d2LogicalModel xmlns="http://datex2.eu/schema/2/2_0">
|
||||||
@@ -84,3 +86,27 @@ test('Tarktee DATEX image parser rejects non-official hosts', () => {
|
|||||||
const images = parseTarkteeDatexImages(xml);
|
const images = parseTarkteeDatexImages(xml);
|
||||||
assert.equal(images.size, 0);
|
assert.equal(images.size, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Tarktee DATEX requests wait 30 s, past the slow answers measured live', async (t) => {
|
||||||
|
const timeouts = [];
|
||||||
|
const timeout = AbortSignal.timeout;
|
||||||
|
t.mock.method(AbortSignal, 'timeout', (ms) => {
|
||||||
|
timeouts.push(ms);
|
||||||
|
return timeout.call(AbortSignal, ms);
|
||||||
|
});
|
||||||
|
t.mock.method(console, 'log', () => {});
|
||||||
|
t.mock.method(
|
||||||
|
globalThis,
|
||||||
|
'fetch',
|
||||||
|
async (url) =>
|
||||||
|
new Response(
|
||||||
|
String(url).includes('roadCameraLocations')
|
||||||
|
? SAMPLE_LOCATIONS_XML
|
||||||
|
: SAMPLE_IMAGES_XML,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const cameras = await loadTarkteeSourcesFromDatex();
|
||||||
|
assert.deepEqual(timeouts, [30_000, 30_000]);
|
||||||
|
assert.equal(TARKTEE_FETCH_TIMEOUT_MS, 30_000);
|
||||||
|
assert.equal(cameras.length, 1);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user