feat!: add Codec abstraction with JSON, MessagePack, and Raw codecs#16
Merged
Conversation
Introduces a `Codec` trait that owns a connection's `Tx` and `Rx` types and controls how each maps to a WebSocket frame. This replaces the hard-wired `serde_json`/Text-frame path with a pluggable interface, lets a single connection use asymmetric framing on send vs receive (e.g. IBKR's prefixed text out, JSON in), and supports MessagePack out of the box behind the new `msgpack` cargo feature. Breaking changes: - `Socketeer<RxMessage, TxMessage, Handler, N>` becomes `Socketeer<C: Codec, Handler, N>`; message types live on the codec - `ConnectionHandler` is now generic over the codec - `HandshakeContext` is codec-aware: codec-driven `send`/`recv` plus raw `send_text`/`send_binary`/`recv_text`/`recv_raw` escape hatches; the old `send_json`/`recv_json` helpers are gone - `ConnectOptions::custom_keepalive_message` widened from `Option<String>` to `Option<Message>` to support binary keepalives - `Error::SerializationError(serde_json::Error)` replaced with `Error::Codec(Box<dyn std::error::Error + Send + Sync>)` - New `connect_with_codec` constructor; `connect`/`connect_with` retained as shortcuts when the codec is `Default`
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #16 +/- ##
==========================================
+ Coverage 93.49% 98.52% +5.02%
==========================================
Files 4 5 +1
Lines 415 811 +396
==========================================
+ Hits 388 799 +411
+ Misses 27 12 -15 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Inline unit tests for JsonCodec, MsgPackCodec, and RawCodec covering frame-type assertions, round-trips, the back-compat Binary decode path on JsonCodec, frame-type rejections, and Error::Codec mapping for malformed payloads - Integration test for codec-driven HandshakeContext::send / recv (the typed handshake path; existing handler tests only exercised send_text / recv_text) - Integration test for the widened Option<Message> custom keepalive, using Message::Binary to confirm the connection survives a binary keepalive cycle
Adds focused tests for the gaps that remained after the initial Codec test pass: - Debug/Default/Clone impls on JsonCodec, MsgPackCodec, RawCodec - Socketeer::Debug formatter and Socketeer::next_raw_message - HandshakeContext::send_binary (round-tripped via msgpack_echo_server) - HandshakeContext::recv_text rejecting a Binary frame as Error::UnexpectedMessageType - ConnectOptions::build_request's extra_headers loop body - auth_echo_server's bad-token branch - msgpack_echo_server's SendPing and Close arms Remaining uncovered regions are unreachable!() arms (by design) and a couple of mock-server protocol-frame edges that need server-side oddities to trigger.
60116b1 to
09d7364
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Codec abstraction to decouple Socketeer’s typed send/receive API from a hard-wired JSON/Text-frame approach, enabling pluggable JSON, MessagePack (feature-gated), and raw-frame codecs, plus codec-aware handshake helpers.
Changes:
- Added
Codectrait and built-inJsonCodec,MsgPackCodec(msgpackfeature), andRawCodec. - Refactored
SocketeerandConnectionHandlerto be generic over a codec, and updatedHandshakeContextto support codec-drivensend/recvplus raw text/binary escape hatches. - Widened keepalive configuration to accept a full WebSocket
Message(enabling binary keepalives) and updated tests/docs/examples accordingly.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/codec.rs |
New codec abstraction + built-in JSON/MessagePack/Raw codecs with unit tests. |
src/lib.rs |
Refactors Socketeer generics to use Codec; updates keepalive plumbing and adds/updates tests. |
src/handler.rs |
Makes HandshakeContext and ConnectionHandler codec-aware; adds raw/typed handshake APIs. |
src/config.rs |
Changes keepalive customization from Option<String> to Option<Message>. |
src/error.rs |
Replaces JSON-specific serialization error with a generic codec error variant. |
src/mock_server.rs |
Adds a msgpack_echo_server for feature-gated MessagePack integration tests. |
README.md |
Updates documentation/examples to use codec-based API and adds MessagePack section. |
examples/echo_chat.rs |
Updates example to specify JsonCodec in Socketeer type. |
Cargo.toml / Cargo.lock |
Adds optional rmp-serde dependency and msgpack feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
So downstream consumers can walk the error chain via std::error::Error::source() and reach the underlying codec error.
With RawCodec, recv_raw returns Ok(Message::Close(_)) and RawCodec::decode is the identity, so a peer-initiated close used to leak through recv() as Ok(Close) instead of Err(WebsocketClosed) — contradicting the documented behavior. Intercept Close before delegating to the codec, and point users at recv_raw if they need to observe close frames directly.
Rename test_send_raw_receive_raw to test_raw_codec_message_roundtrip — it exercises the typed send/next_message path with RawCodec, not the raw API. Update test_next_raw_message to call send_raw alongside next_raw_message (rename to test_send_raw_next_raw_message), giving both escape-hatch methods explicit coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces a
Codectrait that owns a connection'sTxandRxtypes andcontrols how each maps to a WebSocket frame. This replaces the hard-wired
serde_json/Text-frame path with a pluggable interface, lets a singleconnection use asymmetric framing on send vs receive (e.g. IBKR's prefixed
text out, JSON in), and supports MessagePack out of the box behind the new
msgpackcargo feature.Breaking changes:
Socketeer<RxMessage, TxMessage, Handler, N>becomesSocketeer<C: Codec, Handler, N>; message types live on the codecConnectionHandleris now generic over the codecHandshakeContextis codec-aware: codec-drivensend/recvplus rawsend_text/send_binary/recv_text/recv_rawescape hatches; the oldsend_json/recv_jsonhelpers are goneConnectOptions::custom_keepalive_messagewidened fromOption<String>to
Option<Message>to support binary keepalivesError::SerializationError(serde_json::Error)replaced withError::Codec(Box<dyn std::error::Error + Send + Sync>)connect_with_codecconstructor;connect/connect_withretainedas shortcuts when the codec is
Default