Skip to content

Commit 38817a9

Browse files
committed
Quick and dirty patch to compile client-only transport on wasm32.
1 parent 729308b commit 38817a9

File tree

11 files changed

+113
-46
lines changed

11 files changed

+113
-46
lines changed

tonic/Cargo.toml

+16-5
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@ default = ["transport", "codegen", "prost"]
2727
codegen = ["async-trait"]
2828
transport = [
2929
"h2",
30-
"hyper",
31-
"tokio",
30+
"hyper/full",
31+
"tokio/net",
3232
"tower",
33+
"tower/balance",
3334
"tracing-futures",
3435
"tokio/macros"
3536
]
37+
client = [
38+
"h2",
39+
"hyper/client",
40+
"hyper/http2",
41+
"tokio",
42+
"tower",
43+
]
3644
tls = ["transport", "tokio-rustls"]
3745
tls-roots = ["tls", "rustls-native-certs"]
3846
prost = ["prost1", "prost-derive"]
@@ -65,16 +73,19 @@ async-trait = { version = "0.1.13", optional = true }
6573

6674
# transport
6775
h2 = { version = "0.3", optional = true }
68-
hyper = { version = "0.14.2", features = ["full"], optional = true }
69-
tokio = { version = "1.0.1", features = ["net"], optional = true }
76+
hyper = { version = "0.14.2", default-features = false, optional = true }
77+
tokio = { version = "1.0.1", default-features = false, optional = true }
7078
tokio-stream = "0.1"
71-
tower = { version = "0.4", features = ["balance", "buffer", "discover", "limit", "load", "make", "timeout", "util"], optional = true}
79+
tower = { version = "0.4", features = ["buffer", "discover", "limit", "load", "make", "timeout", "util"], optional = true}
7280
tracing-futures = { version = "0.2", optional = true }
7381

7482
# rustls
7583
tokio-rustls = { version = "0.22", optional = true }
7684
rustls-native-certs = { version = "0.5", optional = true }
7785

86+
[target.'cfg(target_arch = "wasm32")'.dependencies]
87+
wasm-bindgen-futures = "0.4.18"
88+
7889
[dev-dependencies]
7990
tokio = { version = "1.0", features = ["rt", "macros"] }
8091
static_assertions = "1.0"

tonic/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub mod codec;
8282
pub mod metadata;
8383
pub mod server;
8484

85-
#[cfg(feature = "transport")]
85+
#[cfg(any(feature = "transport", feature = "client"))]
8686
#[cfg_attr(docsrs, doc(cfg(feature = "transport")))]
8787
pub mod transport;
8888

tonic/src/request.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::metadata::MetadataMap;
2-
#[cfg(feature = "transport")]
2+
#[cfg(any(feature = "transport", feature = "client"))]
33
use crate::transport::Certificate;
44
use futures_core::Stream;
55
use http::Extensions;
66
use std::net::SocketAddr;
7-
#[cfg(feature = "transport")]
7+
#[cfg(any(feature = "transport", feature = "client"))]
88
use std::sync::Arc;
99

