Skip to content
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

feat: allow using http-client feature in wasm32-unknown-unknown target #1485

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/unreleased/features/1485-wasm-http-client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [tendermint-rpc] allow usage of `http-client` trait in `wasm32-unknown-unknown` target. ([\#1485](https://github.com/informalsystems/tendermint-rs/pull/1485))
10 changes: 9 additions & 1 deletion rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ cli = [
http-client = [
"futures",
"reqwest",
"tokio/sync",
"tokio/macros",
"tokio/time",
"wasmtimer/tokio",
"tracing"
]
websocket-client = [
Expand All @@ -70,6 +73,7 @@ tendermint-proto = { version = "0.40.1", path = "../proto", default-features = f

async-trait = { version = "0.1", default-features = false }
bytes = { version = "1.0", default-features = false }
cfg-if = "1.0.0"
getrandom = { version = "0.2", default-features = false, features = ["js"] }
peg = { version = "0.8", default-features = false }
pin-project = { version = "1.0.1", default-features = false }
Expand All @@ -92,10 +96,14 @@ async-tungstenite = { version = "0.24", default-features = false, features = ["t
futures = { version = "0.3", optional = true, default-features = false }
reqwest = { version = "0.11.20", optional = true, default-features = false, features = ["rustls-tls-native-roots"] }
structopt = { version = "0.3", optional = true, default-features = false }
tokio = { version = "1.0", optional = true, default-features = false, features = ["rt-multi-thread"] }
tokio = { version = "1.0", optional = true, default-features = false }
tracing = { version = "0.1", optional = true, default-features = false }
tracing-subscriber = { version = "0.3", optional = true, default-features = false, features = ["fmt"] }

[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
version = "0.4.1"
optional = true

[dev-dependencies]
tendermint = { version = "0.40.1", default-features = false, path = "../tendermint", features = ["secp256k1"] }
http = { version = "1", default-features = false, features = ["std"] }
Expand Down
8 changes: 7 additions & 1 deletion rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ pub trait Client {

/// `/genesis_chunked`: get genesis file in multiple chunks.
#[cfg(any(feature = "http-client", feature = "websocket-client"))]
#[cfg_attr(target_arch = "wasm32", allow(elided_named_lifetimes))]
async fn genesis_chunked_stream(
&self,
) -> core::pin::Pin<Box<dyn futures::Stream<Item = Result<Vec<u8>, Error>> + '_>> {
Expand Down Expand Up @@ -366,7 +367,12 @@ pub trait Client {
}

attempts_remaining -= 1;
tokio::time::sleep(poll_interval).await;

cfg_if::cfg_if! { if #[cfg(target_arch = "wasm32")] {
wasmtimer::tokio::sleep(poll_interval).await;
} else {
tokio::time::sleep(poll_interval).await;
}}
}

Ok(())
Expand Down
48 changes: 29 additions & 19 deletions rpc/src/client/transport/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use core::str::FromStr;
use core::time::Duration;

use async_trait::async_trait;
use reqwest::{header, Proxy};
use cfg_if::cfg_if;
use reqwest::header;

use tendermint::{block::Height, evidence::Evidence, Hash};
use tendermint_config::net;
Expand All @@ -20,6 +21,7 @@ use crate::{Error, Order, Scheme, SimpleRequest, Url};

use super::auth;

#[cfg(not(target_arch = "wasm32"))]
const USER_AGENT: &str = concat!("tendermint.rs/", env!("CARGO_PKG_VERSION"));

/// A JSON-RPC/HTTP Tendermint RPC client (implements [`crate::Client`]).
Expand Down Expand Up @@ -115,23 +117,30 @@ impl Builder {
let inner = if let Some(inner) = self.client {
inner
} else {
let builder = reqwest::ClientBuilder::new()
.user_agent(self.user_agent.unwrap_or_else(|| USER_AGENT.to_string()))
.timeout(self.timeout);

match self.proxy_url {
None => builder.build().map_err(Error::http)?,
Some(proxy_url) => {
let proxy = if self.url.0.is_secure() {
Proxy::https(reqwest::Url::from(proxy_url.0))
.map_err(Error::invalid_proxy)?
} else {
Proxy::http(reqwest::Url::from(proxy_url.0))
.map_err(Error::invalid_proxy)?
};
builder.proxy(proxy).build().map_err(Error::http)?
},
}
cfg_if! {if #[cfg(target_arch = "wasm32")] {
// .user_agent method will become available in reqwest 0.12
reqwest::ClientBuilder::new()
// .user_agent(self.user_agent.unwrap_or_else(|| USER_AGENT.to_string()))
.build().map_err(Error::http)?
} else {
let builder = reqwest::ClientBuilder::new()
.user_agent(self.user_agent.unwrap_or_else(|| USER_AGENT.to_string()))
.timeout(self.timeout);

match self.proxy_url {
None => builder.build().map_err(Error::http)?,
Some(proxy_url) => {
let proxy = if self.url.0.is_secure() {
reqwest::Proxy::https(reqwest::Url::from(proxy_url.0))
.map_err(Error::invalid_proxy)?
} else {
reqwest::Proxy::http(reqwest::Url::from(proxy_url.0))
.map_err(Error::invalid_proxy)?
};
builder.proxy(proxy).build().map_err(Error::http)?
},
}
}}
};

Ok(HttpClient {
Expand Down Expand Up @@ -248,7 +257,8 @@ impl HttpClient {
}
}

#[async_trait]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl Client for HttpClient {
async fn perform<R>(&self, request: R) -> Result<R::Output, Error>
where
Expand Down
2 changes: 2 additions & 0 deletions rpc/src/client/transport/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl SubscriptionRouter {

/// Immediately add a new subscription to the router without waiting for
/// confirmation.
#[cfg_attr(not(feature = "websocket-client"), allow(dead_code))]
pub fn add(&mut self, id: impl ToString, query: impl ToString, tx: SubscriptionTx) {
let query = query.to_string();
let subs_for_query = match self.subscriptions.get_mut(&query) {
Expand All @@ -105,6 +106,7 @@ impl SubscriptionRouter {
}

/// Removes all the subscriptions relating to the given query.
#[cfg_attr(not(feature = "websocket-client"), allow(dead_code))]
pub fn remove_by_query(&mut self, query: impl ToString) -> usize {
self.subscriptions
.remove(&query.to_string())
Expand Down
4 changes: 2 additions & 2 deletions rpc/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ type HttpStatusCode = reqwest::StatusCode;
#[cfg(not(feature = "reqwest"))]
type HttpStatusCode = core::num::NonZeroU16;

#[cfg(feature = "tokio")]
#[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
type JoinError = flex_error::DisplayOnly<tokio::task::JoinError>;

#[cfg(not(feature = "tokio"))]
#[cfg(any(not(feature = "tokio"), target_arch = "wasm32"))]
type JoinError = flex_error::NoSource;

#[cfg(feature = "async-tungstenite")]
Expand Down
Loading