mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-10 13:22:18 +00:00
Merge remote-tracking branch 'origin/main' into feat/datacenters-norway-refresh
This commit is contained in:
commit
4ce28c83c0
67 files changed
+8906
-898
No files matched your search
+110
-5
@@ -1182,6 +1182,37 @@ The station reader addresses the proxy as `/api/gbfs/<encoded feed URL>`; the
|
||||
feed address is read from the path, and a query-string form is refused with a 400. GBFS refuses upstream redirects and enforces its 5 MiB response cap while
|
||||
streaming. The 12-second deadline includes reading the body, and rejected or
|
||||
stalled downloads are cancelled. Development and preview use the same handler.
|
||||
Every upstream request carries `Client-Identifier: gods-eye-view`, which Urban
|
||||
Sharing asks of clients of the Oslo, Bergen and Trondheim Bysykkel feeds
|
||||
(`gbfs.urbansharing.com`); other operators ignore it. Requests to Entur
|
||||
(`api.entur.io`, Kolumbus and Farte Bysykkel) also carry
|
||||
`ET-Client-Name: gods-eye-view-bikeshare`. Entur serves its feeds without a
|
||||
`.json` suffix, so the endpoint check accepts `station_information` and
|
||||
`station_status` with or without it. Hosts that front more than GBFS are kept to
|
||||
their GBFS tree: `api.entur.io` to `/mobility/v2/gbfs/` and `api.cyclocity.fr`
|
||||
(Bysykkel Lillestrøm) to `/contracts/`.
|
||||
|
||||
## Upstream body bounds
|
||||
|
||||
FIRMS CSV, CelesTrak TLE groups, adsb.lol military responses, TomTom flow
|
||||
tiles, OpenSky states/all and adsbdb lookups now read their bodies through the
|
||||
shared streaming readers in `src/sources/httpBody.js`, so a declared or observed body
|
||||
over the cap is refused with `RESPONSE_TOO_LARGE` and cancelled rather than
|
||||
buffered. TomTom flow tiles use `readResponseBytesCapped` alongside
|
||||
GTFS-Realtime. Each read takes the route's abort signal, so a body still
|
||||
streaming when the deadline fires is cancelled. Caps are bounds, not budgets, sized well
|
||||
above measured payloads: FIRMS 64 MiB per satellite source, CelesTrak 16 MiB
|
||||
per group, OpenSky `states/all` 8 MiB, adsb.lol `/v2/mil` 8 MiB, TomTom tiles
|
||||
8 MiB and adsbdb lookups 1 MiB. Where a route already had a deadline (FIRMS
|
||||
60 s, CelesTrak 20 s, TomTom 15 s, adsbdb 8 s, and each 10 s OpenSky
|
||||
`states/all` attempt) it already bounded the body read, because aborting a
|
||||
fetch signal also aborts its body; the capped reader takes the same signal.
|
||||
The adsb.lol military poll, which had no deadline, now waits at most 12
|
||||
seconds for headers and body together. An oversized OpenSky snapshot is not
|
||||
retried, and an OpenSky 429 starts its cooldown from the response headers and
|
||||
cancels the body unread. A rejected or timed-out body is an upstream miss and
|
||||
follows each route's existing error and cached-data paths. FIRMS map-key
|
||||
status, the OpenSky token exchange and CCTV media keep their current handling.
|
||||
|
||||
## Remaining local service modules
|
||||
|
||||
@@ -3163,7 +3194,7 @@ its criteria cannot be silently ignored.
|
||||
| CCTV | Austin + Caltrans (CA) + TfL London + Ontario 511 + Fintraffic (FI) + DriveBC (BC) + TxDOT (TX) + Estonia (Tallinn, Tarktee) + Live Traffic NSW + Open Calgary Open Data + Statens vegvesen (NO, stills + live HLS) + NYC DOT TMC (opt-in) + Street View fallback | `src/data/cctv.js` | `/api/cctv` | 10s (active) |
|
||||
| Radio | Radio Browser (public-domain station directory) | `src/data/radio.js` | `/api/radio/stations`, `/api/radio/click/:uuid` | 45 min directory refresh |
|
||||
| Transit 🚌 | Operator GTFS-Realtime VehiclePositions (7 keyless regions, `src/data/transitFeeds.js`) | `src/layers/transit/` via `src/app/layers/transit.js` | `/api/transit` | 15s (poll + delayed playback) |
|
||||
| Bikeshare 🚲 | GBFS (Lyft + BCycle) | `src/data/bikeshare.js` | `/api/gbfs` | 60s |
|
||||
| Bikeshare 🚲 | GBFS (Lyft + BCycle + Urban Sharing, Entur, JCDecaux NO) | `src/data/bikeshare.js` | `/api/gbfs` | 60s |
|
||||
| Directions 🧭 | OSRM on FOSSGIS servers (OpenStreetMap) | `src/data/directions.js` | `/api/route` (`steps=1`) | on placement / mode change |
|
||||
| Datacenters ▣ | OSM extract (bundled) | `src/data/localLayers.js` | — | static |
|
||||
| Dams ▰ | OpenInfraMap/OSM extract (bundled) | `src/data/localLayers.js` | — | static |
|
||||
@@ -3212,7 +3243,7 @@ provider draws in one colour (`PROVIDER_COLORS` in
|
||||
`src/layers/streetLevel/policy.js`); 360° cones are rings and the selected
|
||||
sequence is GEV cyan. Share options: `m` (Mapillary), `r` (the other providers' switches by id,
|
||||
e.g. `google-1` for Street View), `p` (`a`/`p`/`f` panoramas), `s` (since, days). Mapillary, Google
|
||||
Street View and KartaView are registered. Without
|
||||
Street View, KartaView and Panoramax are registered. Without
|
||||
`MAPILLARY_CLIENT_TOKEN` the panel reads KEY REQUIRED and the controls are
|
||||
disabled. With it, coverage draws as z0–5 overview points from orbit and z11–14
|
||||
sequence lines below 60 km; the proxy strips the unused `image` layer from z14
|
||||
@@ -3408,14 +3439,88 @@ photo that was opening is drawn on the new canvas instead. FIT / FILL hide
|
||||
for panoramas (`supportsRenderModes`). The
|
||||
caption has no place name (KartaView's is where the drive began) and links to
|
||||
the full-size photo through the image proxy, since kartaview.org's photo
|
||||
pages fail for signed-out visitors.
|
||||
pages fail for signed-out visitors. The viewer itself is `photoViewer.js`,
|
||||
shared with Panoramax: each provider hands it a `PhotoSources` table (first
|
||||
and sharper flat and panorama URLs, and the caption fields).
|
||||
|
||||
Panoramax (`providers/panoramax/`) is keyless and browser-side: the
|
||||
meta-catalogue `api.panoramax.xyz` (CORS open) federates every instance, and
|
||||
each picture is served by the instance holding it (OpenStreetMap France,
|
||||
IGN, MapComplete…; IGN's redirect to its OVH object storage). Its chip
|
||||
(orange, `#ff6f00`, Panoramax's own) starts off. Coverage comes from its
|
||||
vector tiles (`/api/map/{z}/{x}/{y}.mvt`, an hour's HTTP cache): sequence
|
||||
lines from z14 below 1.8 km above ground, z13 to 5 km, z12 to 12 km, z11
|
||||
to 30 km and z10 to 60 km, as Mapillary's (a dense z10 tile over Paris is
|
||||
~2.1 MB and 8,600 sequences, 750,000 points). `decode.js` simplifies each
|
||||
line (Douglas–Peucker to the segment, 4 units of a 4,096 tile: about a
|
||||
pixel where it is drawn, 6–10% of a GPS track's points), and the tiles in
|
||||
view draw their longest lines within 90,000 points (`maxPoints`,
|
||||
`keepOrder`), shared out once loading settles so a sparse tile keeps all
|
||||
it has and a dense one (a city centre) takes the rest; the selected
|
||||
sequence is always drawn. Every point becomes ~8 ground-line vertices:
|
||||
unsimplified, the lines hung the tab. Decoded tiles are kept while the
|
||||
provider is on (16, ten minutes, `tileCache.js`, shared with KartaView),
|
||||
and above
|
||||
60 km the `grid` layer's 0.1°
|
||||
density cells, binned to at most 96×96 points a tile (a z0 tile holds
|
||||
~70,000 cells) and not counted as sequences: the panel says to zoom in.
|
||||
A tile decodes in slices of about 8 ms, the page getting a turn between
|
||||
them (a 2 MB z10 tile is ~200 ms of work). A busy API (429/503) holds the
|
||||
tiles back for its Retry-After, which the browser cannot read here (the API
|
||||
exposes no headers), so the wait doubles from 5 s to 5 minutes until it
|
||||
answers; an answer may take as long as it keeps arriving (silent for 15 s
|
||||
is given up), so a slow link still gets its megabyte tiles. Both
|
||||
filters apply: lines carry their day and camera type, and a cell stays while
|
||||
it holds pictures of the kind asked for (cells are undated). A click on a
|
||||
line asks the core (`actions.openNearest`) for that sequence's picture
|
||||
nearest the click, within the camera height / 100 (50–400 m: from high up
|
||||
a click lands well off a line), without framing, then any sequence's within
|
||||
50 m. Each lookup is two searches side by side, ranked by distance in the
|
||||
browser: `place_position` (nearest first, but even at
|
||||
`place_fov_tolerance=180` it leaves out pictures looking away from the
|
||||
point) and a bounding box (those too, roughly nearest first, so 20 are
|
||||
asked for: ~60 kB, against ~600 kB for 100); the filters go to both (`filter=field_of_view=360`, `datetime=<since>/..`). A line is dated
|
||||
by its sequence's first day, so a sequence still growing can hide under
|
||||
SINCE; a line with no camera type or day stays drawn. Lines keep the
|
||||
decoded longest-first order under the per-tile cap (`keepOrder`). Once the picture is on screen
|
||||
its sequence is highlighted and drawn as cones from the z15 tiles around it
|
||||
(their `pictures` layer, ~110 bytes a picture, against ~7.5 kB for a STAC
|
||||
item), plus the neighbours within 150 m of an edge, on their own connection
|
||||
(coverage tiles take three, searches two); each tile's list for the sequence
|
||||
is kept. The open picture's own tile draws at once and the neighbours join
|
||||
as they arrive; one that fails is not counted, so a picture opening in it
|
||||
re-centres the cones there. The cones re-centre when a picture opens outside the tiles
|
||||
they were drawn from, judged from the moment their load starts, and centre
|
||||
only on a picture actually shown (never on a lookup that came back after
|
||||
the user moved on); a lookup nobody waits for any more is stopped. ‹ › follow the picture's own `prev`/`next`
|
||||
links, so stepping costs one small search per picture. The viewer shows the
|
||||
2,048 px SD derivative (equirectangular for a 360° picture, decoded at
|
||||
2,048 × 1,024) and swaps in the HD original only when the viewer is wider
|
||||
than SD (flat) or, for a panorama, expanded; once, shrunk while it decodes.
|
||||
When SD fails a flat picture falls back to the thumbnail, and to the
|
||||
original only in the expanded viewer. Every download of a photo, first or
|
||||
sharper, stops when another opens or the viewer closes. Originals wider than
|
||||
8,192 px are never fetched; a file's header (JPEG, PNG, WebP, GIF) is read
|
||||
before it decodes, and one declaring more than 64 MP or 16,384 px a side
|
||||
is refused undecoded, as is an `<img>` that decodes larger and any file
|
||||
over 48 MB. The caption names every
|
||||
producer (an uploading app and its photographer; never an account named by
|
||||
an email address), or else the instance holding the picture ("via
|
||||
panoramax.ign.fr"), and the picture's licence (CC BY-SA 4.0, Licence
|
||||
Ouverte 2.0…; StreetPose `license`), and links to the picture in the
|
||||
Panoramax viewer. Esc anywhere in the docked viewer clears the selected
|
||||
sequence before the panel can take it (KartaView too). After a GPU reset
|
||||
the viewer draws the same picture again itself (`onReopen`), leaving the
|
||||
core's lookups alone. The MCP globe panel allows the meta-catalogue and the
|
||||
three biggest instances; a picture on another instance shows only in the
|
||||
app.
|
||||
|
||||
Street Level has two browser gates. `npm run qa:street-level -- --url <server>`
|
||||
runs against real Mapillary and needs `MAPILLARY_CLIENT_TOKEN`. `npm run
|
||||
qa:street-level:fixtures -- --url <server>` answers every Mapillary request
|
||||
from fixtures (`providers/mapillary/coverageFixture.mjs`,
|
||||
`scripts/fixtures/street-level/`), so it needs no network and covers the whole
|
||||
photo flow. CI runs the fixture gate and `qa:panel-resize`
|
||||
`scripts/fixtures/street-level/`), and KartaView's and Panoramax's too, so it
|
||||
needs no network and covers the whole photo flow. CI runs the fixture gate and `qa:panel-resize`
|
||||
against a production build served by `vite preview` with a dummy token.
|
||||
|
||||
Directions is a keyless front end to the routing the voice agent already
|
||||
|
||||
Reference in new issue
Block a user