Skip to content

feat!: add Codec abstraction with JSON, MessagePack, and Raw codecs#16

Merged
zheylmun merged 7 commits into
mainfrom
feature/message_pack
May 8, 2026
Merged

feat!: add Codec abstraction with JSON, MessagePack, and Raw codecs#16
zheylmun merged 7 commits into
mainfrom
feature/message_pack

Conversation

@zheylmun
Copy link
Copy Markdown
Owner

@zheylmun zheylmun commented May 7, 2026

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

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
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 99.34498% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.52%. Comparing base (c6764ac) to head (b10d987).

Files with missing lines Patch % Lines
src/mock_server.rs 92.00% 2 Missing ⚠️
src/codec.rs 99.30% 1 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

zheylmun added 2 commits May 7, 2026 18:34
- 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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Codec trait and built-in JsonCodec, MsgPackCodec (msgpack feature), and RawCodec.
  • Refactored Socketeer and ConnectionHandler to be generic over a codec, and updated HandshakeContext to support codec-driven send/recv plus 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.

Comment thread src/mock_server.rs
Comment thread src/mock_server.rs
Comment thread src/error.rs Outdated
Comment thread src/handler.rs Outdated
Comment thread src/lib.rs
zheylmun added 4 commits May 8, 2026 09:08
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.
@zheylmun zheylmun merged commit 405dc1c into main May 8, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants