-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add Hyperliquid WebSocket client #2922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
nicolad
commented
Sep 2, 2025
- Add WebSocket client, codec, and exchange modules
- Implement message handling and subscription management
- Add WebSocket client, codec, and exchange modules - Implement message handling and subscription management - Fix clippy warnings for collapsible if statements and unnecessary casts
9b92b57
to
6de9941
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @nicolad, good progress here!
@@ -72,6 +72,7 @@ serde_urlencoded = { workspace = true } | |||
strum = { workspace = true } | |||
thiserror = { workspace = true } | |||
tokio = { workspace = true } | |||
tokio-stream = { workspace = true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's interesting tokio-stream
is required, but not for the other adapters. This suggests a different pattern somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aspect | Other adapters: channel + tokio::select! (no tokio-stream ) |
This adapter: stream-first (uses tokio-stream ) |
What it says about the dep |
---|---|---|---|
Direct answer | Doesn’t need tokio-stream because it pulls from channels via recv().await and coordinates with select! . |
Needs tokio-stream when it wraps Tokio primitives as Stream s or uses stream combinators. |
Yes—different pattern. Presence of tokio-stream signals a stream-centric composition somewhere. |
Primary abstraction | Futures + channels (mpsc , broadcast ) + select! . |
Stream<Item = T> (from futures-core ) + tokio_stream::wrappers + StreamExt combinators. |
Stream API → extra crate. |
What you’ll see in code | while let Some(x) = rx.recv().await { ... } , tokio::select! { ... } . |
ReceiverStream::new(rx).map(...).merge(...).next().await , StreamMap . |
Wrappers/combinators imply tokio-stream . |
Fan-in / merging sources | Manual select! over multiple recv() branches; verbose for many/dynamic sources. |
merge , SelectAll , or StreamMap to combine many streams succinctly. |
tokio-stream added to get these tools. |
Timers / heartbeats | tokio::time::interval() polled inside loops. |
IntervalStream + combinators (timeout , throttle , chunks_timeout ). |
Time-aware ops come from tokio-stream features. |
Public API shape | Pull style: async fn next_event() -> Option<T> . |
Stream style: fn into_stream(self) -> impl Stream<Item = T> . |
Exposing a stream almost always pulls in tokio-stream . |
Composability (map/filter/batch) | Hand-rolled; more boilerplate/state machines. | One-liners with StreamExt (map , filter , chunks_timeout , etc.). |
Crate enables declarative pipelines. |
Backpressure semantics | Channel capacity controls it; explicit. | Same underlying channels; wrappers don’t change capacity. | Neutral—dependency is about ergonomics. |
Fairness/ordering | select! has randomized fairness; ordering is imperative. |
Per-stream order preserved; cross-stream order depends on combinator. | Must document semantics either way. |
Testability | Drive loops manually; custom harnesses. | collect::<Vec<_>>() , take(n) , etc. on streams simplify tests. |
Stream API often easier to test. |
Cost / deps | Fewer deps; minimal indirection. | Adds tokio-stream ; thin wrapper overhead. |
Small runtime impact; main cost is dep surface. |
If you want to remove it | Keep pull-style API; replace any wrappers with direct recv() /timeout() . |
N/A. | Run cargo udeps ; drop tokio-stream if unused. |
If you want to keep it (justify) | N/A. | You’re wrapping mpsc /broadcast /interval as streams, merging sources, or exposing a stream API. |
Consider feature-gating: stream-api = ["tokio-stream"] . |
Reply | “The other adapters use channel + select! , so they don’t need tokio-stream .” |
“This adapter embraces a Stream-based composition (wrapping channels/timers and/or using combinators), which is why tokio-stream is required.” |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more details here: https://www.vadim.blog/tokio-vs-tokio-stream-websocket-adapters