|
|
||
|---|---|---|
| .. | ||
| scripts | ||
| src | ||
| test | ||
| zone-sources | ||
| .dockerignore | ||
| Dockerfile | ||
| README.md | ||
| package.json | ||
| runtime-entrypoint.mjs | ||
README.md
NODE.DC Map Gateway
map-gateway — единый платформенный boundary для map providers. Он не является частью Engine и не принадлежит отдельному Module Studio application.
Что делает
- хранит master Cesium Ion token только в private runtime storage: первоначально он может прийти из server environment, а после admin rotation — из закрытого файла в NAS volume;
- никогда не выдаёт browser-у master, asset-scoped Cesium token или Bing key: endpoint response содержит только публичный provider URL, а Gateway подставляет credential в свой upstream request;
- проксирует и кэширует tile/3D Tiles/terrain resources через
GET /api/map/cache?url=<https-url>; - может отдать перенесённый локальный Engine snapshot через
MAP_GATEWAY_LEGACY_CACHE_HOSTS, но никогда не догружает для него cache miss из сети; - работает с persistent volume, а не с Git или Docker image layer;
- при upstream outage отдаёт ранее сохранённый cache object; offline режим включается только для providers, явно разрешённых их лицензией;
- защищает proxy allowlist-ом upstream hosts, HTTPS-only правилом, лимитами размера и token-free cache key;
- ведёт лёгкий persistent cache index и health/stats без автоматического удаления уже записанных tiles.
- отдаёт Engine отдельный provider-neutral generation геозон из проверенного профиля: текущий backend — версионированный snapshot Дептранса, будущий API-адаптер обязан материализовать тот же envelope и не меняет L2-потребителя.
API
GET /healthz
GET /api/map/ion/assets/:assetId/endpoint
GET|HEAD /api/map/cache?url=<encoded-upstream-url>
Внутренний route GET|HEAD /internal/zone-sources/v1/profiles/moscow-pmd-slow-zones/current доступен сервисам в private engine network и намеренно не публикуется через Caddy. На старте Gateway проверяет manifest, SHA-256 обоих исходных JSON, геометрию, замкнутость колец, уникальность identity, расписание и его связи с зонами; повреждённый или неполный generation останавливает запуск. Сейчас profile упакован в image как immutable MMap snapshot. Для будущего Дептранс API меняется producer профиля (depttrans-api-snapshot-v1), но endpoint, stable source IDs и nodedc.zone-source-generation/v2 остаются прежними.
Внутренний admin route GET|PUT /api/map/admin/cesium-ion не является Browser API: он доступен только из Foundry по HMAC. Ключ подписи создаётся и хранится root-owned deploy runner в /volume1/docker/nodedc-platform/secrets/map-gateway-admin-secret, а оба сервиса получают только read-only file mount. Он не является .env-значением, настройкой Foundry или Cesium credential. Перед записью PUT проверяет candidate token через Cesium asset endpoints 1 (terrain), 2 (imagery) и 96188 (3D Buildings). Не прошедшее проверку значение не заменяет рабочее. Успешный token записывается атомарно в ${MAP_CACHE_DIR}/secrets/cesium-ion-token с mode 0600; ответ содержит только факт конфигурации, safe verification state и audit metadata — никогда само значение.
/api/map/ion/assets/:assetId/endpoint разрешает только CESIUM_ION_ASSET_ALLOWLIST. Ответ не содержит credential: Browser использует публичный provider URL вместе с Cesium DefaultProxy, направляющим resource requests в /api/map/cache. Gateway валидирует scope URL, удаляет любые credential query parameters из browser request и добавляет соответствующий server-side credential только перед обращением к provider.
Ion endpoint metadata с asset credential сохраняется только в private persistent storage с файловыми правами 0600. Это нужно для cold start и offline: Browser по-прежнему получает только sanitised URL, а Gateway отвечает из ранее записанного cache. В metadata никогда не записывается master token; NAS backup этого каталога считается service-sensitive.
Cache modes
readwrite— при включённомНе перезаписывать cacheотдаёт уже записанный object прямо из общего TileCache; только miss идёт к официальному upstream и атомарно дописывается. Явныйrefreshviewport получает live response и заменяет объект;readonly— отдаёт ранее записанный object из TileCache; новый object через Gateway может быть показан live, но не записывается;offline— никогда не идёт наружу; cache miss возвращает504.
nodedc_cache_refresh=1 — единственный путь заменить уже записанный объект. Без него существующий object всегда отдаётся прямо с NAS и вообще не обращается к Ion/AMD/VPN. Foundry создаёт refresh либо когда Application явно разрешил обновление cache, либо для одноразового действия «Обновить текущий viewport». При достижении MAP_CACHE_MAX_MB Gateway не удаляет LRU-объекты: новый miss продолжает live-маршрут без записи с x-nodedc-map-cache: live-pass-through-cache-full.
Первый cold miss начинает стримиться клиенту сразу после provider headers и одновременно записывается в private temp-файл. Только полностью полученный object публикуется через atomic rename и durable index.json; partial/error никогда не становится cache entry. Одинаковые параллельные misses делят один upstream download, а отмена одного browser request не прерывает server-owned fill для других инстансов. Warm hit не меняет index. Параллельные новые объекты объединяются в минимальное число полных index snapshots вместо одного O(N) rewrite на каждый tile.
offline дополнительно требует, чтобы hostname был явно указан в MAP_GATEWAY_OFFLINE_PROVIDER_ALLOWLIST. По умолчанию список пуст: Gateway не превращает Cesium ion или public OSM tile service в offline distribution. Это осознанная provider policy, а не техническая ошибка cache.
Range requests пока transparently проксируются и не записываются как partial cache object. Полные GET responses кэшируются. Это безопасная начальная граница для terrain/3D Tiles; отдельным следующим шагом добавляется range-aware chunk cache после замеров реальных GOS/3D Tiles assets.
Persistent storage
Production Platform Compose использует два NAS host directories: mutable /volume1/docker/nodedc-platform/map-gateway/live-tile-cache монтируется в /var/lib/nodedc-map-live-cache, read-only /volume1/docker/nodedc-platform/map-gateway/offline-snapshot — в /var/lib/nodedc-map-offline-snapshot. Их создаёт root-owned deploy runner при первом Map Gateway rollout. Они намеренно исключены из Git и artifact; Compose teardown их не удаляет. При необходимости offline seed доставляется отдельным export/import artifact, а не коммитом runtime cache.
Внутри mutable volume имеется service-sensitive подкаталог secrets/: там лежит только текущий Cesium Ion master token и metadata последнего изменения. Это не TileCache, не часть offline export и не объект SMB-операций. Gateway создаёт его с directory mode 0700, files 0600; не включать его в backup, export или diagnostic archive без отдельной процедуры секретов.
Кэш не способен создать участок карты, который никогда не был скачан. Для целевых офлайн-регионов нужен отдельный licensed dataset/provider и его seed/prefetch job: он заранее проходит разрешённые assets, zoom-диапазоны и географические области, записывает их в тот же persistent volume и формирует проверяемый export/import artifact. Эта задача не смешивается с runtime gateway и не помещает binary tiles в историю репозитория.
Legacy Engine cache: локальный перенос без изменения Engine
В локальной Studio-песочнице существующий Engine cache можно скопировать в persistent volume как неизменяемый входной snapshot. Исходная директория Engine при этом только читается: import job не удаляет, не переименовывает и не изменяет ни одного её файла.
npm run audit:engine-cache -- /absolute/path/to/nodedc-data/api/cesium/manifest.json
Команда audit выдаёт агрегированный отчёт: hosts, число объектов, declared/on-disk размер и отсутствующие файлы. Сам перенос выполняется отдельно, после остановки gateway на время записи index:
npm run import:engine-cache -- /absolute/path/to/nodedc-data/api/cesium/manifest.json /persistent/map-tile-cache
По умолчанию действует режим no-overwrite: если объект уже присутствует в новом cache, он остаётся без изменений. --dry-run выводит план без копирования, --refresh разрешает осознанно заменить уже импортированный объект. Legacy http URLs нормализуются до https, чтобы совпасть с HTTPS-only Gateway; сами файлы, content-type, etag, timestamp и provenance сохраняются в новом index/import report.
Это sandbox-механизм переноса уже существующей локальной реализации. Для внешней коммерческой публикации потребуется отдельная provider/offline policy; она не блокирует текущую локальную миграцию, но и не должна смешиваться с ней. Runtime cache по-прежнему не попадает в Git или Docker image layer.
Security and access
В local dev допускается MAP_GATEWAY_ALLOW_ANONYMOUS=true. В production он должен быть false; Caddy/Auth BFF проверяет Authentik session и передаёт очищенный trusted subject header в private platform network. Нельзя открывать gateway напрямую наружу и нельзя принимать user-provided upstream hosts вне allowlist.
Required environment
# Optional migration bootstrap; the private token file is preferred after an
# admin has configured it through Foundry.
CESIUM_ION_TOKEN=
# Production: runner-owned NODEDC_MAP_GATEWAY_ADMIN_SECRET_FILE is mounted
# automatically. Do not put the secret into an env file.
CESIUM_ION_ASSET_ALLOWLIST=1,2,96188
CESIUM_ION_ENDPOINT_TTL_SECONDS=300
CESIUM_ION_ENDPOINT_REFRESH_AHEAD_SECONDS=60
MAP_GATEWAY_UPSTREAM_ALLOWLIST=api.cesium.com,assets.ion.cesium.com,tile.openstreetmap.org,dev.virtualearth.net,ecn.t0.tiles.virtualearth.net,ecn.t1.tiles.virtualearth.net,ecn.t2.tiles.virtualearth.net,ecn.t3.tiles.virtualearth.net
MAP_GATEWAY_LEGACY_CACHE_HOSTS=ecn.t0.tiles.virtualearth.net,ecn.t1.tiles.virtualearth.net,ecn.t2.tiles.virtualearth.net,ecn.t3.tiles.virtualearth.net
MAP_GATEWAY_OFFLINE_PROVIDER_ALLOWLIST=
MAP_CACHE_DIR=/var/lib/nodedc-map-cache
MAP_CACHE_MODE=readwrite
Cache topology
MAP_CACHE_DIR is the mutable live cache. In the production Platform
compose profile it is bind-mounted from the NAS path
/volume1/docker/nodedc-platform/map-gateway/live-tile-cache and is the only
store that can receive new upstream objects.
MAP_OFFLINE_SNAPSHOT_DIR is optional and mounted read-only as
/volume1/docker/nodedc-platform/map-gateway/offline-snapshot. It is
populated only by the controlled Engine cache import. Requests marked with the
offline cache profile are served exclusively from this snapshot; a missing
tile returns a cache miss and never reaches an upstream provider.