Farsight Feeds

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

RPCRequestResponseNotes
HealthzEmptyHealthStatusLiveness.
ReadyzEmptyHealthStatusReadiness + layer/dataset counts.
GetCatalogEmptyCatalogResponseFull catalog as JSON.
ListLayersEmptyListLayersResponseLayer keys + stats.
GetLayerGetLayerRequest { key, bbox[], simplify_tolerance }LayerResponseGeoJSON for one layer.
StreamLayerGetLayerRequeststream LayerResponseServer-streamed updates every 60 s or on snapshot change.
GetDatasetGetDatasetRequest { name, property_path }DatasetResponseCatalog dataset as JSON, optionally drilled to a path.
GetFeedsGetFeedsRequest { category }FeedsResponseRSS feeds by category.
ListUpstreamsEmptyListUpstreamsResponsePer-upstream status.
RefreshUpstreamRefreshUpstreamRequest { id }UpstreamStatusForce 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 routegRPC RPC
GET /healthzHealthz
GET /readyzReadyz
GET /catalogGetCatalog
GET /layersListLayers
GET /layers/{key}GetLayer
(planned) GET /stream/{layer}StreamLayer
GET /datasets/{name}GetDataset
GET /feedsGetFeeds
GET /upstreamListUpstreams
POST /upstream/{id}/refreshRefreshUpstream

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 with GRPC_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.

On this page