Skip to content

Commit d5f6d1e

Browse files
committed
updated readme and placed async feature tag before async-minreq
1 parent e81ebe2 commit d5f6d1e

2 files changed

Lines changed: 119 additions & 92 deletions

File tree

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Bitcoin Esplora API client library. Supports plaintext, TLS and Onion servers. B
1414

1515
## Minimum Supported Rust Version (MSRV)
1616

17-
This library should compile with any combination of features with Rust 1.63.0.
17+
This library should compile with any combination of features with Rust 1.71.0.
1818

1919
To build with the MSRV you will need to pin dependencies as follows:
2020

@@ -36,3 +36,16 @@ cargo update -p lock_api --precise "0.4.12"
3636
cargo update -p socket2@0.6.0 --precise "0.5.10"
3737
cargo update -p webpki-roots@1.0.2 --precise "1.0.1"
3838
```
39+
40+
## Experimental Features using [async-minreq](https://crates.io/crates/async_minreq)
41+
42+
async-minreq features are currently experimental but may become the only async client In the future once it's more mature.
43+
44+
Currently Supported features
45+
46+
```shell
47+
async-minreq
48+
async-minreq-https
49+
async-minreq-https-native
50+
async-minreq-https-rustls
51+
```

src/async.rs

Lines changed: 105 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ pub struct AsyncClient<S = DefaultSleeper> {
5050
}
5151

5252
impl<S: Sleeper> AsyncClient<S> {
53-
#[cfg(feature = "async-minreq")]
54-
/// Build an async client from a builder
55-
pub fn from_builder(builder: Builder) -> Result<Self, Error> {
56-
Ok(AsyncClient {
57-
url: builder.base_url,
58-
max_retries: builder.max_retries,
59-
headers: builder.headers,
60-
marker: PhantomData,
61-
})
62-
}
63-
6453
#[cfg(feature = "async")]
6554
/// Build an async client from a builder
6655
pub fn from_builder(builder: Builder) -> Result<Self, Error> {
@@ -97,13 +86,14 @@ impl<S: Sleeper> AsyncClient<S> {
9786
}
9887

9988
#[cfg(feature = "async-minreq")]
100-
pub fn from_client(url: String, headers: HashMap<String, String>) -> Self {
101-
AsyncClient {
102-
url,
103-
headers,
104-
max_retries: crate::DEFAULT_MAX_RETRIES,
89+
/// Build an async client from a builder
90+
pub fn from_builder(builder: Builder) -> Result<Self, Error> {
91+
Ok(AsyncClient {
92+
url: builder.base_url,
93+
max_retries: builder.max_retries,
94+
headers: builder.headers,
10595
marker: PhantomData,
106-
}
96+
})
10797
}
10898

10999
#[cfg(feature = "async")]
@@ -115,6 +105,16 @@ impl<S: Sleeper> AsyncClient<S> {
115105
marker: PhantomData,
116106
}
117107
}
108+
#[cfg(feature = "async-minreq")]
109+
pub fn from_client(url: String, headers: HashMap<String, String>) -> Self {
110+
AsyncClient {
111+
url,
112+
headers,
113+
max_retries: crate::DEFAULT_MAX_RETRIES,
114+
marker: PhantomData,
115+
}
116+
}
117+
118118
/// Make an HTTP GET request to given URL, deserializing to any `T` that
119119
/// implement [`bitcoin::consensus::Decodable`].
120120
///
@@ -130,6 +130,18 @@ impl<S: Sleeper> AsyncClient<S> {
130130
let url = format!("{}{}", self.url, path);
131131
let response = self.get_with_retry(&url).await?;
132132

133+
#[cfg(feature = "async")]
134+
{
135+
if !response.status().is_success() {
136+
return Err(Error::HttpResponse {
137+
status: response.status().as_u16(),
138+
message: response.text().await?,
139+
});
140+
}
141+
142+
Ok(deserialize::<T>(&response.bytes().await?)?)
143+
}
144+
133145
#[cfg(feature = "async-minreq")]
134146
{
135147
if response.status_code > VALID_HTTP_CODE {
@@ -144,15 +156,6 @@ impl<S: Sleeper> AsyncClient<S> {
144156

145157
return Ok(deserialize::<T>(response.as_bytes())?);
146158
}
147-
#[cfg(feature = "async")]
148-
if !response.status().is_success() {
149-
return Err(Error::HttpResponse {
150-
status: response.status().as_u16(),
151-
message: response.text().await?,
152-
});
153-
}
154-
155-
Ok(deserialize::<T>(&response.bytes().await?)?)
156159
}
157160

158161
/// Make an HTTP GET request to given URL, deserializing to `Option<T>`.
@@ -185,6 +188,17 @@ impl<S: Sleeper> AsyncClient<S> {
185188
let url = format!("{}{}", self.url, path);
186189
let response = self.get_with_retry(&url).await?;
187190

191+
#[cfg(feature = "async")]
192+
{
193+
if !response.status().is_success() {
194+
return Err(Error::HttpResponse {
195+
status: response.status().as_u16(),
196+
message: response.text().await?,
197+
});
198+
}
199+
200+
response.json::<T>().await.map_err(Error::Reqwest)
201+
}
188202
#[cfg(feature = "async-minreq")]
189203
{
190204
if response.status_code > VALID_HTTP_CODE {
@@ -199,16 +213,6 @@ impl<S: Sleeper> AsyncClient<S> {
199213

200214
return response.json().map_err(Error::AsyncMinreq);
201215
}
202-
203-
#[cfg(feature = "async")]
204-
if !response.status().is_success() {
205-
return Err(Error::HttpResponse {
206-
status: response.status().as_u16(),
207-
message: response.text().await?,
208-
});
209-
}
210-
211-
response.json::<T>().await.map_err(Error::Reqwest)
212216
}
213217

214218
/// Make an HTTP GET request to given URL, deserializing to `Option<T>`.
@@ -243,6 +247,19 @@ impl<S: Sleeper> AsyncClient<S> {
243247
let url = format!("{}{}", self.url, path);
244248
let response = self.get_with_retry(&url).await?;
245249

250+
#[cfg(feature = "async")]
251+
{
252+
if !response.status().is_success() {
253+
return Err(Error::HttpResponse {
254+
status: response.status().as_u16(),
255+
message: response.text().await?,
256+
});
257+
}
258+
259+
let hex_str = response.text().await?;
260+
Ok(deserialize(&Vec::from_hex(&hex_str)?)?)
261+
}
262+
246263
#[cfg(feature = "async-minreq")]
247264
{
248265
if response.status_code > VALID_HTTP_CODE {
@@ -262,16 +279,6 @@ impl<S: Sleeper> AsyncClient<S> {
262279

263280
return Ok(deserialize(&Vec::from_hex(&hex_str)?)?);
264281
}
265-
#[cfg(feature = "async")]
266-
if !response.status().is_success() {
267-
return Err(Error::HttpResponse {
268-
status: response.status().as_u16(),
269-
message: response.text().await?,
270-
});
271-
}
272-
273-
let hex_str = response.text().await?;
274-
Ok(deserialize(&Vec::from_hex(&hex_str)?)?)
275282
}
276283

277284
/// Make an HTTP GET request to given URL, deserializing to `Option<T>`.
@@ -300,6 +307,18 @@ impl<S: Sleeper> AsyncClient<S> {
300307
let url = format!("{}{}", self.url, path);
301308
let response = self.get_with_retry(&url).await?;
302309

310+
#[cfg(feature = "async")]
311+
{
312+
if !response.status().is_success() {
313+
return Err(Error::HttpResponse {
314+
status: response.status().as_u16(),
315+
message: response.text().await?,
316+
});
317+
}
318+
319+
Ok(response.text().await?)
320+
}
321+
303322
#[cfg(feature = "async-minreq")]
304323
{
305324
if response.status_code > VALID_HTTP_CODE {
@@ -317,15 +336,6 @@ impl<S: Sleeper> AsyncClient<S> {
317336
Err(_) => return Err(Error::InvalidResponse),
318337
});
319338
}
320-
#[cfg(feature = "async")]
321-
if !response.status().is_success() {
322-
return Err(Error::HttpResponse {
323-
status: response.status().as_u16(),
324-
message: response.text().await?,
325-
});
326-
}
327-
328-
Ok(response.text().await?)
329339
}
330340

331341
/// Make an HTTP GET request to given URL, deserializing to `Option<T>`.
@@ -356,34 +366,36 @@ impl<S: Sleeper> AsyncClient<S> {
356366
let url = format!("{}{}", self.url, path);
357367
let body = serialize::<T>(&body).to_lower_hex_string();
358368

359-
#[cfg(feature = "async-minreq")]
369+
#[cfg(feature = "async")]
360370
{
361-
let mut request = Request::new(Method::Post, &url).with_body(body);
362-
for (key, value) in &self.headers {
363-
request = request.with_header(key, value);
364-
}
371+
let response = self.client.post(url).body(body).send().await?;
365372

366-
let response = request.send().await.map_err(Error::AsyncMinreq)?;
367-
if response.status_code > VALID_HTTP_CODE {
373+
if !response.status().is_success() {
368374
return Err(Error::HttpResponse {
369-
status: response.status_code as u16,
370-
message: match response.as_str() {
371-
Ok(resp) => resp.to_string(),
372-
Err(_) => return Err(Error::InvalidResponse),
373-
},
375+
status: response.status().as_u16(),
376+
message: response.text().await?,
374377
});
375378
}
376-
}
377-
#[cfg(feature = "async")]
378-
let response = self.client.post(url).body(body).send().await?;
379379

380-
if !response.status().is_success() {
381-
return Err(Error::HttpResponse {
382-
status: response.status().as_u16(),
383-
message: response.text().await?,
384-
});
385-
}
380+
#[cfg(feature = "async-minreq")]
381+
{
382+
let mut request = Request::new(Method::Post, &url).with_body(body);
383+
for (key, value) in &self.headers {
384+
request = request.with_header(key, value);
385+
}
386386

387+
let response = request.send().await.map_err(Error::AsyncMinreq)?;
388+
if response.status_code > VALID_HTTP_CODE {
389+
return Err(Error::HttpResponse {
390+
status: response.status_code as u16,
391+
message: match response.as_str() {
392+
Ok(resp) => resp.to_string(),
393+
Err(_) => return Err(Error::InvalidResponse),
394+
},
395+
});
396+
}
397+
}
398+
}
387399
Ok(())
388400
}
389401

@@ -576,6 +588,19 @@ impl<S: Sleeper> AsyncClient<S> {
576588
async fn get_with_retry(&self, url: &str) -> Result<Response, Error> {
577589
let mut delay = BASE_BACKOFF_MILLIS;
578590
let mut attempts = 0;
591+
592+
#[cfg(feature = "async")]
593+
loop {
594+
match self.client.get(url).send().await? {
595+
resp if attempts < self.max_retries && is_status_retryable(resp.status()) => {
596+
S::sleep(delay).await;
597+
attempts += 1;
598+
delay *= 2;
599+
}
600+
resp => return Ok(resp),
601+
}
602+
}
603+
579604
#[cfg(feature = "async-minreq")]
580605
{
581606
loop {
@@ -596,28 +621,17 @@ impl<S: Sleeper> AsyncClient<S> {
596621
}
597622
}
598623
}
599-
#[cfg(feature = "async")]
600-
loop {
601-
match self.client.get(url).send().await? {
602-
resp if attempts < self.max_retries && is_status_retryable(resp.status()) => {
603-
S::sleep(delay).await;
604-
attempts += 1;
605-
delay *= 2;
606-
}
607-
resp => return Ok(resp),
608-
}
609-
}
610624
}
611625
}
612626

613-
#[cfg(feature = "async-minreq")]
614-
fn is_status_retryable(status: i32) -> bool {
615-
RETRYABLE_ERROR_CODES.contains(&(status as u16))
616-
}
617627
#[cfg(feature = "async")]
618628
fn is_status_retryable(status: reqwest::StatusCode) -> bool {
619629
RETRYABLE_ERROR_CODES.contains(&status.as_u16())
620630
}
631+
#[cfg(feature = "async-minreq")]
632+
fn is_status_retryable(status: i32) -> bool {
633+
RETRYABLE_ERROR_CODES.contains(&(status as u16))
634+
}
621635

622636
pub trait Sleeper: 'static {
623637
type Sleep: std::future::Future<Output = ()>;

0 commit comments

Comments
 (0)