feat(rpc): add webzockets dependency for json rpc websockets#1222
Open
jbuckmccready wants to merge 49 commits intomainfrom
Open
feat(rpc): add webzockets dependency for json rpc websockets#1222jbuckmccready wants to merge 49 commits intomainfrom
jbuckmccready wants to merge 49 commits intomainfrom
Conversation
87e052b to
35e2914
Compare
- Add webzockets as a local path dependency in build.zig.zon - Wire up webzockets module in build.zig - Re-export webzockets module from src/rpc/lib.zig to include in build - Update libxev dependency with fix for error returns (compatible with zig 0.14): Syndica/libxev@11a00ee
35e2914 to
8e6b2f6
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 🚀 New features to boost your workflow:
|
Not particularly useful and takes up a lot of space in the README.md.
- Define test_webzockets job for Linux environment - Define test_webzockets_macos job for macOS environment - Update workflows to run webzockets tests on both platforms
- add RawClient wait helpers for message type, close frames, and disconnects - make read timeout configurable and default to 2s to reduce jitter flakes - update close, fragmentation, handshake, and timeout tests to use bounded waits
Sobeston
reviewed
Feb 10, 2026
Comment on lines
11
to
15
| /// Manages read buffer state with automatic tier escalation: | ||
| /// - Starts with an embedded buffer for small messages | ||
| /// - Upgrades to pooled or dynamic buffer when needed | ||
| /// - Retains larger buffer for subsequent messages (performance optimization) | ||
| /// - Restores to embedded only on explicit reset() |
Contributor
There was a problem hiding this comment.
Not convinced that we need any of this
Contributor
There was a problem hiding this comment.
I would tend to agree with the original comment here, I don't quite understand why we need this.
Author
There was a problem hiding this comment.
Comments have been cleaned up. We need a read buffer of some kind, what is the suggested change here?
Contributor
There was a problem hiding this comment.
With the merge of the 0.15 update, I think it would be worth looking at trying to use std.Io.Reader instead, and simplifying some of the requirements. My gut instinct is that most of what we actually need can be expressed through that interface.
83cd274 to
96a343e
Compare
Also removes need for pool_buffer_size field in Reader.
- remove pending_data from client and server write state - add outstandingUserWrite helper for busy, defer, and cleanup checks - clear header_len in finishWrite before invoking onWriteComplete
Update libxev dependency hash in both root and webzockets build.zig.zon
…ertNoLeaks with check() - Rename fd_leak.zig to fd_leak_detector.zig; import is now the module directly - Replace assertNoLeaks() (panics inline) with check() returning a Result enum - Call sites use: defer std.testing.expect(fd_check.check() == .ok) catch @Panic("FD leak") - Leak details logged via std.log.err instead of embedded in panic message
- Replace manual crypto random seed with std.testing.random_seed in stress test - Replace std.crypto.random.bytes with seeded PRNG in raw_client WebSocket key generation - Remove redundant default_read_buf_size constant, inline the value - Remove unnecessary @intcast on timeval fields
…G in e2e clients - Add RawClient.rng field seeded at connect time; use it for mask key generation - Seed TestEnv ClientMaskPRNG from std.testing.random_seed instead of std.crypto.random
- Change loop and server fields from pointers to inline values - Remove heap allocations and matching destroy calls for both fields
231cbaf to
f463465
Compare
- Remove comptime frameStatic and calculateFrameLen utilities with all associated tests - Extract anonymous fuzz test structs into named helpers for clarity
- Add sendRaw() to both server and client connections for sending pre-built frame data as a single write with no validation - Use header_len=1 as sentinel to distinguish raw from normal deferred writes (1 is impossible for real frame headers) - Add server and client e2e tests for text, binary, 16-bit length, and batched raw sends - Update README with sendRaw API and buffer lifetime
Also avoid panic in tests so they continue running and just std.log.err for failures.
Test runner code for Zig 0.14.1 indicates it should reset std.testing.log_level between each test but the testing level holds across all tests (bug). Removed comments for behavior that may change/break in the future.
- Add upgrade_timeout_ms config to client and server with 10_000ms default - Enforce absolute handshake deadlines in client/server handshake state machines - Cancel active I/O safely before terminal callbacks to avoid completion races - Add e2e coverage for stalled and partial upgrade responses and update docs
7e0691f to
588472a
Compare
588472a to
008a8ff
Compare
- std.DoublyLinkedList is no longer generic; use @fieldParentPtr to recover connection from node
- std.time.sleep moved to std.Thread.sleep
- std.net.Address format specifier {} is now ambiguous; use {f}
- std.ArrayList drops stored allocator; init() removed, use .empty; deinit/append now take allocator
1f8b9da to
2af680e
Compare
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.
Summary
Adds
webzocketspackage to pathsrc/rpc/webzockets.webzocketsimplements websockets in zig, built on top oflibxevfor network IO. Seesrc/rpc/webzockets/README.mdfor details on the package itself.This is only adds a websocket implementation needed to implement the json RPC websocket API. The json RPC API will be in a different PR.
Changes
Updated the
libxevversion used by sig inbuild.zig.zonto new commit (current HEAD of zig-0.14 branch): Syndica/libxev@11a00eeThis commit is on top of a slightly later version of
libxevthan we were previously using that is still compatible with zig 0.14.1, and the commit fixes error returns for thekqueuebackend (associated pull request upstream: mitchellh/libxev#207).Updated
build.zigandbuild.zig.zonwithwebzocketsdependency, and added import tosrc/rpc/lib.zigsowebzocketsis part of the build.Ran
docs/generate.pysowebzocketsREADME.md is included in the published docs.Updated
scripts/style.pyto skip cache dirs.Update 2026-02-13:
Fixed another bug in libxev where io_uring gave unexpected error on shutdown when socket already closed.
Upstream PR: mitchellh/libxev#211
Syndica fork commit: Syndica/libxev@c16162f
NOTE: for kqueue/epoll backends it could just issue
std.posix.shutdowndirectly to avoid the event loop processing entirely, but io_uring backend actually queues the shutdown command to avoid a syscall.Update 2026-02-14:
Added read pause/resume (0028053)
Removed BufferPool (51641cc), it will not be used by the jrpc server (embedded read buffer will cover sub/unsub requests) and adds complexity.
Update 2026-02-19:
Optimized close initiated by caller to not wait for handshake for the close frame response (not required by websockets RFC) and simplified logic a bit for closing. Commit: 19cf287
Update 2026-02-22:
Added
sendRawto api to allow the caller to prepare the web socket frames (header + payload), this avoids the 2 sends per message required for zero-copy use (one for header, one for payload) without having to change the backend to support vectored writes. Jrpc broadcasting benchmarks show about 50% increase in performance with this small change.Note even with vectored writes this API is useful as it allows the caller to batch an arbitrary number of websocket messages into a single TCP write buffer, avoids creating the frame on the IO loop, and can support the caller performing per-message deflate compression in the future (allowing for shared broadcasting across web socket clients utilizing per-message deflate).
Update 2026-02-24:
Fix missing timeout on handshake upgrade: 3a7db8f
Needed otherwise TCP socket can stay open indefinitely and not release associated resources.