Skip to content
This repository was archived by the owner on Feb 22, 2026. It is now read-only.

Commit f4b1a74

Browse files
committed
feat: support multiple tungstenite versions
1 parent d25a3ca commit f4b1a74

13 files changed

Lines changed: 501 additions & 76 deletions

.github/workflows/rust.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ jobs:
4444
components: clippy
4545
- uses: Swatinem/rust-cache@v2
4646
- name: Build
47-
run: cargo build --workspace --all-features
47+
run: cargo build --workspace --features client-cynic,client-graphql-client,ws_stream_wasm
4848
- name: Build tests
49-
run: cargo test --workspace --all-features --no-run
49+
run: cargo test --workspace --no-run --features client-cynic,client-graphql-client,ws_stream_wasm
5050
- name: Run tests
51-
run: cargo test --workspace --all-features
51+
run: cargo test --workspace --features client-cynic,client-graphql-client,ws_stream_wasm
5252
- name: Build examples
53-
run: cargo build --workspace --all-features --examples
53+
run: cargo build --workspace --features client-cynic,client-graphql-client,ws_stream_wasm --examples
5454
- name: Build examples tests
55-
run: cargo test --workspace --all-features --examples --no-run
55+
run: cargo test --workspace --features client-cynic,client-graphql-client,ws_stream_wasm --examples --no-run
5656
- name: Run examples tests
57-
run: cargo test --workspace --all-features --examples
57+
run: cargo test --workspace --features client-cynic,client-graphql-client,ws_stream_wasm --examples
5858
- name: Run clippy
59-
run: cargo clippy --all --all-features
59+
run: cargo clippy --all --features client-cynic,client-graphql-client,ws_stream_wasm

Cargo.lock

Lines changed: 78 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,20 @@ members = ["examples", "examples-wasm"]
2828
[features]
2929
default = ["logging"]
3030
logging = ["dep:log"]
31-
tungstenite = ["dep:tungstenite"]
31+
sink_ext = []
32+
3233
client-cynic = ["cynic"]
3334
client-graphql-client = ["graphql_client"]
35+
3436
ws_stream_wasm = ["dep:ws_stream_wasm", "dep:pharos"]
3537

38+
"tungstenite-0.23" = ["dep:tungstenite-0-23", "sink_ext"]
39+
"tungstenite-0.24" = ["dep:tungstenite-0-24", "sink_ext"]
40+
"tungstenite-0.25" = ["dep:tungstenite-0-25", "sink_ext"]
41+
"tungstenite-0.26" = ["dep:tungstenite-0-26", "sink_ext"]
42+
"tungstenite-0.27" = ["dep:tungstenite-0-27", "sink_ext"]
43+
"tungstenite-0.28" = ["dep:tungstenite-0-28", "sink_ext"]
44+
3645
[dependencies]
3746
async-channel = "2"
3847
futures-lite = "2"
@@ -44,18 +53,27 @@ serde = { version = "1.0", features = ["derive"] }
4453
serde_json = "1.0"
4554
thiserror = "2.0.16"
4655

56+
# Client specific optional deps
4757
cynic = { version = "3", optional = true }
48-
tungstenite = { version = ">=0.23, <=0.24", optional = true }
4958
graphql_client = { version = "0.14.0", optional = true }
5059

60+
# Websocket specific optional deps
5161
ws_stream_wasm = { version = "0.7", optional = true }
5262
pharos = { version = "0.5.2", optional = true }
5363

64+
# Tungstenite versions
65+
tungstenite-0-23 = { version = "0.23", optional = true, package = "tungstenite" }
66+
tungstenite-0-24 = { version = "0.24", optional = true, package = "tungstenite" }
67+
tungstenite-0-25 = { version = "0.25", optional = true, package = "tungstenite" }
68+
tungstenite-0-26 = { version = "0.26", optional = true, package = "tungstenite" }
69+
tungstenite-0-27 = { version = "0.27", optional = true, package = "tungstenite" }
70+
tungstenite-0-28 = { version = "0.28", optional = true, package = "tungstenite" }
71+
5472
[dev-dependencies]
5573
assert_matches = "1.5"
5674
async-graphql = "=7.0.16"
5775
async-graphql-axum = "7"
58-
async-tungstenite = { version = "0.28", features = ["tokio-runtime"] }
76+
async-tungstenite = { version = "0.31", features = ["tokio-runtime"] }
5977
axum = "0.8.4"
6078
axum-macros = "0.5.0"
6179
cynic = { version = "3" }
@@ -67,7 +85,7 @@ graphql-ws-client.path = "."
6785
graphql-ws-client.features = [
6886
"client-cynic",
6987
"client-graphql-client",
70-
"tungstenite",
88+
"tungstenite-0.27",
7189
]
7290

