use std::marker::PhantomData;
use reqwest::Url;
use super::{Client, Error, LoginManager, RequestSettings, auth::AuthCallback};
use crate::version::{DefaultVersion, FhirVersion};
const DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
pub struct ClientBuilder<Version = DefaultVersion, ACB = ()> {
base_url: Option<Url>,
client: Option<reqwest::Client>,
user_agent: Option<String>,
request_settings: Option<RequestSettings>,
auth_callback: Option<ACB>,
error_on_version_mismatch: bool,
error_on_origin_mismatch: bool,
version: PhantomData<Version>,
}
impl<V, ACB> Default for ClientBuilder<V, ACB>
where
V: FhirVersion,
{
fn default() -> Self {
Self {
base_url: None,
client: None,
user_agent: None,
request_settings: None,
auth_callback: None,
error_on_version_mismatch: true,
error_on_origin_mismatch: true,
version: PhantomData,
}
}
}
impl<V, ACB> ClientBuilder<V, ACB>
where
V: FhirVersion,
{
#[must_use]
pub fn base_url(mut self, base_url: Url) -> Self {
self.base_url = Some(base_url);
self
}
#[must_use]
pub fn client(mut self, client: reqwest::Client) -> Self {
self.client = Some(client);
self
}
#[must_use]
pub fn user_agent(mut self, user_agent: String) -> Self {
self.user_agent = Some(user_agent);
self
}
#[must_use]
pub fn request_settings(mut self, settings: RequestSettings) -> Self {
self.request_settings = Some(settings);
self
}
#[must_use]
pub fn auth_callback<LM>(self, login_manager: LM) -> ClientBuilder<V, LM>
where
LM: LoginManager + 'static,
{
ClientBuilder {
base_url: self.base_url,
client: self.client,
user_agent: self.user_agent,
request_settings: self.request_settings,
auth_callback: Some(login_manager),
version: self.version,
error_on_version_mismatch: self.error_on_version_mismatch,
error_on_origin_mismatch: self.error_on_origin_mismatch,
}
}
#[must_use]
pub const fn allow_version_mismatch(mut self) -> Self {
self.error_on_version_mismatch = false;
self
}
#[must_use]
pub const fn allow_origin_mismatch(mut self) -> Self {
self.error_on_origin_mismatch = false;
self
}
pub fn build(self) -> Result<Client<V>, Error>
where
ACB: LoginManager + 'static,
{
let Some(base_url) = self.base_url else {
return Err(Error::BuilderMissingField("base_url"));
};
if base_url.cannot_be_a_base() {
return Err(Error::UrlCannotBeBase);
}
let client = match self.client {
Some(client) => client,
None => {
let user_agent = self.user_agent.as_deref().unwrap_or(DEFAULT_USER_AGENT);
reqwest::Client::builder().user_agent(user_agent).build()?
}
};
let request_settings = self.request_settings.unwrap_or_default();
let data = super::ClientData {
base_url,
client,
request_settings: std::sync::Mutex::new(request_settings),
auth_callback: tokio::sync::Mutex::new(self.auth_callback.map(AuthCallback::new)),
error_on_version_mismatch: self.error_on_version_mismatch,
error_on_origin_mismatch: self.error_on_origin_mismatch,
};
Ok(Client::from(data))
}
}
impl<V, ACB> Clone for ClientBuilder<V, ACB>
where
ACB: Clone,
{
fn clone(&self) -> Self {
Self {
base_url: self.base_url.clone(),
client: self.client.clone(),
user_agent: self.user_agent.clone(),
request_settings: self.request_settings.clone(),
auth_callback: self.auth_callback.clone(),
version: self.version,
error_on_version_mismatch: self.error_on_version_mismatch,
error_on_origin_mismatch: self.error_on_origin_mismatch,
}
}
}
impl<V, ACB> std::fmt::Debug for ClientBuilder<V, ACB> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClientBuilder")
.field("base_url", &self.base_url)
.field("client", &self.client)
.field("user_agent", &self.user_agent)
.field("request_settings", &self.request_settings)
.field("auth_callback", &self.auth_callback.as_ref().map(|_| "<login_manager>"))
.field("error_on_version_mismatch", &self.error_on_version_mismatch)
.field("error_on_origin_mismatch", &self.error_on_origin_mismatch)
.field("version", &std::any::type_name::<V>())
.finish()
}
}