Skip to content

Commit 6f427ea

Browse files
committed
final cleanup
1 parent 0c024f0 commit 6f427ea

File tree

3 files changed

+31
-106
lines changed

3 files changed

+31
-106
lines changed

lightning-block-sync/src/http.rs

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ use bitreq::RequestExt;
88

99
use std::convert::TryFrom;
1010
use std::fmt;
11-
use std::time::Duration;
1211

13-
/// Timeout for requests. This is set to a high value as it is not uncommon for Bitcoin Core to be
14-
/// blocked waiting on UTXO cache flushes for upwards of 10 minutes on slow devices (e.g. RPis with
15-
/// SSDs over USB).
16-
const TCP_STREAM_RESPONSE_TIMEOUT: Duration = Duration::from_secs(300);
12+
/// Timeout for requests in seconds. This is set to a high value as it is not uncommon for Bitcoin
13+
/// Core to be blocked waiting on UTXO cache flushes for upwards of 10 minutes on slow devices
14+
/// (e.g. RPis with SSDs over USB).
15+
const TCP_STREAM_RESPONSE_TIMEOUT: u64 = 300;
1716

1817
/// Maximum HTTP message body size in bytes. Enough for a hex-encoded block in JSON format and any
1918
/// overhead for HTTP chunked transfer encoding.
@@ -68,79 +67,25 @@ impl From<HttpError> for HttpClientError {
6867
}
6968
}
7069

71-
/// Endpoint for interacting with an HTTP-based API.
72-
#[derive(Debug)]
73-
pub struct HttpEndpoint {
74-
host: String,
75-
port: Option<u16>,
76-
path: String,
77-
}
78-
79-
impl HttpEndpoint {
80-
/// Creates an endpoint for the given host and default HTTP port.
81-
pub fn for_host(host: String) -> Self {
82-
Self { host, port: None, path: String::from("/") }
83-
}
84-
85-
/// Specifies a port to use with the endpoint.
86-
pub fn with_port(mut self, port: u16) -> Self {
87-
self.port = Some(port);
88-
self
89-
}
90-
91-
/// Specifies a path to use with the endpoint.
92-
pub fn with_path(mut self, path: String) -> Self {
93-
self.path = path;
94-
self
95-
}
96-
97-
/// Returns the endpoint host.
98-
pub fn host(&self) -> &str {
99-
&self.host
100-
}
101-
102-
/// Returns the endpoint port.
103-
pub fn port(&self) -> u16 {
104-
match self.port {
105-
None => 80,
106-
Some(port) => port,
107-
}
108-
}
109-
110-
/// Returns the endpoint path.
111-
pub fn path(&self) -> &str {
112-
&self.path
113-
}
114-
}
115-
116-
impl<'a> std::net::ToSocketAddrs for &'a HttpEndpoint {
117-
type Iter = <(&'a str, u16) as std::net::ToSocketAddrs>::Iter;
118-
119-
fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
120-
(self.host(), self.port()).to_socket_addrs()
121-
}
122-
}
123-
12470
/// Maximum number of cached connections in the connection pool.
12571
#[cfg(feature = "tokio")]
12672
const MAX_CONNECTIONS: usize = 10;
12773

12874
/// Client for making HTTP requests.
12975
pub(crate) struct HttpClient {
130-
host: String,
131-
port: u16,
76+
base_url: String,
13277
#[cfg(feature = "tokio")]
13378
client: bitreq::Client,
13479
}
13580

