Repository navigation
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.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity