Documentation
¶
Overview ¶
Package maps wires same-origin reverse-proxies that let the SPA reach self-hosted map services (Valhalla for routing + map matching, an nginx-served PMTiles bundle for vector basemaps) through the existing rivolt origin and session cookie.
Why proxy instead of CORS-on-the-upstream:
- Most upstreams (Valhalla, the tile nginx) have no native CORS. nginx can be configured for it, but exposing each upstream behind its own ingress + cert burns hostnames for what is effectively the SPA's own data path.
- Proxying through the rivolt API keeps drive maps same-origin, reuses the existing auth middleware (routes are mounted inside the requireUser group), and lets us add per-user rate limits later without touching the cluster.
- The frontend code change shrinks to "swap base URL"; no CORS preflight handling, no second fetch credential mode.
The proxy is intentionally dumb: it forwards every request path unchanged to the upstream. Path-prefix stripping is done at mount time via http.StripPrefix in api.go, so this package only handles host rewrite and credential scrubbing.
Index ¶
- Constants
- Variables
- func AllowDEM(next http.Handler) http.Handler
- func AllowTiles(next http.Handler) http.Handler
- func AllowValhalla(next http.Handler) http.Handler
- func DEMPath(p string) bool
- func DEMTile(p string) (z, x, y int, ok bool)
- func GlyphHandler() http.Handler
- func GlyphPath(p string) (key string, ok bool)
- func GlyphSize(p string) int
- func LimitValhalla(next http.Handler) http.Handler
- func NewProxy(baseURL string) (http.Handler, error)
- type BadShapeError
- type Route
- type RouteLeg
- type RouteOpts
- type Valhalla
Constants ¶
const ( DEMMaxZoom = 12 DEMClientMinZoom = 3 DEMClientMaxZoom = 10 )
DEMMaxZoom is the deepest zoom the route admits (the recorder's own mirror holds z=12 for Texas); DEMMinZoom/DEMClientMaxZoom are what the client is told to request (the hillshade needs the coarse levels everywhere and nothing finer than z10).
const ( MaxValhallaBody = 1 << 20 MaxTraceShapePoints = 2000 MaxRouteLocations = 100 )
Ceilings on one Valhalla request, so the proxy serves what the clients draw and can't be used for bulk routing. The web and the iPhone send at most 1500 trace points plus the two parked ends to /trace_route, and the planner's /route carries the origin, the destination and up to 25 charging stops.
const GlyphMaxAge = "public, max-age=604800"
GlyphMaxAge is how long a glyph file may be cached: the files never change under a URL (a new set would be a new release), and the ETag lets a client revalidate cheaply after that.
const MaxDEMResponse = 512 << 10
MaxDEMResponse is the most a DEM tile may carry: a Terrarium tile is under 100 KB; a larger answer is the upstream serving something else.
const MaxTileResponse = 2 << 20
MaxTileResponse is the most a single tile read may carry. Real reads are a header, a directory or one tile (the largest in the 19 GB basemap is 344 KiB); 2 MiB leaves room, and anything bigger is an upstream answering something other than the byte range that was asked for.
Variables ¶
var ( GlyphFonts = []string{"Noto Sans Regular", "Noto Sans Medium", "Noto Sans Italic"} GlyphRanges = []string{"0-255", "256-511"} )
GlyphFonts and GlyphRanges are exactly what is shipped; anything else is a 404.
var ErrInvalidURL = errors.New("maps: base URL must include scheme and host")
ErrInvalidURL is returned when a configured base URL parses but is missing a scheme or host. Treated as fatal at startup so a typo in RIVOLT_VALHALLA_BASE_URL / RIVOLT_TILES_BASE_URL fails fast instead of silently dropping every drive map back to public CDNs.
var ErrNoRoute = errors.New("valhalla: no route found")
ErrNoRoute means Valhalla found no road route between the locations (a location in the ocean, or islands with no ferry). It is the caller's input, not a service failure.
Functions ¶
func AllowDEM ¶ added in v0.40.16
AllowDEM admits only GET/HEAD of a single tile path, and guards the answer: PNG only, bounded, with no cookies and a private cache header the upstream's own does not override. A tile the mirror does not hold is a 404 (the client draws no terrain there), cached briefly.
func AllowTiles ¶ added in v0.37.5
AllowTiles admits only GET/HEAD of a single top-level *.pmtiles file (Range requests are plain GETs). Directory listings, nested paths and any other file on the tile server are refused. Whatever is admitted goes through guardTiles, so a GET can only ever be answered with a bounded byte range.
func AllowValhalla ¶ added in v0.37.5
AllowValhalla admits only what the SPA uses: POST /route and POST /trace_route. Everything else (isochrone, matrix, expansion, status, any GET) is refused before it reaches Valhalla.
func DEMPath ¶ added in v0.40.16
DEMPath reports whether p (the path after /api/maps/dem) names one tile.
func DEMTile ¶ added in v0.40.16
DEMTile parses "/z/x/y.png" strictly (no leading zeros, no extra segments or characters, x and y inside the zoom's grid).
func GlyphHandler ¶ added in v0.40.16
GlyphHandler serves a glyph range from memory, with the path after /api/maps/glyphs. GET and HEAD only, an exact shipped font and range only, an ETag and a week of caching.
func GlyphPath ¶ added in v0.40.16
GlyphPath parses "/{fontstack}/{range}.pbf" for a shipped font and range, and returns the file's key. The font stack is the decoded path segment (a single font; a comma-joined stack is not served).
func GlyphSize ¶ added in v0.40.16
GlyphSize is the size in bytes of the file at a valid glyph path (0 when it is not one).
func LimitValhalla ¶ added in v0.38.19
LimitValhalla refuses a body over MaxValhallaBody (413), a /trace_route with more than MaxTraceShapePoints shape points or a /route with more than MaxRouteLocations locations (413), and anything the counts can't see (400): a query string (Valhalla reads a whole request from ?json=), a body that isn't one JSON object, an encoded_polyline (a polyline string holds points the count can't see), and a top-level key repeated or spelled in another case (Go's decoder and Valhalla's may pick different copies). Our clients send none of these. What passes is handed on with its body intact.
func NewProxy ¶
NewProxy builds a reverse-proxy handler that forwards to baseURL. The empty string returns (nil, nil) - callers (api.New) treat nil as "feature off" and skip mounting the route.
baseURL is typically a cluster-internal Service address ("http://valhalla.valhalla.svc.cluster.local", "http://tiles.tiles.svc.cluster.local").
Types ¶
type BadShapeError ¶ added in v0.40.19
type BadShapeError struct {
Kind string // "offglobe" or "detour": which check refused it (the recorder's refusal counter is labelled by it)
Reason string
}
BadShapeError is RouteShape's answer when the routing engine's shape cannot be a road between the ends. The recorder counts these apart from a routing engine that is merely down (it recognises the BadShape method, so it needs no import of this package).
func (*BadShapeError) BadShape ¶ added in v0.40.19
func (e *BadShapeError) BadShape() bool
func (*BadShapeError) Error ¶ added in v0.40.19
func (e *BadShapeError) Error() string
func (*BadShapeError) ShapeKind ¶ added in v0.40.19
func (e *BadShapeError) ShapeKind() string
type Route ¶ added in v0.37.0
type Route struct {
Legs []RouteLeg
}
Route is a Valhalla route through an ordered list of locations.
type RouteLeg ¶ added in v0.37.0
type RouteLeg struct {
LengthMeters float64
TimeSec float64
// Shape is the leg's road geometry as (lat, lon) pairs.
Shape [][2]float64
}
RouteLeg is one leg of a Route: from one location to the next.
type Valhalla ¶
Valhalla is a thin server-to-server client for the in-cluster Valhalla routing service. It exists alongside the same-origin reverse proxy (NewProxy in this package) — the proxy is for the SPA, this client is for backend code that wants a routing answer directly without going through the user-facing HTTP path.
Today the only consumer is the live recorder's GPS-gap fill: when the WS feed drops fixes for several seconds, we ask Valhalla what road-level path is most likely between the last good fix and the new one, and splice that shape into the drive polyline so the rendered trace doesn't contain a straight-line shortcut across whatever the car actually drove.
func NewValhalla ¶
NewValhalla returns a client pointed at baseURL. Empty baseURL returns nil — callers must nil-check and skip the feature.
func (*Valhalla) Route ¶ added in v0.37.0
Route asks Valhalla for the auto route through locs (lat, lon pairs, at least two, every one a stop so each gap is its own leg) in one request, and returns per-leg length, time and shape. It sits beside RouteShape, which stays as it is.
func (*Valhalla) RouteShape ¶
RouteShape returns the on-road shape between two points as a sequence of (lat, lon) pairs, derived from a Valhalla /route call with auto costing. Used by the recorder to fill GPS-lag gaps with a plausible road-snapped path. The returned slice INCLUDES the requested endpoints (Valhalla always echoes them as the first/last shape vertex).
The context's deadline bounds the upstream call. Callers should pass a tight timeout (a few hundred ms) — if Valhalla can't answer quickly it's better to fall back to a straight line than to delay the live recorder.