Repository navigation
Hrana WebSocket: support JSON over WebSocket (phase 1) #187
Copy link
Copy link
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Goal
Speak Hrana 3 JSON over WebSocket (hrana3 subprotocol) to sqld, selected by the JDBC URL. This is phase 1 of the Hrana WebSocket work tracked in #189.
What the code already does, and what has to change
The existing client is HTTP-pipeline-shaped in two places that do not carry over to WebSocket:
- The codec is baton-shaped.
StreamRequest/StreamResponseinlibsql-hrana-codecmodel the HTTPv3/pipelinebodies:type: "close"with nostream_id, and theHranaJsonCodecSPI isserializePipelineRequest/deserializePipelineResponse. Over WebSocket the envelope is different: aClientMsg(hello|request) andServerMsg(hello_ok|hello_error|response_ok|response_error), each stream request carries a client-assignedstream_id, andclosebecomesclose_streamwithopen_streamadded. Only the leaf structures (Stmt,StmtResult,Batch,BatchResult,Error,Value,DescribeResult) are shared. - The connection is coupled to the HTTP client and its baton.
LibsqlConnectiondepends directly on the concreteLibsqlHttpClientand derives "is a stream open" frombaton == null(beginPending()). WebSocket has no baton; the client owns astream_id. Introduce a stream-level seam (open / execute / batch / close, with error mapping) implemented by bothLibsqlHttpClient(baton) and the newLibsqlWebSocketClient(stream_id), and migrateLibsqlConnectionto depend on the seam.
Scope
libsql-hrana-codec: WS envelope models (ClientMsg/ServerMsg/request_id) and WS request/response variants (open_stream,close_stream,execute,batch,sequence,describe,store_sql,close_sql,get_autocommit— each stream op with itsstream_id), plus the JSON codec for them. Reuse the leaf serialization from the existing JSON codec.libsql-client:LibsqlWebSocketClientonjava.net.http.WebSocket(no new dependency), and the seam interface thatLibsqlHttpClientalso implements.libsql-jdbc:LibsqlUrlParser.acceptsUrlandparsegainws/wss;LibsqlDriverselects the client from the scheme;LibsqlConnectionmigrates to the seam.- Auth: HTTP sends
Authorization: Bearer <token>; WebSocket sends the same token as thejwtfield ofhello. - Handshake: offer
hrana3inSec-WebSocket-Protocol; sendhellofirst and fail the connection if the server replieshello_erroror selects an unexpected subprotocol. Text frames (opcode 0x1). - Correlation: the client assigns a
request_id, sends, and matches the response byrequest_id(the server may reorder responses). With a single outstanding request this is trivial, but the matching logic is a correctness requirement. - Busy handling: preserve the existing
SQLITE_BUSYretry/backoff semantics. The HTTP-only 429/503 branch has no WebSocket equivalent; over WebSocket a busy DB arrives as aresponse_errorwith a busycode, and must retry the same way.
Out of scope
- Cursor ops (
open_cursor/close_cursor/fetch_cursor). Nothing in the driver uses them today, and the HTTP path does not either. - Protobuf encoding (phase 2, Hrana WebSocket: support Protobuf over WebSocket (phase 2) #188).
- Any change to the HTTP transport's behavior.
- Sharing one socket across JDBC connections (the protocol supports it, but it is not needed for a synchronous driver).
Source of truth
vendor/HRANA_3_SPEC.md, "Hrana over WebSocket": the subprotocol table, hello, request/response messages, ordering, and close codes.
Acceptance (outside check)
- Unit tests: round-trip the WS envelope codec; a local fake WebSocket server asserts the hello handshake and
request_idcorrelation. Assertions check observable JDBC results, not internal frames. - Integration tests: JDBC over
ws://against the pinned sqld image (libsql.imagein the rootpom.xml) run the same basic query, transaction, and error cases the HTTP itests already cover. spotless:checkand./mvnw testpass; itests pass with the documentedDOCKER_CONFIGoverride.
Open decisions
- URL scheme. Proposed:
jdbc:libsql:ws://andjdbc:libsql:wss://, mirroringhttp/https. Alternative: keephttpURLs and select the transport with a property. - Connection model. Proposed: one WebSocket per JDBC connection. Alternative: a shared socket per URL (a pool).
- TLS for
wss. Proposed: the JDK default trust store only. Alternative: a configurable truststore. - Dropped socket. Proposed: fail the JDBC connection with an
SQLException. Transparent reconnect would lose open streams and transaction state.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity