#![allow(missing_docs)]
#![allow(clippy::needless_lifetimes)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[doc(hidden)]
pub mod api_calls;
pub mod api_tokens;
pub mod apps;
pub mod constant;
pub mod file;
pub mod hidden;
pub mod meta;
pub mod oauth2;
pub mod payments;
pub mod sessions;
#[cfg(test)]
mod tests;
pub mod types;
pub mod unit;
pub mod users;
use std::env;
static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
#[derive(Clone, Debug)]
pub struct Client {
token: String,
base_url: String,
client: reqwest_middleware::ClientWithMiddleware,
}
impl Client {
#[tracing::instrument]
pub fn new<T>(token: T) -> Self
where
T: ToString + std::fmt::Debug,
{
let retry_policy =
reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
let client = reqwest::Client::builder()
.user_agent(APP_USER_AGENT)
.timeout(std::time::Duration::from_secs(60))
.connect_timeout(std::time::Duration::from_secs(60))
.build();
match client {
Ok(c) => {
let client = reqwest_middleware::ClientBuilder::new(c)
.with(reqwest_tracing::TracingMiddleware::default())
.with(reqwest_conditional_middleware::ConditionalMiddleware::new(
reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
|req: &reqwest::Request| req.try_clone().is_some(),
))
.build();
Client {
token: token.to_string(),
base_url: "https://api.kittycad.io".to_string(),
client,
}
}
Err(e) => panic!("creating reqwest client failed: {:?}", e),
}
}
#[tracing::instrument]
pub fn set_base_url<H>(&mut self, base_url: H)
where
H: Into<String> + std::fmt::Display + std::fmt::Debug,
{
self.base_url = base_url.to_string().trim_end_matches('/').to_string();
}
#[tracing::instrument]
pub fn new_from_env() -> Self {
let token = env::var("KITTYCAD_API_TOKEN").expect("must set KITTYCAD_API_TOKEN");
Client::new(token)
}
#[tracing::instrument]
pub async fn request_raw(
&self,
method: reqwest::Method,
uri: &str,
body: Option<reqwest::Body>,
) -> anyhow::Result<reqwest_middleware::RequestBuilder> {
let u = if uri.starts_with("https://") || uri.starts_with("http://") {
uri.to_string()
} else {
format!("{}/{}", self.base_url, uri.trim_start_matches('/'))
};
let mut req = self.client.request(method, &u);
req = req.bearer_auth(&self.token);
req = req.header(
reqwest::header::ACCEPT,
reqwest::header::HeaderValue::from_static("application/json"),
);
req = req.header(
reqwest::header::CONTENT_TYPE,
reqwest::header::HeaderValue::from_static("application/json"),
);
if let Some(body) = body {
req = req.body(body);
}
Ok(req)
}
pub fn api_calls(&self) -> api_calls::ApiCalls {
api_calls::ApiCalls::new(self.clone())
}
pub fn api_tokens(&self) -> api_tokens::ApiTokens {
api_tokens::ApiTokens::new(self.clone())
}
pub fn apps(&self) -> apps::Apps {
apps::Apps::new(self.clone())
}
pub fn constant(&self) -> constant::Constant {
constant::Constant::new(self.clone())
}
pub fn file(&self) -> file::File {
file::File::new(self.clone())
}
pub fn hidden(&self) -> hidden::Hidden {
hidden::Hidden::new(self.clone())
}
pub fn meta(&self) -> meta::Meta {
meta::Meta::new(self.clone())
}
pub fn oauth2(&self) -> oauth2::Oauth2 {
oauth2::Oauth2::new(self.clone())
}
pub fn payments(&self) -> payments::Payments {
payments::Payments::new(self.clone())
}
pub fn sessions(&self) -> sessions::Sessions {
sessions::Sessions::new(self.clone())
}
pub fn unit(&self) -> unit::Unit {
unit::Unit::new(self.clone())
}
pub fn users(&self) -> users::Users {
users::Users::new(self.clone())
}
}