Skip to content

Commit 6ae51f8

Browse files
committed
Make sleep into a trait
1 parent 1f1e396 commit 6ae51f8

File tree

3 files changed

+64
-17
lines changed

3 files changed

+64
-17
lines changed

src/async.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! Esplora by way of `reqwest` HTTP client.
1313
1414
use std::collections::HashMap;
15+
use std::marker::PhantomData;
1516
use std::str::FromStr;
1617

1718
use bitcoin::consensus::{deserialize, serialize, Decodable, Encodable};
@@ -26,24 +27,30 @@ use log::{debug, error, info, trace};
2627

2728
use reqwest::{header, Client, Response};
2829

30+
use crate::runtime::{DefaultRuntime, Runtime};
2931
use crate::{
3032
BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus,
3133
BASE_BACKOFF_MILLIS, RETRYABLE_ERROR_CODES,
3234
};
3335

3436
#[derive(Debug, Clone)]
35-
pub struct AsyncClient {
37+
pub struct AsyncClient<R: Runtime = DefaultRuntime> {
3638
/// The URL of the Esplora Server.
3739
url: String,
3840
/// The inner [`reqwest::Client`] to make HTTP requests.
3941
client: Client,
4042
/// Number of times to retry a request
4143
max_retries: usize,
44+
45+
runtime: PhantomData<R>,
4246
}
4347

44-
impl AsyncClient {
48+
impl<R> AsyncClient<R>
49+
where
50+
R: Runtime,
51+
{
4552
/// Build an async client from a builder
46-
pub fn from_builder(builder: Builder) -> Result<Self, Error> {
53+
pub fn from_builder(builder: Builder<R>) -> Result<Self, Error> {
4754
let mut client_builder = Client::builder();
4855

4956
#[cfg(not(target_arch = "wasm32"))]
@@ -72,15 +79,16 @@ impl AsyncClient {
7279
url: builder.base_url,
7380
client: client_builder.build()?,
7481
max_retries: builder.max_retries,
82+
runtime: PhantomData,
7583
})
7684
}
7785

78-
/// Build an async client from the base url and [`Client`]
7986
pub fn from_client(url: String, client: Client) -> Self {
8087
AsyncClient {
8188
url,
8289
client,
8390
max_retries: crate::DEFAULT_MAX_RETRIES,
91+
runtime: PhantomData,
8492
}
8593
}
8694

@@ -433,7 +441,7 @@ impl AsyncClient {
433441
loop {
434442
match self.client.get(url).send().await? {
435443
resp if attempts < self.max_retries && is_status_retryable(resp.status()) => {
436-
crate::runtime::sleep(delay).await;
444+
R::sleep(delay).await;
437445
attempts += 1;
438446
delay *= 2;
439447
}

src/lib.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub use api::*;
8585
pub use blocking::BlockingClient;
8686
#[cfg(feature = "async")]
8787
pub use r#async::AsyncClient;
88+
use runtime::{DefaultRuntime, Runtime};
8889

8990
/// Response status codes for which the request may be retried.
9091
const RETRYABLE_ERROR_CODES: [u16; 3] = [
@@ -113,7 +114,7 @@ pub fn convert_fee_rate(target: usize, estimates: HashMap<u16, f64>) -> Option<f
113114
}
114115

115116
#[derive(Debug, Clone)]
116-
pub struct Builder {
117+
pub struct Builder<R: Runtime = DefaultRuntime> {
117118
/// The URL of the Esplora server.
118119
pub base_url: String,
119120
/// Optional URL of the proxy to use to make requests to the Esplora server
@@ -135,6 +136,8 @@ pub struct Builder {
135136
pub headers: HashMap<String, String>,
136137
/// Max retries
137138
pub max_retries: usize,
139+
/// Async runtime, trait must implement `sleep` function, default is `tokio`
140+
pub runtime: R,
138141
}
139142

140143
impl Builder {
@@ -146,6 +149,31 @@ impl Builder {
146149
timeout: None,
147150
headers: HashMap::new(),
148151
max_retries: DEFAULT_MAX_RETRIES,
152+
runtime: DefaultRuntime,
153+
}
154+
}
155+
156+
/// Build a blocking client from builder
157+
#[cfg(feature = "blocking")]
158+
pub fn build_blocking(self) -> BlockingClient {
159+
BlockingClient::from_builder(self)
160+
}
161+
}
162+
163+
impl<R: Runtime> Builder<R>
164+
where
165+
R: Runtime,
166+
{
167+
/// New with runtime
168+
#[cfg(feature = "async")]
169+
pub fn new_with_runtime(base_url: &str, runtime: R) -> Self {
170+
Builder {
171+
base_url: base_url.to_string(),
172+
proxy: None,
173+
timeout: None,
174+
headers: HashMap::new(),
175+
max_retries: DEFAULT_MAX_RETRIES,
176+
runtime,
149177
}
150178
}
151179

@@ -174,15 +202,9 @@ impl Builder {
174202
self
175203
}
176204

177-
/// Build a blocking client from builder
178-
#[cfg(feature = "blocking")]
179-
pub fn build_blocking(self) -> BlockingClient {
180-
BlockingClient::from_builder(self)
181-
}
182-
183205
// Build an asynchronous client from builder
184206
#[cfg(feature = "async")]
185-
pub fn build_async(self) -> Result<AsyncClient, Error> {
207+
pub fn build_async(self) -> Result<AsyncClient<R>, Error> {
186208
AsyncClient::from_builder(self)
187209
}
188210
}

src/runtime.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
#[cfg(feature = "tokio")]
2-
pub use tokio::time::sleep;
2+
use std::time::Duration;
3+
4+
pub trait Runtime {
5+
fn sleep(duration: Duration) -> impl std::future::Future<Output = ()> + Send;
6+
}
7+
8+
pub struct DefaultRuntime;
9+
10+
#[cfg(feature = "tokio")]
11+
impl Runtime for DefaultRuntime {
12+
async fn sleep(duration: Duration) {
13+
tokio::time::sleep(duration).await;
14+
}
15+
}
316

417
#[cfg(feature = "async-std")]
5-
pub use async_std::task::sleep;
18+
pub struct AsyncStd;
619

7-
#[cfg(not(any(feature = "tokio", feature = "async-std")))]
8-
compile_error!("Either 'tokio' or 'async-std' feature must be enabled");
20+
#[cfg(feature = "async-std")]
21+
impl Runtime for AsyncStd {
22+
async fn sleep(duration: Duration) {
23+
async_std::task::sleep(duration).await;
24+
}
25+
}

0 commit comments

Comments
 (0)