Skip to content

Commit 5b39f52

Browse files
committed
feat: add support for WebTransport
Signed-off-by: Roman Volosatovs <[email protected]>
1 parent 51b4b3a commit 5b39f52

File tree

9 files changed

+574
-35
lines changed

9 files changed

+574
-35
lines changed

Cargo.lock

+63-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ repository = "https://github.com/bytecodealliance/wrpc"
2222
members = ["benches/reactor", "crates/*", "examples/rust/*"]
2323

2424
[features]
25-
default = ["bin", "nats", "net", "quic", "wasmtime"]
25+
default = ["bin", "nats", "net", "quic", "wasmtime", "web-transport"]
2626

2727
bin = ["bin-bindgen", "bin-wasmtime"]
2828
bin-bindgen = [
@@ -36,6 +36,7 @@ bin-wasmtime = ["dep:tokio", "dep:wrpc-wasmtime-cli", "tokio/rt-multi-thread"]
3636
nats = ["dep:async-nats", "dep:wrpc-transport-nats", "wrpc-cli/nats"]
3737
net = ["wrpc-transport/net"]
3838
quic = ["dep:wrpc-transport-quic"]
39+
web-transport = ["dep:wrpc-transport-web"]
3940
wasmtime = ["dep:wrpc-runtime-wasmtime"]
4041

4142
[[bin]]
@@ -78,6 +79,7 @@ wrpc-transport-nats = { workspace = true, features = [
7879
"async-nats-0_37",
7980
], optional = true }
8081
wrpc-transport-quic = { workspace = true, optional = true }
82+
wrpc-transport-web = { workspace = true, optional = true }
8183
wrpc-wasmtime-cli = { workspace = true, optional = true }
8284

8385
[dev-dependencies]
@@ -108,7 +110,7 @@ wasmtime-cli-flags = { workspace = true, features = [
108110
"pooling-allocator",
109111
"threads",
110112
] }
111-
wrpc-test = { workspace = true, features = ["nats", "quic"] }
113+
wrpc-test = { workspace = true, features = ["nats", "quic", "web-transport"] }
112114
wrpc-transport = { workspace = true, features = ["net"] }
113115

114116
[workspace.dependencies]
@@ -151,6 +153,7 @@ wasmparser = { version = "0.219", default-features = false }
151153
wasmtime = { version = "25", default-features = false }
152154
wasmtime-cli-flags = { version = "25", default-features = false }
153155
wasmtime-wasi = { version = "25", default-features = false }
156+
web-transport-quinn = { version = "0.3.4", default-features = false }
154157
wit-bindgen = { version = "0.34", default-features = false }
155158
wit-bindgen-core = { version = "0.34", default-features = false }
156159
wit-bindgen-wrpc = { version = "0.8", default-features = false, path = "./crates/wit-bindgen" }
@@ -166,6 +169,7 @@ wrpc-test = { path = "./crates/test", default-features = false }
166169
wrpc-transport = { version = "0.28.2", path = "./crates/transport", default-features = false }
167170
wrpc-transport-nats = { version = "0.27.1", path = "./crates/transport-nats", default-features = false }
168171
wrpc-transport-quic = { version = "0.4", path = "./crates/transport-quic", default-features = false }
172+
wrpc-transport-web = { version = "0.1", path = "./crates/transport-web", default-features = false }
169173
wrpc-wasi-keyvalue = { version = "0.1", path = "./crates/wasi-keyvalue", default-features = false }
170174
wrpc-wasi-keyvalue-mem = { version = "0.1", path = "./crates/wasi-keyvalue-mem", default-features = false }
171175
wrpc-wasmtime-cli = { version = "0.2", path = "./crates/wasmtime-cli", default-features = false }

crates/test/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license.workspace = true
1111
repository.workspace = true
1212

1313
[features]
14-
default = ["nats", "quic"]
14+
default = ["nats", "quic", "web-transport"]
1515
nats = ["dep:async-nats", "async-nats/ring", "wrpc-cli/nats"]
1616
quic = [
1717
"dep:quinn",
@@ -28,6 +28,7 @@ quic = [
2828
"rustls/logging",
2929
"rustls/ring",
3030
]
31+
web-transport = ["dep:web-transport-quinn", "dep:url", "quic"]
3132

3233
[dependencies]
3334
anyhow = { workspace = true }
@@ -37,5 +38,7 @@ rcgen = { workspace = true, optional = true }
3738
rustls = { workspace = true, optional = true }
3839
tokio = { workspace = true, features = ["net", "process", "rt-multi-thread"] }
3940
tracing = { workspace = true }
41+
url = { workspace = true, optional = true }
42+
web-transport-quinn = { workspace = true, optional = true }
4043
wrpc-cli = { workspace = true }
4144
wrpc-transport = { workspace = true }

crates/test/src/lib.rs

+72-28
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ where
7878
}
7979

8080
#[cfg(feature = "quic")]
81-
pub async fn with_quic<T, Fut>(
82-
f: impl FnOnce(quinn::Connection, quinn::Connection) -> Fut,
81+
pub async fn with_quic_endpoints<T, Fut>(
82+
f: impl FnOnce(std::net::SocketAddr, quinn::Endpoint, quinn::Endpoint) -> Fut,
8383
) -> anyhow::Result<T>
8484
where
8585
Fut: core::future::Future<Output = anyhow::Result<T>>,
@@ -91,12 +91,20 @@ where
9191
use rcgen::{generate_simple_self_signed, CertifiedKey};
9292
use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer};
9393
use rustls::version::TLS13;
94-
use tokio::try_join;
94+
95+
let mut clt_ep = quinn::Endpoint::client((Ipv6Addr::LOCALHOST, 0).into())
96+
.context("failed to create client endpoint")?;
97+
98+
let srv_sock = std::net::UdpSocket::bind((Ipv6Addr::LOCALHOST, 0))
99+
.context("failed to open a UDP socket")?;
100+
let srv_addr = srv_sock
101+
.local_addr()
102+
.context("failed to query server address")?;
95103

96104
let CertifiedKey {
97105
cert: srv_crt,
98106
key_pair: srv_key,
99-
} = generate_simple_self_signed(["server.wrpc".to_string()])
107+
} = generate_simple_self_signed(["localhost".to_string()])
100108
.context("failed to generate server certificate")?;
101109
let CertifiedKey {
102110
cert: clt_crt,
@@ -123,15 +131,7 @@ where
123131
)
124132
.expect("failed to create server config");
125133

