Filo.Plug (Filo v0.2.0)

Copy Markdown View Source

A Plug that speaks Hrana over HTTP (versions 1, 2, and 3) and upgrades WebSocket requests to Filo.Socket (Hrana over WebSocket). Mount it in any Plug or Phoenix app to accept libSQL clients (django-libsql over ws, libsql-client, libsql-experimental, the libSQL SDKs).

Routes

  • GET /v1 · /v2 · /v3 · /v3-protobuf — protocol-support checks; reply 200.
  • POST /v2/pipeline · /v3/pipeline — run a pipeline of stream requests (JSON).
  • POST /v3-protobuf/pipeline — same, Protobuf-encoded (application/x-protobuf).
  • POST /v3/cursor — run a batch, streaming the result (Hrana 3, JSON).
  • POST /v3-protobuf/cursor — same, length-delimited Protobuf frames.
  • POST /v1/execute · /v1/batch — stateless Hrana 1 legacy API.
  • A WebSocket upgrade (any path) is handed to Filo.Socket.

Configuration (init/1)

  • :executor (required) — the Filo.Executor module backing each stream.
  • :streams (required) — the registered name of a Filo.Streams supervisor the host keeps in its supervision tree.
  • :key (required) — the baton signing key (Filo.Baton.new_key/0). Keep it stable for the life of the server; rotating it invalidates live batons.
  • :open_arg — host context for executor.open/1. Either a term used as-is or a 1-arity function of the Plug.Conn (e.g. to pick a database from the request). Default nil.
  • :authorize — optional host auth callback, fun(open_arg, token):ok | {:ok, context} | {:error, %Filo.Error{}}. token is the request's Authorization: Bearer credential (HTTP), or — on the WebSocket binding — the jwt the client sent in its Hrana hello (libSQL's authToken travels there, not in an upgrade header), falling back to the upgrade request's bearer token; nil when the client sent neither. Checked once per stream open (HTTP pipeline/cursor without a baton, each stateless v1 request, the WS hello) — a baton resumes a stream that was already authorized when opened. Returning {:ok, context} threads context (any host-opaque term — the verified scope, a tenant id) to executor.open/2 for every stream this connection opens; a bare :ok threads nil. A refusal is surfaced with the error's status (default 401), or as a fatal hello_error on WebSocket. Default nil (no auth — the host trusts the network).
  • :base_url — value returned in each response's base_url. Default nil.
  • :idle_timeout — per-stream inactivity timeout in ms. Default uses Filo.Stream's.

Pipeline flow

A request with no baton opens a new stream; a request with a baton resumes the stream it names. Each response carries a fresh baton for the next request (or null once the stream is closed). A reused, forged, or malformed baton, or a baton for a stream that has been closed or expired, is rejected with 400.