use serde::Serialize;
use crate::config::{CallOptions, Config};
use crate::error::Error;
use crate::question::Questions;
use crate::request::{self, Prepared, Reply, Retries, Success};
use crate::response::{Model, Response};
#[derive(Clone, Debug)]
pub struct Client {
config: Config,
http: reqwest::blocking::Client,
}
impl Default for Client {
fn default() -> Self {
Client::new()
}
}
impl Client {
pub fn new() -> Self {
Client::with_config(Config::from_env()).expect("the HTTP client could not be built")
}
pub fn with_config(config: Config) -> Result<Self, Error> {
let http = reqwest::blocking::Client::builder()
.build()
.map_err(Error::from_reqwest)?;
Ok(Client { config, http })
}
pub fn config(&self) -> &Config {
&self.config
}
pub fn is_configured(&self) -> bool {
self.config.is_configured()
}
pub fn system_one<S: Serialize + ?Sized>(
&self,
state: &S,
questions: &Questions,
) -> Result<Response, Error> {
self.system_one_with(state, questions, &CallOptions::default())
}
pub fn system_one_with<S: Serialize + ?Sized>(
&self,
state: &S,
questions: &Questions,
options: &CallOptions,
) -> Result<Response, Error> {
let prepared = request::system_one(&self.config, state, questions, options)?;
let success = self.execute(prepared)?;
request::decode_system_one(success, questions)
}
pub fn models(&self) -> Result<Vec<Model>, Error> {
let prepared = request::models(&self.config)?;
let success = self.execute(prepared)?;
request::decode_models(success)
}
fn execute(&self, prepared: Prepared) -> Result<Success, Error> {
let mut retries = Retries::start(prepared.retry.clone());
loop {
retries.attempts += 1;
let result = self.attempt(&prepared, &retries);
match retries.after(&result) {
Some(delay) => std::thread::sleep(delay),
None => return request::finish(result),
}
}
}
fn attempt(&self, prepared: &Prepared, retries: &Retries) -> Result<Reply, Error> {
let mut builder = self
.http
.request(prepared.method.clone(), &prepared.url)
.headers(prepared.headers.clone())
.timeout(prepared.timeout);
if let Some((name, value)) = retries.retry_count_header() {
builder = builder.header(name, value);
}
if let Some(body) = &prepared.body {
builder = builder.body(body.clone());
}
let response = builder.send().map_err(Error::from_reqwest)?;
let status = response.status().as_u16();
let headers = response.headers().clone();
let body = response.bytes().map_err(Error::from_reqwest)?;
Ok(Reply {
status,
headers,
body: body.to_vec(),
})
}
}