use std::sync::Arc;
use reqwest::header::HeaderMap;
use crate::runtime::auth::Authenticator;
use crate::runtime::error::Error;
/// HTTP client wrapper around reqwest.
#[derive(Debug, Clone)]
pub struct Client {
inner: reqwest::Client,
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: reqwest::Client::new(),
base_url: base_url.trim_end_matches('/').to_string(),
authenticator: None,
}
}
/// Create a new client with a custom reqwest::Client.
pub fn with_client(inner: reqwest::Client, base_url: &str) -> Self {
Self {
inner,
base_url: base_url.trim_end_matches('/').to_string(),
authenticator: None,
}
}
/// Set the authenticator for this client.
pub fn with_auth(mut self, auth: impl Authenticator + 'static) -> Self {
self.authenticator = Some(Arc::new(auth));
self
}
/// Build a request with authentication applied.
pub async fn request(
&self,
method: reqwest::Method,
path: &str,
) -> Result<reqwest::RequestBuilder, Error> {
let url = format!("{}{}", self.base_url, path);
let mut builder = self.inner.request(method, &url);
if let Some(auth) = &self.authenticator {
let mut headers = HeaderMap::new();
auth.authenticate(&mut headers)?;
builder = builder.headers(headers);
}
Ok(builder)
}
/// Send a request and return the response.
pub async fn send(
&self,
request: reqwest::RequestBuilder,
) -> Result<reqwest::Response, Error> {
let response = request.send().await.map_err(Error::Network)?;
Ok(response)
}
}