7391
[package.metadata.docs.rs]

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ It supports the websocket libraries
3030
[tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) and
3131
[ws-stream-wasm](https://github.com/najamelan/ws_stream_wasm), and
3232

33+
### Tungstenite Versions
34+
35+
As the tungstenite library is pre-1.0 `graphql-ws-client` provides support for
36+
a range of versions. You can select which version of tungestenite you want
37+
using the `tungstenite-0-xx` feature flags. Note that only one of these can be
38+
active at any time, or `graphql-ws-client` won't compile. Because of these
39+
limitations only one tungstenite version will be tested on the
40+
`grapqhl-ws-client` CI, as a result the other versions may not compile or
41+
work corectly.
42+
3343
## Integrations
3444

3545
The library offers integrations with some popular GraphQL clients with feature flags:

examples/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ publish = false
99

1010
[dependencies]
1111
async-std = { version = "1.9", features = ["attributes"] }
12-
async-tungstenite = { version = "0.28", features = [
12+
async-tungstenite = { version = "0.31", features = [
1313
"async-std-runtime",
1414
"tokio-runtime",
1515
] }
@@ -23,7 +23,7 @@ tokio = { version = "1.15", features = ["rt-multi-thread", "macros"] }
2323
path = "../"
2424
version = "0.11.1"
2525
default-features = false
26-
features = ["cynic", "tungstenite"]
26+
features = ["cynic", "tungstenite-0.27"]
2727

2828
[lints]
2929
workspace = true

src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
mod error;
4545
mod logging;
4646
mod protocol;
47-
#[cfg(any(feature = "ws_stream_wasm", feature = "tungstenite"))]
47+
48+
#[cfg(any(feature = "ws_stream_wasm", feature = "sink_ext"))]
4849
mod sink_ext;
4950

5051
#[doc(hidden)]
@@ -62,8 +63,6 @@ mod client;
6263
/// [1]: https://docs.rs/ws_stream/latest/ws_stream
6364
pub mod ws_stream_wasm;
6465

65-
#[cfg(feature = "tungstenite")]
66-
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite")))]
6766
mod native;
6867

6968
pub use client::*;

src/native.rs

Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,23 @@
1-
use futures_lite::{Stream, StreamExt};
2-
use futures_sink::Sink;
3-
use tungstenite::{self, protocol::CloseFrame};
1+
#[cfg(feature = "tungstenite-0.23")]
2+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.23")))]
3+
mod tungstenite_0_23;
44

5-
use crate::{Error, Message, sink_ext::SinkExt};
5+
#[cfg(feature = "tungstenite-0.24")]
6+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.24")))]
7+
mod tungstenite_0_24;
68

7-
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite")))]
8-
impl<T> crate::client::Connection for T
9-
where
10-
T: Stream<Item = Result<tungstenite::Message, tungstenite::Error>>
11-
+ Sink<tungstenite::Message>
12-
+ Send
13-
+ Sync
14-
+ Unpin,
15-
<T as Sink<tungstenite::Message>>::Error: std::fmt::Display,
16-
{
17-
async fn receive(&mut self) -> Option<Message> {
18-
loop {
19-
match self.next().await? {
20-
Ok(tungstenite::Message::Text(text)) => {
21-
return Some(crate::client::Message::Text(text));
22-
}
23-
Ok(tungstenite::Message::Ping(_)) => return Some(crate::client::Message::Ping),
24-
Ok(tungstenite::Message::Pong(_)) => return Some(crate::client::Message::Pong),
25-
Ok(tungstenite::Message::Close(frame)) => {
26-
return Some(crate::client::Message::Close {
27-
code: frame.as_ref().map(|frame| frame.code.into()),
28-
reason: frame.map(|frame| frame.reason.to_string()),
29-
});
30-
}
31-
Ok(tungstenite::Message::Frame(_) | tungstenite::Message::Binary(_)) => continue,
32-
Err(error) => {
33-
#[allow(unused)]
34-
let error = error;
35-
crate::logging::warning!("error receiving message: {error:?}");
36-
return None;
37-
}
38-
}
39-
}
40-
}
9+
#[cfg(feature = "tungstenite-0.25")]
10+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.25")))]
11+
mod tungstenite_0_25;
4112

42-
async fn send(&mut self, message: crate::client::Message) -> Result<(), Error> {
43-
<Self as SinkExt<tungstenite::Message>>::send(
44-
self,
45-
match message {
46-
crate::client::Message::Text(text) => tungstenite::Message::Text(text),
47-
crate::client::Message::Close { code, reason } => {
48-
tungstenite::Message::Close(code.zip(reason).map(|(code, reason)| CloseFrame {
49-
code: code.into(),
50-
reason: reason.into(),
51-
}))
52-
}
53-
crate::client::Message::Ping => tungstenite::Message::Ping(vec![]),
54-
crate::client::Message::Pong => tungstenite::Message::Pong(vec![]),
55-
},
56-
)
57-
.await
58-
.map_err(|error| Error::Send(error.to_string()))
59-
}
60-
}
13+
#[cfg(feature = "tungstenite-0.26")]
14+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.26")))]
15+
mod tungstenite_0_26;
16+
17+
#[cfg(feature = "tungstenite-0.27")]
18+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.27")))]
19+
mod tungstenite_0_27;
20+
21+
#[cfg(feature = "tungstenite-0.28")]
22+
#[cfg_attr(docsrs, doc(cfg(feature = "tungstenite-0.28")))]
23+
mod tungstenite_0_28;

0 commit comments

Comments
 (0)