mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
Tilted views: the visible box came from screen rays against the bare
ellipsoid and the 9 tiles kept were the ones nearest its centre, so a view
over high ground (Denver, 1,600 m up) or near the horizon dropped the
streets in front of the camera. At street zooms the rays now meet an
ellipsoid raised to the ground under the camera, hits beyond a range tied
to camera height are ignored, tilted views also keep the ground around the
camera, and tiles are ranked along the line of sight (nadir to screen
centre). Simulated with real Cesium ray maths over Sacramento and Denver
from 2 m to 1,000 m: the nearest visible ground and the screen centre are
always loaded.
Rejected token: Mapillary's 401/403 reached the panel as a raw "Mapillary
tiles HTTP 403" while the pill said ON, and every pan asked Mapillary again.
The proxy now answers a refusal as {keyRejected: true} and holds it for that
token (5 min), and a 429 with its Retry-After (held until then). The panel
reads KEY REJECTED, names MAPILLARY_CLIENT_TOKEN and Provider Settings,
gates its controls like KEY REQUIRED, requests nothing more, and clears the
message when the layer goes off. A rate limit keeps the drawn tiles and
refreshes once the wait is over.
Found in the IC8 review of #768 (P1 tile selection, P2 rejected token).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
55 lines
2.1 KiB
JavaScript
55 lines
2.1 KiB
JavaScript
import path from 'node:path';
|
||
|
||
/** Mapillary vector tile root; the path template is /{layer}/2/{z}/{x}/{y}. */
|
||
export const MAPILLARY_TILE_HOST = 'https://tiles.mapillary.com/maps/vtp';
|
||
|
||
/** Public tile layer names this proxy exposes, mapped to Mapillary's ids. */
|
||
export const TILE_LAYERS = Object.freeze({
|
||
// Overview points (z0–5), sequences (z6–14) and image points (z14 only).
|
||
// The z14 `image` point layer is ~98% of a 10 MB tile and unused here:
|
||
// image positions come from the graph API per sequence. Dropped in transit.
|
||
coverage: Object.freeze({
|
||
upstream: 'mly1_public',
|
||
minZoom: 0,
|
||
maxZoom: 14,
|
||
dropLayers: Object.freeze(['image']),
|
||
}),
|
||
});
|
||
|
||
/** Disk cache root, alongside the other providers' caches. */
|
||
export const MAPILLARY_CACHE_DIR = path.join(
|
||
process.cwd(),
|
||
'.gev-cache',
|
||
'mapillary',
|
||
);
|
||
export const TILE_DISK_DIR = path.join(MAPILLARY_CACHE_DIR, 'tiles');
|
||
|
||
/**
|
||
* Tiles change when new imagery is processed, which is far slower than the
|
||
* 15-minute upstream Cache-Control. A day keeps a session over one city from
|
||
* re-downloading its tiles on every camera move.
|
||
*/
|
||
export const TILE_DISK_TTL_MS = 24 * 60 * 60 * 1000;
|
||
|
||
/** A z14 image tile over a dense city is ~11 MB; anything past this is wrong. */
|
||
export const TILE_MAX_BYTES = 48 * 1024 * 1024;
|
||
|
||
/** In-memory tile cache budget (bytes) and upstream fetch timeout. */
|
||
export const TILE_MEMORY_BUDGET_BYTES = 96 * 1024 * 1024;
|
||
export const TILE_FETCH_TIMEOUT_MS = 60_000;
|
||
/**
|
||
* After Mapillary rejects the token (401/403), tile misses are answered from
|
||
* that verdict for this long instead of asking again on every camera move.
|
||
* A changed token is asked at once.
|
||
*/
|
||
export const TILE_KEY_REJECTED_HOLD_MS = 5 * 60 * 1000;
|
||
/** After a 429 without a usable Retry-After, hold tile misses this long. */
|
||
export const TILE_RATE_LIMIT_HOLD_MS = 60_000;
|
||
/** The longest Retry-After honoured, so a bad header cannot stall coverage. */
|
||
export const TILE_RATE_LIMIT_MAX_HOLD_MS = 10 * 60 * 1000;
|
||
|
||
/** The client token lives in the browser by design; the server adds it to tile URLs too. */
|
||
export function mapillaryToken() {
|
||
return String(process.env.MAPILLARY_CLIENT_TOKEN || '').trim();
|
||
}
|