use async_trait::async_trait;
use crate::Version;
use super::timeouts::Timeouts;
use super::clients::{ClientAuth, ClientCore, Xnat};
#[allow(dead_code)]
pub struct XnatBuilder<V: Version> {
hostname: String,
password: Option<String>,
timeouts: Option<Timeouts>,
username: Option<String>,
use_secure: bool,
version: Option<V>,
}
enum UrlKind<'a> {
Basic,
Credentialed(&'a str, Option<&'a str>),
}
impl<V: Version + Clone> XnatBuilder<V> {
fn base_url(&self, kind: UrlKind) -> anyhow::Result<reqwest::Url> {
let mut host = reqwest::Url::parse("http://stud")?;
host.set_host(Some(&self.hostname.clone()))?;
host.set_scheme(if self.use_secure {
"https"
} else {
"http"
}).unwrap();
Ok(match kind {
UrlKind::Basic => host,
UrlKind::Credentialed(u, p) => {
host.set_password(p).unwrap();
host.set_username(u).unwrap();
host
}
})
}
fn credentials(&self) -> UrlKind {
UrlKind::Credentialed(
self.username.as_deref().unwrap(),
self.password.as_deref()
)
}
fn version(&self) -> anyhow::Result<V> {
Ok(self.version.as_ref().cloned().unwrap())
}
}
pub trait ClientBuilderCore {
type Client;
fn build(&self) -> anyhow::Result<Self::Client>;
fn new(hostname: &str) -> Self;
}
impl<V: Version + Clone> ClientBuilderCore for XnatBuilder<V> {
type Client = Xnat<V>;
fn build(&self) -> anyhow::Result<Self::Client> {
Ok(Xnat::new(
&self.base_url(UrlKind::Basic)?,
&self.timeouts,
self.use_secure,
&self.version()?,
))
}
fn new(hostname: &str) -> Self {
XnatBuilder{
hostname: hostname.to_owned(),
password: None,
timeouts: None,
username: None,
use_secure: false,
version: None
}
}
}
pub trait ClientBuilderAttrs: ClientBuilderCore {
type Version: Version + Clone;
fn use_secure(self, value: bool) -> Self;
fn with_hostname(self, hostname: &str) -> Self;
fn with_password(self, password: &str) -> Self;
fn with_timeouts(self, timeouts: &Timeouts) -> Self;
fn with_username(self, username: &str) -> Self;
fn with_version(self, version: Self::Version) -> Self;
}
impl<V: Version + Clone> ClientBuilderAttrs for XnatBuilder<V> {
type Version = V;
fn use_secure(mut self, value: bool) -> Self {
self.use_secure = value;
self
}
fn with_hostname(mut self, hostname: &str) -> Self {
hostname.clone_into(&mut self.hostname);
self
}
fn with_password(mut self, password: &str) -> Self {
self.password.clone_from(&Some(password.to_owned()));
self
}
fn with_timeouts(mut self, timeouts: &Timeouts) -> Self {
self.timeouts.clone_from(&Some(timeouts.to_owned()));
self
}
fn with_username(mut self, username: &str) -> Self {
self.username.clone_from(&Some(username.to_owned()));
self
}
fn with_version(mut self, version: Self::Version) -> Self {
self.version = Some(version);
self
}
}
#[async_trait(?Send)]
pub trait ClientBuilderToken: ClientBuilderCore
where
Self::Client: ClientAuth,
{
async fn acquire(&self) -> anyhow::Result<Self::Client>;
}
#[async_trait(?Send)]
impl<V: Version + Clone> ClientBuilderToken for XnatBuilder<V>
where
Self::Client: ClientAuth,
{
async fn acquire(&self) -> anyhow::Result<Self::Client> {
let mut client = self.build()?;
let mut base_url = self.base_url(self.credentials())?;
base_url.set_path(&client.auth_uri()?);
let res = client
.client()?
.post(base_url)
.send()
.await?;
super::clients::tokacq_validator(res)
.await
.map(|token| {
client.set_session_id(&token);
client
})
}
}