use std::fmt;
use std::sync::Arc;
use crate::runtime::auth::Authenticator;
/// Synchronous HTTP client wrapping `ureq::Agent`.
pub struct Client {
inner: ureq::Agent,
base_url: String,
authenticator: Option<Arc<dyn Authenticator>>,
}
impl Client {
/// Create a new client with the given base URL.
pub fn new(base_url: &str) -> Self {
Self {
inner: ureq::Agent::new_with_defaults(),
base_url: base_url.trim_end_matches('/').to_string(),
authenticator: None,
}
}
/// Create a client with a custom `ureq::Agent`.
pub fn with_agent(inner: ureq::Agent, base_url: &str) -> Self {
Self {
inner,
base_url: base_url.trim_end_matches('/').to_string(),
authenticator: None,
}
}
/// Attach an authenticator to the client.
pub fn with_auth(mut self, auth: Arc<dyn Authenticator>) -> Self {
self.authenticator = Some(auth);
self
}
fn full_url(&self, path: &str) -> String {
format!("{}{}", self.base_url, path)
}
fn apply_auth<S>(&self, mut req: ureq::RequestBuilder<S>) -> ureq::RequestBuilder<S> {
if let Some(auth) = &self.authenticator {
for (key, value) in auth.auth_headers() {
req = req.header(key, &value);
}
}
req
}
/// Build a GET request.
pub fn get(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithoutBody> {
self.apply_auth(self.inner.get(&self.full_url(path)))
}
/// Build a POST request.
pub fn post(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithBody> {
self.apply_auth(self.inner.post(&self.full_url(path)))
}
/// Build a PUT request.
pub fn put(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithBody> {
self.apply_auth(self.inner.put(&self.full_url(path)))
}
/// Build a DELETE request.
pub fn delete(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithoutBody> {
self.apply_auth(self.inner.delete(&self.full_url(path)))
}
/// Build a PATCH request.
pub fn patch(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithBody> {
self.apply_auth(self.inner.patch(&self.full_url(path)))
}
/// Build a HEAD request.
pub fn head(&self, path: &str) -> ureq::RequestBuilder<ureq::typestate::WithoutBody> {
self.apply_auth(self.inner.head(&self.full_url(path)))
}
}
impl fmt::Debug for Client {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Client")
.field("base_url", &self.base_url)
.finish()
}
}