gRPC Service
tonic FeedAdapter service — the Rust→Rust IPC surface parallel to the HTTP API.
The adapter exposes the same read surface over gRPC on port 50051
(GRPC_BIND). The HTTP API is the right choice for browsers and one-off
tooling; gRPC is the right choice for Rust→Rust IPC inside the cluster, and
for the one streaming RPC that is live today.
Schema: proto/feed_adapter.proto.
Service: FeedAdapter
| RPC | Request | Response | Notes |
|---|---|---|---|
Healthz | Empty | HealthStatus | Liveness. |
Readyz | Empty | HealthStatus | Readiness + layer/dataset counts. |
GetCatalog | Empty | CatalogResponse | Full catalog as JSON. |
ListLayers | Empty | ListLayersResponse | Layer keys + stats. |
GetLayer | GetLayerRequest { key, bbox[], simplify_tolerance } | LayerResponse | GeoJSON for one layer. |
StreamLayer | GetLayerRequest | stream LayerResponse | Server-streamed updates every 60 s or on snapshot change. |
GetDataset | GetDatasetRequest { name, property_path } | DatasetResponse | Catalog dataset as JSON, optionally drilled to a path. |
GetFeeds | GetFeedsRequest { category } | FeedsResponse | RSS feeds by category. |
ListUpstreams | Empty | ListUpstreamsResponse | Per-upstream status. |
RefreshUpstream | RefreshUpstreamRequest { id } | UpstreamStatus | Force one-off poll. |
10 RPCs total — 9 unary + 1 server-streaming.
StreamLayer — the one live streaming surface
Until the HTTP SSE/WebSocket streaming endpoints land, StreamLayer is the only
push surface. It emits a full LayerResponse immediately on subscribe, then
again every 60 s and on every snapshot change.
let mut stream = client
.stream_layer(GetLayerRequest { key: "ais".into(), bbox: vec![], simplify_tolerance: 0.0 })
.await?
.into_inner();
while let Some(resp) = stream.message().await? {
handle_snapshot(resp);
}For tight per-delta fan-out (CBOR/JSON over the Zenoh spine), see the planned
/stream/{layer} and /ws/{layer} HTTP endpoints in
Tiles & Streaming.
Equivalence table
| HTTP route | gRPC RPC |
|---|---|
GET /healthz | Healthz |
GET /readyz | Readyz |
GET /catalog | GetCatalog |
GET /layers | ListLayers |
GET /layers/{key} | GetLayer |
(planned) GET /stream/{layer} | StreamLayer |
GET /datasets/{name} | GetDataset |
GET /feeds | GetFeeds |
GET /upstream | ListUpstreams |
POST /upstream/{id}/refresh | RefreshUpstream |
Routes outside that table (operator control plane, vessels, analysis, satellites, alerts, webcam proxy) are HTTP-only today.
Ports & gating
- Default bind:
0.0.0.0:50051. Override withGRPC_BIND. - Same gating env vars as HTTP (
ENABLED_UPSTREAMS,CATALOG_PATH). - TLS terminates at Envoy in the production deployment; the adapter itself speaks plaintext gRPC inside the pod.