1use serde::Serialize;
9
10use crate::config::{CallOptions, Config};
11use crate::error::Error;
12use crate::question::Questions;
13use crate::request::{self, Prepared, Reply, Retries, Success};
14use crate::response::{Model, Response};
15
16#[derive(Clone, Debug)]
31pub struct Client {
32 config: Config,
33 http: reqwest::blocking::Client,
34}
35
36impl Default for Client {
37 fn default() -> Self {
38 Client::new()
39 }
40}
41
42impl Client {
43 pub fn new() -> Self {
51 Client::with_config(Config::from_env()).expect("the HTTP client could not be built")
52 }
53
54 pub fn with_config(config: Config) -> Result<Self, Error> {
55 let http = reqwest::blocking::Client::builder()
56 .build()
57 .map_err(Error::from_reqwest)?;
58 Ok(Client { config, http })
59 }
60
61 pub fn config(&self) -> &Config {
62 &self.config
63 }
64
65 pub fn is_configured(&self) -> bool {
67 self.config.is_configured()
68 }
69
70 pub fn system_one<S: Serialize + ?Sized>(
75 &self,
76 state: &S,
77 questions: &Questions,
78 ) -> Result<Response, Error> {
79 self.system_one_with(state, questions, &CallOptions::default())
80 }
81
82 pub fn system_one_with<S: Serialize + ?Sized>(
84 &self,
85 state: &S,
86 questions: &Questions,
87 options: &CallOptions,
88 ) -> Result<Response, Error> {
89 let prepared = request::system_one(&self.config, state, questions, options)?;
90 let success = self.execute(prepared)?;
91 request::decode_system_one(success, questions)
92 }
93
94 pub fn models(&self) -> Result<Vec<Model>, Error> {
97 let prepared = request::models(&self.config)?;
98 let success = self.execute(prepared)?;
99 request::decode_models(success)
100 }
101
102 fn execute(&self, prepared: Prepared) -> Result<Success, Error> {
103 let mut retries = Retries::start(prepared.retry.clone());
104 loop {
105 retries.attempts += 1;
106 let result = self.attempt(&prepared, &retries);
107 match retries.after(&result) {
108 Some(delay) => std::thread::sleep(delay),
109 None => return request::finish(result),
110 }
111 }
112 }
113
114 fn attempt(&self, prepared: &Prepared, retries: &Retries) -> Result<Reply, Error> {
115 let mut builder = self
116 .http
117 .request(prepared.method.clone(), &prepared.url)
118 .headers(prepared.headers.clone())
119 .timeout(prepared.timeout);
120 if let Some((name, value)) = retries.retry_count_header() {
121 builder = builder.header(name, value);
122 }
123 if let Some(body) = &prepared.body {
124 builder = builder.body(body.clone());
125 }
126 let response = builder.send().map_err(Error::from_reqwest)?;
127 let status = response.status().as_u16();
128 let headers = response.headers().clone();
129 let body = response.bytes().map_err(Error::from_reqwest)?;
130 Ok(Reply {
131 status,
132 headers,
133 body: body.to_vec(),
134 })
135 }
136}