126-
let mut clt_ep = quinn::Endpoint::client((Ipv6Addr::LOCALHOST, 0).into())
127-
.context("failed to create client endpoint")?;
128134
clt_ep.set_default_client_config(ClientConfig::new(Arc::new(clt_cnf)));
129-
130-
let srv_sock = std::net::UdpSocket::bind((Ipv6Addr::LOCALHOST, 0))
131-
.context("failed to open a UDP socket")?;
132-
let srv_addr = srv_sock
133-
.local_addr()
134-
.context("failed to query server address")?;
135135
let srv_ep = quinn::Endpoint::new(
136136
EndpointConfig::default(),
137137
Some(srv_cnf),
@@ -140,20 +140,64 @@ where
140140
)
141141
.context("failed to create server endpoint")?;
142142

143-
let (clt, srv) = try_join!(
144-
async move {
145-
let conn = clt_ep
146-
.connect(srv_addr, "server.wrpc")
147-
.context("failed to connect to server")?;
148-
conn.await.context("failed to establish client connection")
149-
},
150-
async move {
151-
let conn = srv_ep
152-
.accept()
153-
.await
154-
.context("failed to accept connection")?;
155-
conn.await.context("failed to establish server connection")
156-
}
157-
)?;
158-
f(clt, srv).await.context("closure failed")
143+
f(srv_addr, clt_ep, srv_ep).await.context("closure failed")
144+
}
145+
146+
#[cfg(feature = "quic")]
147+
pub async fn with_quic<T, Fut>(
148+
f: impl FnOnce(quinn::Connection, quinn::Connection) -> Fut,
149+
) -> anyhow::Result<T>
150+
where
151+
Fut: core::future::Future<Output = anyhow::Result<T>>,
152+
{
153+
with_quic_endpoints(|addr, clt, srv| async move {
154+
let (clt, srv) = tokio::try_join!(
155+
async move {
156+
let conn = clt
157+
.connect(addr, "localhost")
158+
.context("failed to connect to server")?;
159+
conn.await.context("failed to establish client connection")
160+
},
161+
async move {
162+
let conn = srv.accept().await.context("failed to accept connection")?;
163+
conn.await.context("failed to establish server connection")
164+
}
165+
)?;
166+
f(clt, srv).await.context("closure failed")
167+
})
168+
.await
169+
}
170+
171+
#[cfg(feature = "web-transport")]
172+
pub async fn with_web_transport<T, Fut>(
173+
f: impl FnOnce(web_transport_quinn::Session, web_transport_quinn::Session) -> Fut,
174+
) -> anyhow::Result<T>
175+
where
176+
Fut: core::future::Future<Output = anyhow::Result<T>>,
177+
{
178+
with_quic_endpoints(|addr, clt, srv| async move {
179+
let url = url::Url::parse(&format!("https://localhost:{}", addr.port()))
180+
.context("failed to construct URL")?;
181+
let (clt, srv) = tokio::try_join!(
182+
async move {
183+
web_transport_quinn::connect(&clt, &url)
184+
.await
185+
.context("failed to connect to server")
186+
},
187+
async move {
188+
let conn = srv.accept().await.context("failed to accept connection")?;
189+
let conn = conn
190+
.await
191+
.context("failed to establish server connection")?;
192+
let req = web_transport_quinn::accept(conn)
193+
.await
194+
.context("failed to accept connection")?;
195+
req.ok()
196+
.await
197+
.context("failed to establish server connection")
198+
}
199+
)?;
200+
f(clt, srv).await.context("closure failed")
201+
})
202+
.await
159203
}

crates/transport-web/Cargo.toml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "wrpc-transport-web"
3+
version = "0.1.0"
4+
description = "wRPC WebTransport transport"
5+
6+
authors.workspace = true
7+
categories.workspace = true
8+
edition.workspace = true
9+
license.workspace = true
10+
repository.workspace = true
11+
12+
[dependencies]
13+
anyhow = { workspace = true, features = ["std"] }
14+
bytes = { workspace = true }
15+
tracing = { workspace = true }
16+
web-transport-quinn = { workspace = true }
17+
wrpc-transport = { workspace = true }
18+
19+
[dev-dependencies]
20+
futures = { workspace = true }
21+
test-log = { workspace = true, features = ["color", "log", "trace"] }
22+
tokio = { workspace = true, features = ["rt-multi-thread"] }
23+
wrpc-test = { workspace = true, features = ["web-transport"] }

0 commit comments

Comments
 (0)