mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat(cctv): seven camera packs, semantic labels, terrain-clear monitor planes (#433)
Seven contributed CCTV camera packs (Ontario 511, Fintraffic Finland, DriveBC, TxDOT Texas, Estonia Tallinn + Tarktee, Warendorf, Live Traffic NSW) on a fair per-pack catalog cap; semantic camera labels; monitor planes lifted clear of the terrain from a precomputed, bundled ground-height dataset. Default catalog 800 → 3,446 cameras. Full context in PR #433. Co-authored-by: sendmebits <[email protected]> Co-authored-by: avocadoAgent <[email protected]> Co-authored-by: Alex Harvey <[email protected]> Co-authored-by: Jason Meredith <[email protected]> Co-authored-by: Daniel Smith <[email protected]> Co-authored-by: Vladimir Sobolev <[email protected]> Co-authored-by: Matthias Schneider <[email protected]> Co-authored-by: Cyber Knight <[email protected]> Co-authored-by: NovaSoft Australia <[email protected]>
This commit is contained in:
51 files changed
+78682
-939
No files matched your search
@@ -0,0 +1,196 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
loadNswSourcesFromOpenData,
|
||||
nswCameraLabel,
|
||||
nswCameraToSource,
|
||||
} from '../../server/providers/cctv/sources.js';
|
||||
import {
|
||||
cctvUpstreamUserAgent,
|
||||
fetchCctvImageFromUpstream,
|
||||
} from '../../server/providers/cctv/media.js';
|
||||
import {
|
||||
NSW_CAMERAS_URL,
|
||||
NSW_IMAGE_USER_AGENT,
|
||||
} from '../../server/providers/cctv/constants.js';
|
||||
|
||||
const feature = (overrides = {}, props = {}) => ({
|
||||
type: 'Feature',
|
||||
id: '5_ways_miranda',
|
||||
geometry: { type: 'Point', coordinates: [151.1036, -34.0337] },
|
||||
properties: {
|
||||
region: 'SYD_SOUTH',
|
||||
title: '5 Ways (Miranda)',
|
||||
view: '5 Ways at The Boulevarde looking west towards Sutherland.',
|
||||
direction: 'W',
|
||||
href: 'https://webcams.transport.nsw.gov.au/livetraffic-webcams/cameras/5_ways_miranda.jpeg',
|
||||
...props,
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
|
||||
test('NSW label prefers the view sentence and falls back to the title for works notices', () => {
|
||||
assert.equal(
|
||||
nswCameraLabel({ title: '5 Ways (Miranda)', view: '5 Ways looking west.' }),
|
||||
'5 Ways looking west.',
|
||||
);
|
||||
assert.equal(
|
||||
nswCameraLabel({ title: 'Victoria Pass', view: 'x'.repeat(200) }),
|
||||
'Victoria Pass',
|
||||
);
|
||||
assert.equal(nswCameraLabel({ title: 'T', view: 'line one\nline two' }), 'T');
|
||||
assert.equal(nswCameraLabel({}), '');
|
||||
});
|
||||
|
||||
test('NSW feature maps to a source with a compass heading and a pinned image host', () => {
|
||||
const source = nswCameraToSource(feature({}, { direction: 'N-E' }));
|
||||
assert.equal(source.id, 'nsw-5_ways_miranda');
|
||||
assert.equal(source.city, 'SYD SOUTH');
|
||||
assert.equal(source.provider, 'Live Traffic NSW');
|
||||
assert.equal(source.lat, -34.0337);
|
||||
assert.equal(source.lon, 151.1036);
|
||||
assert.equal(source.headingDeg, 45);
|
||||
assert.equal(source.headingConfidence, 'high');
|
||||
assert.equal(source.sourceKind, 'nsw-livetraffic');
|
||||
assert.match(source.license, /CC BY 4.0/);
|
||||
assert.equal(source.url, source.snapshotUrl);
|
||||
});
|
||||
|
||||
test('NSW mapping rejects off-host images and unusable geometry', () => {
|
||||
assert.equal(
|
||||
nswCameraToSource(feature({}, { href: 'https://evil.example/x.jpeg' })),
|
||||
null,
|
||||
);
|
||||
assert.equal(nswCameraToSource(feature({ geometry: null })), null);
|
||||
assert.equal(nswCameraToSource(feature({ id: '' })), null);
|
||||
const noBearing = nswCameraToSource(feature({}, { direction: '' }));
|
||||
assert.equal(noBearing.headingConfidence, 'low');
|
||||
assert.ok(Number.isFinite(noBearing.headingDeg));
|
||||
});
|
||||
|
||||
test('NSW loader reads the keyless feed and caps around Sydney', async (t) => {
|
||||
t.mock.method(console, 'log', () => {});
|
||||
const requested = [];
|
||||
t.mock.method(globalThis, 'fetch', async (url) => {
|
||||
requested.push(String(url));
|
||||
return Response.json({
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
feature(),
|
||||
feature({ id: 'other' }, { href: 'https://evil.example/x.jpeg' }),
|
||||
],
|
||||
});
|
||||
});
|
||||
const cameras = await loadNswSourcesFromOpenData();
|
||||
assert.deepEqual(requested, [NSW_CAMERAS_URL]);
|
||||
assert.deepEqual(
|
||||
cameras.map((camera) => camera.id),
|
||||
['nsw-5_ways_miranda'],
|
||||
);
|
||||
});
|
||||
|
||||
test('the browser User-Agent applies to the NSW image host only', async () => {
|
||||
assert.equal(
|
||||
cctvUpstreamUserAgent(
|
||||
'https://webcams.transport.nsw.gov.au/livetraffic-webcams/cameras/x.jpeg',
|
||||
),
|
||||
NSW_IMAGE_USER_AGENT,
|
||||
);
|
||||
assert.equal(
|
||||
cctvUpstreamUserAgent(
|
||||
'https://webcams.transport.nsw.gov.au.evil.test/x.jpeg',
|
||||
),
|
||||
'gods-eye-view-cctv-proxy/1.0',
|
||||
);
|
||||
assert.equal(
|
||||
cctvUpstreamUserAgent(
|
||||
'https://example.test/webcams.transport.nsw.gov.au/x.jpeg',
|
||||
),
|
||||
'gods-eye-view-cctv-proxy/1.0',
|
||||
);
|
||||
assert.equal(
|
||||
cctvUpstreamUserAgent('not a url'),
|
||||
'gods-eye-view-cctv-proxy/1.0',
|
||||
);
|
||||
|
||||
const seen = [];
|
||||
await fetchCctvImageFromUpstream(
|
||||
'https://cctv.austinmobility.io/image/1.jpg',
|
||||
{
|
||||
timeoutMs: 100,
|
||||
fetchImpl: async (url, init) => {
|
||||
seen.push(init.headers['User-Agent']);
|
||||
return new Response(Buffer.from([0xff, 0xd8, 0xff]), {
|
||||
headers: { 'Content-Type': 'image/jpeg' },
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
assert.deepEqual(seen, ['gods-eye-view-cctv-proxy/1.0']);
|
||||
});
|
||||
|
||||
test('the frame path follows redirects within the host only', async () => {
|
||||
const jpeg = () =>
|
||||
new Response(Buffer.from([0xff, 0xd8, 0xff]), {
|
||||
headers: { 'Content-Type': 'image/jpeg' },
|
||||
});
|
||||
const redirect = (location) =>
|
||||
new Response(null, { status: 302, headers: { location } });
|
||||
const start = 'https://cctv.austinmobility.io/image/1.jpg';
|
||||
|
||||
const sameHost = [];
|
||||
const followed = await fetchCctvImageFromUpstream(start, {
|
||||
timeoutMs: 100,
|
||||
fetchImpl: async (url, init) => {
|
||||
assert.equal(init.redirect, 'manual', 'the fetch itself never follows');
|
||||
sameHost.push(url);
|
||||
return sameHost.length === 1 ? redirect('/image/moved/1.jpg') : jpeg();
|
||||
},
|
||||
});
|
||||
assert.equal(followed?.ok, true);
|
||||
assert.deepEqual(sameHost, [
|
||||
start,
|
||||
'https://cctv.austinmobility.io/image/moved/1.jpg',
|
||||
]);
|
||||
|
||||
const offHost = [];
|
||||
const refused = await fetchCctvImageFromUpstream(start, {
|
||||
timeoutMs: 100,
|
||||
fetchImpl: async (url) => {
|
||||
offHost.push(url);
|
||||
return redirect('https://evil.example/1.jpg');
|
||||
},
|
||||
});
|
||||
assert.equal(refused, null);
|
||||
assert.deepEqual(offHost, [start], 'the off-host target is never requested');
|
||||
|
||||
// Same host on another port, a plaintext downgrade, and a protocol-relative
|
||||
// other host are all a different origin and are refused.
|
||||
for (const target of [
|
||||
'https://cctv.austinmobility.io:8443/image/1.jpg',
|
||||
'http://cctv.austinmobility.io/image/1.jpg',
|
||||
'//evil.example/1.jpg',
|
||||
]) {
|
||||
const seen = [];
|
||||
const result = await fetchCctvImageFromUpstream(start, {
|
||||
timeoutMs: 100,
|
||||
fetchImpl: async (url) => {
|
||||
seen.push(url);
|
||||
return redirect(target);
|
||||
},
|
||||
});
|
||||
assert.equal(result, null, target);
|
||||
assert.deepEqual(seen, [start], target);
|
||||
}
|
||||
|
||||
let hops = 0;
|
||||
const looped = await fetchCctvImageFromUpstream(start, {
|
||||
timeoutMs: 100,
|
||||
fetchImpl: async () => {
|
||||
hops += 1;
|
||||
return redirect('/image/again.jpg');
|
||||
},
|
||||
});
|
||||
assert.equal(looped, null);
|
||||
assert.equal(hops, 3, 'at most two redirect hops are followed');
|
||||
});
|
||||
Reference in new issue
Block a user