Skip to content

Commit 7ad948b

Browse files
committed
feat(aggregator-client): add AggregatorClientBuilder
1 parent 6607cb0 commit 7ad948b

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use anyhow::Context;
2+
use reqwest::{IntoUrl, Url};
3+
use slog::{Logger, o};
4+
5+
use mithril_common::StdResult;
6+
7+
use crate::client::AggregatorClient;
8+
9+
/// A builder of [AggregatorClient]
10+
pub struct AggregatorClientBuilder {
11+
aggregator_url_result: reqwest::Result<Url>,
12+
logger: Option<Logger>,
13+
}
14+
15+
impl AggregatorClientBuilder {
16+
/// Constructs a new `AggregatorClientBuilder`.
17+
//
18+
// This is the same as `AggregatorClient::builder()`.
19+
pub fn new<U: IntoUrl>(aggregator_url: U) -> Self {
20+
Self {
21+
aggregator_url_result: aggregator_url.into_url(),
22+
logger: None,
23+
}
24+
}
25+
26+
/// Set the [Logger] to use.
27+
pub fn with_logger(mut self, logger: Logger) -> Self {
28+
self.logger = Some(logger);
29+
self
30+
}
31+
32+
/// Returns an [AggregatorClient] based on the builder configuration
33+
pub fn build(self) -> StdResult<AggregatorClient> {
34+
let aggregator_endpoint =
35+
enforce_trailing_slash(self.aggregator_url_result.with_context(
36+
|| "Invalid aggregator endpoint, it must be a correctly formed url",
37+
)?);
38+
let logger = self.logger.unwrap_or_else(|| Logger::root(slog::Discard, o!()));
39+
40+
Ok(AggregatorClient {
41+
aggregator_endpoint,
42+
client: reqwest::Client::new(),
43+
logger,
44+
})
45+
}
46+
}
47+
48+
fn enforce_trailing_slash(url: Url) -> Url {
49+
// Trailing slash is significant because url::join
50+
// (https://docs.rs/url/latest/url/struct.Url.html#method.join) will remove
51+
// the 'path' part of the url if it doesn't end with a trailing slash.
52+
if url.as_str().ends_with('/') {
53+
url
54+
} else {
55+
let mut url = url.clone();
56+
url.set_path(&format!("{}/", url.path()));
57+
url
58+
}
59+
}
60+
61+
#[cfg(test)]
62+
mod tests {
63+
use super::*;
64+
65+
#[test]
66+
fn enforce_trailing_slash_for_aggregator_url() {
67+
let url_without_trailing_slash = Url::parse("http://localhost:8080").unwrap();
68+
let url_with_trailing_slash = Url::parse("http://localhost:8080/").unwrap();
69+
70+
assert_eq!(
71+
url_with_trailing_slash,
72+
enforce_trailing_slash(url_without_trailing_slash.clone())
73+
);
74+
assert_eq!(
75+
url_with_trailing_slash,
76+
enforce_trailing_slash(url_with_trailing_slash.clone())
77+
);
78+
}
79+
}

internal/mithril-aggregator-client/src/client.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
use anyhow::{Context, anyhow};
2-
use reqwest::Url;
2+
use reqwest::{IntoUrl, Url};
33

44
use slog::Logger;
55

66
use crate::AggregatorClientResult;
7+
use crate::builder::AggregatorClientBuilder;
78
use crate::error::AggregatorClientError;
89
use crate::query::{AggregatorQuery, QueryContext, QueryMethod};
910

1011
pub struct AggregatorClient {
11-
aggregator_endpoint: Url,
12-
client: reqwest::Client,
13-
logger: Logger,
12+
pub(super) aggregator_endpoint: Url,
13+
pub(super) client: reqwest::Client,
14+
pub(super) logger: Logger,
1415
}
1516

1617
impl AggregatorClient {
18+
/// Creates a [AggregatorClientBuilder] to configure a `AggregatorClient`.
19+
//
20+
// This is the same as `AggregatorClient::builder()`.
21+
pub fn builder<U: IntoUrl>(aggregator_url: U) -> AggregatorClientBuilder {
22+
AggregatorClientBuilder::new(aggregator_url)
23+
}
24+
1725
pub async fn send<Q: AggregatorQuery>(&self, query: Q) -> AggregatorClientResult<Q::Response> {
1826
let mut request_builder = match Q::method() {
1927
QueryMethod::Get => self.client.get(self.join_aggregator_endpoint(&query.route())?),

internal/mithril-aggregator-client/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
//! This crate provides a client to request data from a Mithril Aggregator.
33
//!
44
5+
mod builder;
56
mod client;
67
mod error;
78
pub mod query;
89
#[cfg(test)]
910
mod test;
1011

12+
pub use builder::AggregatorClientBuilder;
1113
pub use client::AggregatorClient;
1214
pub use error::AggregatorClientError;
1315

0 commit comments

Comments
 (0)