13681
impl HttpClient {
137-
/// Creates a new HTTP client for the given endpoint.
82+
/// Creates a new HTTP client for the given base URL.
13883
///
84+
/// The base URL should include the scheme, host, and port (e.g., "http://127.0.0.1:8332").
13985
/// DNS resolution is deferred until the first request is made.
140-
pub fn new(endpoint: &HttpEndpoint) -> Self {
86+
pub fn new(base_url: &str) -> Self {
14187
Self {
142-
host: endpoint.host().to_string(),
143-
port: endpoint.port(),
88+
base_url: base_url.to_string(),
14489
#[cfg(feature = "tokio")]
14590
client: bitreq::Client::new(MAX_CONNECTIONS),
14691
}
@@ -154,9 +99,9 @@ impl HttpClient {
15499
where
155100
F: TryFrom<Vec<u8>, Error = std::io::Error>,
156101
{
157-
let url = format!("http://{}:{}{}", self.host, self.port, uri);
102+
let url = format!("{}{}", self.base_url, uri);
158103
let request = bitreq::get(url)
159-
.with_timeout(TCP_STREAM_RESPONSE_TIMEOUT.as_secs())
104+
.with_timeout(TCP_STREAM_RESPONSE_TIMEOUT)
160105
.with_max_body_size(Some(MAX_HTTP_MESSAGE_BODY_SIZE));
161106
let response_body = self.send_request(request).await?;
162107
F::try_from(response_body).map_err(HttpClientError::Io)
@@ -174,11 +119,11 @@ impl HttpClient {
174119
where
175120
F: TryFrom<Vec<u8>, Error = std::io::Error>,
176121
{
177-
let url = format!("http://{}:{}{}", self.host, self.port, uri);
122+
let url = format!("{}{}", self.base_url, uri);
178123
let request = bitreq::post(url)
179124
.with_header("Authorization", auth)
180125
.with_header("Content-Type", "application/json")
181-
.with_timeout(TCP_STREAM_RESPONSE_TIMEOUT.as_secs())
126+
.with_timeout(TCP_STREAM_RESPONSE_TIMEOUT)
182127
.with_max_body_size(Some(MAX_HTTP_MESSAGE_BODY_SIZE))
183128
.with_body(content.to_string());
184129
let response_body = self.send_request(request).await?;
@@ -249,6 +194,7 @@ impl TryFrom<Vec<u8>> for JsonResponse {
249194
pub(crate) mod client_tests {
250195
use super::*;
251196
use std::io::{BufRead, Read, Write};
197+
use std::time::Duration;
252198

253199
/// Server for handling HTTP client requests with a stock response.
254200
pub struct HttpServer {
@@ -392,15 +338,14 @@ pub(crate) mod client_tests {
392338
Self { address, handler: Some(handler), shutdown }
393339
}
394340

395-
pub fn endpoint(&self) -> HttpEndpoint {
396-
HttpEndpoint::for_host(self.address.ip().to_string()).with_port(self.address.port())
341+
pub fn endpoint(&self) -> String {
342+
format!("http://{}:{}", self.address.ip(), self.address.port())
397343
}
398344
}
399345

400346
#[tokio::test]
401347
async fn connect_with_invalid_host() {
402-
let endpoint = HttpEndpoint::for_host("invalid.host.example".to_string()).with_port(80);
403-
let client = HttpClient::new(&endpoint);
348+
let client = HttpClient::new("http://invalid.host.example:80");
404349
match client.get::<JsonResponse>("/foo").await {
405350
Err(HttpClientError::Transport(_)) => {},
406351
Err(e) => panic!("Unexpected error type: {:?}", e),

lightning-block-sync/src/rest.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use crate::convert::GetUtxosResponse;
55
use crate::gossip::UtxoSource;
6-
use crate::http::{BinaryResponse, HttpClient, HttpClientError, HttpEndpoint, JsonResponse};
6+
use crate::http::{BinaryResponse, HttpClient, HttpClientError, JsonResponse};
77
use crate::{BlockData, BlockHeaderData, BlockSource, BlockSourceResult};
88

99
use bitcoin::hash_types::BlockHash;
@@ -12,37 +12,27 @@ use bitcoin::OutPoint;
1212
use std::convert::TryFrom;
1313
use std::convert::TryInto;
1414
use std::future::Future;
15-
use std::sync::Mutex;
1615

1716
/// A simple REST client for requesting resources using HTTP `GET`.
1817
pub struct RestClient {
19-
endpoint: HttpEndpoint,
20-
client: Mutex<Option<HttpClient>>,
18+
client: HttpClient,
2119
}
2220

2321
impl RestClient {
2422
/// Creates a new REST client connected to the given endpoint.
2523
///
26-
/// The endpoint should contain the REST path component (e.g., http://127.0.0.1:8332/rest).
27-
pub fn new(endpoint: HttpEndpoint) -> Self {
28-
Self { endpoint, client: Mutex::new(None) }
24+
/// The base URL should include the REST path component (e.g., "http://127.0.0.1:8332/rest").
25+
pub fn new(base_url: String) -> Self {
26+
Self { client: HttpClient::new(&base_url) }
2927
}
3028

3129
/// Requests a resource encoded in `F` format and interpreted as type `T`.
3230
pub async fn request_resource<F, T>(&self, resource_path: &str) -> Result<T, HttpClientError>
3331
where
3432
F: TryFrom<Vec<u8>, Error = std::io::Error> + TryInto<T, Error = std::io::Error>,
3533
{
36-
let uri = format!("{}/{}", self.endpoint.path().trim_end_matches("/"), resource_path);
37-
let reserved_client = self.client.lock().unwrap().take();
38-
let client = if let Some(client) = reserved_client {
39-
client
40-
} else {
41-
HttpClient::new(&self.endpoint)
42-
};
43-
let res = client.get::<F>(&uri).await?.try_into().map_err(HttpClientError::Io);
44-
*self.client.lock().unwrap() = Some(client);
45-
res
34+
let uri = format!("/{}", resource_path);
35+
self.client.get::<F>(&uri).await?.try_into().map_err(HttpClientError::Io)
4636
}
4737
}
4838

lightning-block-sync/src/rpc.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
//! endpoint.
33
44
use crate::gossip::UtxoSource;
5-
use crate::http::{HttpClient, HttpClientError, HttpEndpoint, JsonResponse};
5+
use crate::http::{HttpClient, HttpClientError, JsonResponse};
66
use crate::{BlockData, BlockHeaderData, BlockSource, BlockSourceResult};
77

88
use bitcoin::hash_types::BlockHash;
99
use bitcoin::OutPoint;
1010

11-
use std::sync::Mutex;
12-
1311
use serde_json;
1412

1513
use std::convert::TryFrom;
@@ -85,20 +83,20 @@ impl From<RpcError> for RpcClientError {
8583
/// [`RpcClient::call_method`] for details.
8684
pub struct RpcClient {
8785
basic_auth: String,
88-
endpoint: HttpEndpoint,
89-
client: Mutex<Option<HttpClient>>,
86+
client: HttpClient,
9087
id: AtomicUsize,
9188
}
9289

9390
impl RpcClient {
9491
/// Creates a new RPC client connected to the given endpoint with the provided credentials. The
9592
/// credentials should be a base64 encoding of a user name and password joined by a colon, as is
9693
/// required for HTTP basic access authentication.
97-
pub fn new(credentials: &str, endpoint: HttpEndpoint) -> Self {
94+
///
95+
/// The base URL should include the scheme, host, and port (e.g., "http://127.0.0.1:8332").
96+
pub fn new(credentials: &str, base_url: String) -> Self {
9897
Self {
9998
basic_auth: "Basic ".to_string() + credentials,
100-
endpoint,
101-
client: Mutex::new(None),
99+
client: HttpClient::new(&base_url),
102100
id: AtomicUsize::new(0),
103101
}
104102
}
@@ -110,21 +108,13 @@ impl RpcClient {
110108
where
111109
JsonResponse: TryFrom<Vec<u8>, Error = std::io::Error> + TryInto<T, Error = std::io::Error>,
112110
{
113-
let uri = self.endpoint.path();
114111
let content = serde_json::json!({
115112
"method": method,
116113
"params": params,
117114
"id": &self.id.fetch_add(1, Ordering::AcqRel).to_string()
118115
});
119116

120-
let reserved_client = self.client.lock().unwrap().take();
121-
let client = if let Some(client) = reserved_client {
122-
client
123-
} else {
124-
HttpClient::new(&self.endpoint)
125-
};
126-
let http_response = client.post::<JsonResponse>(&uri, &self.basic_auth, content).await;
127-
*self.client.lock().unwrap() = Some(client);
117+
let http_response = self.client.post::<JsonResponse>("/", &self.basic_auth, content).await;
128118

129119
let mut response = match http_response {
130120
Ok(JsonResponse(response)) => response,

0 commit comments

Comments
 (0)