1010
/// A gRPC request and metadata from an RPC call.
@@ -18,7 +18,7 @@ pub struct Request<T> {
1818
#[derive(Clone)]
1919
pub(crate) struct ConnectionInfo {
2020
pub(crate) remote_addr: Option<SocketAddr>,
21-
#[cfg(feature = "transport")]
21+
#[cfg(any(feature = "transport", feature = "client"))]
2222
pub(crate) peer_certs: Option<Arc<Vec<Certificate>>>,
2323
}
2424

tonic/src/transport/channel/endpoint.rs

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl Endpoint {
4343
// FIXME: determine if we want to expose this or not. This is really
4444
// just used in codegen for a shortcut.
4545
#[doc(hidden)]
46+
#[cfg(feature = "transport")]
4647
pub fn new<D>(dst: D) -> Result<Self, Error>
4748
where
4849
D: TryInto<Self>,
@@ -231,6 +232,7 @@ impl Endpoint {
231232
}
232233

233234
/// Create a channel from this config.
235+
#[cfg(feature = "transport")]
234236
pub async fn connect(&self) -> Result<Channel, Error> {
235237
let mut http = hyper::client::connect::HttpConnector::new();
236238
http.enforce_http(false);
@@ -250,6 +252,7 @@ impl Endpoint {
250252
///
251253
/// The channel returned by this method does not attempt to connect to the endpoint until first
252254
/// use.
255+
#[cfg(feature = "transport")]
253256
pub fn connect_lazy(&self) -> Result<Channel, Error> {
254257
let mut http = hyper::client::connect::HttpConnector::new();
255258
http.enforce_http(false);

tonic/src/transport/channel/mod.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,35 @@ pub use endpoint::Endpoint;
99
#[cfg(feature = "tls")]
1010
pub use tls::ClientTlsConfig;
1111

12-
use super::service::{Connection, DynamicServiceStream};
12+
use super::service::Connection;
13+
#[cfg(feature = "transport")]
14+
use super::service::DynamicServiceStream;
1315
use crate::body::BoxBody;
1416
use bytes::Bytes;
1517
use http::{
1618
uri::{InvalidUri, Uri},
1719
Request, Response,
1820
};
1921
use hyper::client::connect::Connection as HyperConnection;
22+
#[cfg(feature = "transport")]
23+
use std::hash::Hash;
2024
use std::{
2125
fmt,
2226
future::Future,
23-
hash::Hash,
2427
pin::Pin,
2528
task::{Context, Poll},
2629
};
27-
use tokio::{
28-
io::{AsyncRead, AsyncWrite},
29-
sync::mpsc::{channel, Sender},
30-
};
3130

31+
use tokio::io::{AsyncRead, AsyncWrite};
32+
#[cfg(feature = "transport")]
33+
use tokio::sync::mpsc::{channel, Sender};
34+
35+
#[cfg(feature = "transport")]
3236
use tower::balance::p2c::Balance;
37+
#[cfg(feature = "transport")]
38+
use tower::discover::{Change, Discover};
3339
use tower::{
3440
buffer::{self, Buffer},
35-
discover::{Change, Discover},
3641
util::{BoxService, Either},
3742
Service,
3843
};
@@ -108,6 +113,7 @@ impl Channel {
108113
///
109114
/// This creates a [`Channel`] that will load balance accross all the
110115
/// provided endpoints.
116+
#[cfg(feature = "transport")]
111117
pub fn balance_list(list: impl Iterator<Item = Endpoint>) -> Self {
112118
let (channel, tx) = Self::balance_channel(DEFAULT_BUFFER_SIZE);
113119
list.for_each(|endpoint| {
@@ -121,6 +127,7 @@ impl Channel {
121127
/// Balance a list of [`Endpoint`]'s.
122128
///
123129
/// This creates a [`Channel`] that will listen to a stream of change events and will add or remove provided endpoints.
130+
#[cfg(feature = "transport")]
124131
pub fn balance_channel<K>(capacity: usize) -> (Self, Sender<Change<K, Endpoint>>)
125132
where
126133
K: Hash + Eq + Send + Clone + 'static,
@@ -130,6 +137,7 @@ impl Channel {
130137
(Self::balance(list, DEFAULT_BUFFER_SIZE), tx)
131138
}
132139

140+
#[cfg(feature = "transport")]
133141
pub(crate) fn new<C>(connector: C, endpoint: Endpoint) -> Self
134142
where
135143
C: Service<Uri> + Send + 'static,
@@ -162,6 +170,7 @@ impl Channel {
162170
Ok(Channel { svc })
163171
}
164172

173+
#[cfg(feature = "transport")]
165174
pub(crate) fn balance<D>(discover: D, buffer_size: usize) -> Self
166175
where
167176
D: Discover<Service = Connection> + Unpin + Send + 'static,

tonic/src/transport/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,34 @@
8787
//! [rustls]: https://docs.rs/rustls/0.16.0/rustls/
8888
8989
pub mod channel;
90+
#[cfg(feature = "transport")]
9091
pub mod server;
9192

93+
/// Trait that connected IO resources implement.
94+
///
95+
/// The goal for this trait is to allow users to implement
96+
/// custom IO types that can still provide the same connection
97+
/// metadata.
98+
pub trait Connected {
99+
/// Return the remote address this IO resource is connected too.
100+
fn remote_addr(&self) -> Option<std::net::SocketAddr> {
101+
None
102+
}
103+
104+
/// Return the set of connected peer TLS certificates.
105+
fn peer_certs(&self) -> Option<Vec<Certificate>> {
106+
None
107+
}
108+
}
109+
92110
mod error;
93111
mod service;
94112
mod tls;
95113

96114
#[doc(inline)]
97115
pub use self::channel::{Channel, Endpoint};
98116
pub use self::error::Error;
117+
#[cfg(feature = "transport")]
99118
#[doc(inline)]
100119
pub use self::server::{NamedService, Server};
101120
pub use self::tls::{Certificate, Identity};
@@ -105,6 +124,7 @@ pub use hyper::{Body, Uri};
105124
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
106125
pub use self::channel::ClientTlsConfig;
107126
#[cfg(feature = "tls")]
127+
#[cfg(feature = "transport")]
108128
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
109129
pub use self::server::ServerTlsConfig;
110130

tonic/src/transport/server/conn.rs

+2-17
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,12 @@
1+
#[cfg(feature = "tls")]
12
use crate::transport::Certificate;
3+
use crate::transport::Connected;
24
use hyper::server::conn::AddrStream;
35
use std::net::SocketAddr;
46
use tokio::net::TcpStream;
57
#[cfg(feature = "tls")]
68
use tokio_rustls::{rustls::Session, server::TlsStream};
79

8-
/// Trait that connected IO resources implement.
9-
///
10-
/// The goal for this trait is to allow users to implement
11-
/// custom IO types that can still provide the same connection
12-
/// metadata.
13-
pub trait Connected {
14-
/// Return the remote address this IO resource is connected too.
15-
fn remote_addr(&self) -> Option<SocketAddr> {
16-
None
17-
}
18-
19-
/// Return the set of connected peer TLS certificates.
20-
fn peer_certs(&self) -> Option<Vec<Certificate>> {
21-
None
22-
}
23-
}
24-
2510
impl Connected for AddrStream {
2611
fn remote_addr(&self) -> Option<SocketAddr> {
2712
Some(self.remote_addr())

tonic/src/transport/server/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod incoming;
66
#[cfg_attr(docsrs, doc(cfg(feature = "tls")))]
77
mod tls;
88

9-
pub use conn::Connected;
9+
pub use super::Connected;
1010
#[cfg(feature = "tls")]
1111
pub use tls::ServerTlsConfig;
1212

tonic/src/transport/service/connection.rs

+36-11
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ pub(crate) struct Connection {
2727
inner: BoxService<Request, Response, crate::Error>,
2828
}
2929

30+
#[cfg(target_arch = "wasm32")]
31+
mod wasm {
32+
use std::future::Future;
33+
use std::pin::Pin;
34+
35+
type BoxSendFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
36+
37+
pub(crate) struct Executor;
38+
39+
impl hyper::rt::Executor<BoxSendFuture> for Executor {
40+
fn execute(&self, fut: BoxSendFuture) {
41+
wasm_bindgen_futures::spawn_local(fut)
42+
}
43+
}
44+
}
45+
3046
impl Connection {
3147
fn new<C>(connector: C, endpoint: Endpoint, is_lazy: bool) -> Self
3248
where
@@ -35,21 +51,29 @@ impl Connection {
3551
C::Future: Unpin + Send,
3652
C::Response: AsyncRead + AsyncWrite + HyperConnection + Unpin + Send + 'static,
3753
{
38-
let mut settings = Builder::new()
39-
.http2_initial_stream_window_size(endpoint.init_stream_window_size)
40-
.http2_initial_connection_window_size(endpoint.init_connection_window_size)
41-
.http2_only(true)
42-
.http2_keep_alive_interval(endpoint.http2_keep_alive_interval)
43-
.clone();
54+
let mut settings = Builder::new();
4455

45-
if let Some(val) = endpoint.http2_keep_alive_timeout {
46-
settings.http2_keep_alive_timeout(val);
56+
#[cfg(target_arch = "wasm32")]
57+
{
58+
settings.executor(wasm::Executor);
4759
}
48-
49-
if let Some(val) = endpoint.http2_keep_alive_while_idle {
50-
settings.http2_keep_alive_while_idle(val);
60+
#[cfg(feature = "transport")]
61+
{
62+
settings.http2_keep_alive_interval(endpoint.http2_keep_alive_interval);
63+
if let Some(val) = endpoint.http2_keep_alive_timeout {
64+
settings.http2_keep_alive_timeout(val);
65+
}
66+
67+
if let Some(val) = endpoint.http2_keep_alive_while_idle {
68+
settings.http2_keep_alive_while_idle(val);
69+
}
5170
}
5271

72+
settings
73+
.http2_initial_stream_window_size(endpoint.init_stream_window_size)
74+
.http2_initial_connection_window_size(endpoint.init_connection_window_size)
75+
.http2_only(true);
76+
5377
let stack = ServiceBuilder::new()
5478
.layer_fn(|s| AddOrigin::new(s, endpoint.uri.clone()))
5579
.layer_fn(|s| UserAgent::new(s, endpoint.user_agent.clone()))
@@ -78,6 +102,7 @@ impl Connection {
78102
Self::new(connector, endpoint, false).ready_oneshot().await
79103
}
80104

105+
#[cfg(feature = "transport")]
81106
pub(crate) fn lazy<C>(connector: C, endpoint: Endpoint) -> Self
82107
where
83108
C: Service<Uri> + Send + 'static,

tonic/src/transport/service/io.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use crate::transport::{server::Connected, Certificate};
1+
#[cfg(feature = "transport")]
2+
use crate::transport::Certificate;
3+
use crate::transport::Connected;
24
use hyper::client::connect::{Connected as HyperConnected, Connection};
35
use std::io;
6+
#[cfg(feature = "transport")]
47
use std::net::SocketAddr;
58
use std::pin::Pin;
69
use std::task::{Context, Poll};
@@ -61,14 +64,17 @@ pub(in crate::transport) trait ConnectedIo: Io + Connected {}
6164

6265
impl<T> ConnectedIo for T where T: Io + Connected {}
6366

67+
#[cfg(feature = "transport")]
6468
pub(crate) struct ServerIo(Pin<Box<dyn ConnectedIo>>);
6569

70+
#[cfg(feature = "transport")]
6671
impl ServerIo {
6772
pub(in crate::transport) fn new<I: ConnectedIo>(io: I) -> Self {
6873
ServerIo(Box::pin(io))
6974
}
7075
}
7176

77+
#[cfg(feature = "transport")]
7278
impl Connected for ServerIo {
7379
fn remote_addr(&self) -> Option<SocketAddr> {
7480
(&*self.0).remote_addr()
@@ -79,6 +85,7 @@ impl Connected for ServerIo {
7985
}
8086
}
8187

88+
#[cfg(feature = "transport")]
8289
impl AsyncRead for ServerIo {
8390
fn poll_read(
8491
mut self: Pin<&mut Self>,
@@ -89,6 +96,7 @@ impl AsyncRead for ServerIo {
8996
}
9097
}
9198

99+
#[cfg(feature = "transport")]
92100
impl AsyncWrite for ServerIo {
93101
fn poll_write(
94102
mut self: Pin<&mut Self>,

0 commit comments

Comments
 (0)