#![forbid(unsafe_code)]
mod error;
#[rustfmt::skip]
pub mod generated;
mod pagination;
mod sse;
mod transport;
use std::sync::Arc;
use std::time::Duration;
use reqwest::header::HeaderMap;
use reqwest::Method;
use serde_json::Value;
pub use error::{ApiError, MisarDevError, PlanLimitError, RateLimitError};
pub use generated::*;
pub use pagination::{items_of, paginate, PaginateOptions};
pub use sse::{parse_frame, EventStream, RawFrame, SseEvent};
pub use transport::{
backoff, build_query, encode_path, Query, Transport, DEFAULT_BASE_URL, SDK_VERSION,
};
#[derive(Debug, Clone)]
pub struct MisarDev {
pub(crate) transport: Arc<Transport>,
}
impl MisarDev {
pub fn new(api_key: impl Into<String>) -> Result<Self, MisarDevError> {
Self::builder().api_key(api_key).build()
}
pub fn from_env() -> Result<Self, MisarDevError> {
Self::builder().build()
}
pub fn builder() -> MisarDevBuilder {
MisarDevBuilder::default()
}
pub fn base_url(&self) -> &str {
&self.transport.base_url
}
pub fn transport(&self) -> &Transport {
&self.transport
}
pub async fn request(
&self,
method: Method,
path: &str,
query: Option<Value>,
body: Option<Value>,
) -> Result<Value, MisarDevError> {
let q = build_query(query.as_ref(), &[]);
self.transport.request(method, path, &q, body).await
}
pub async fn stream(
&self,
method: Method,
path: &str,
query: Option<Value>,
body: Option<Value>,
terminator: Option<&str>,
) -> Result<EventStream, MisarDevError> {
let q = build_query(query.as_ref(), &[]);
self.transport
.stream(method, path, &q, body, terminator)
.await
}
}
#[derive(Debug, Default)]
pub struct MisarDevBuilder {
api_key: Option<String>,
base_url: Option<String>,
max_retries: Option<u32>,
timeout: Option<Duration>,
headers: Vec<(String, String)>,
http: Option<reqwest::Client>,
}
impl MisarDevBuilder {
pub fn api_key(mut self, key: impl Into<String>) -> Self {
self.api_key = Some(key.into());
self
}
pub fn base_url(mut self, url: impl Into<String>) -> Self {
self.base_url = Some(url.into());
self
}
pub fn max_retries(mut self, n: u32) -> Self {
self.max_retries = Some(n);
self
}
pub fn timeout(mut self, d: Duration) -> Self {
self.timeout = Some(d);
self
}
pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
self.headers.push((name.into(), value.into()));
self
}
pub fn http_client(mut self, client: reqwest::Client) -> Self {
self.http = Some(client);
self
}
pub fn build(self) -> Result<MisarDev, MisarDevError> {
let api_key = self
.api_key
.filter(|k| !k.is_empty())
.or_else(|| {
std::env::var("MISARDEV_API_KEY")
.ok()
.filter(|k| !k.is_empty())
})
.ok_or(MisarDevError::MissingApiKey)?;
let base_url = self
.base_url
.filter(|u| !u.is_empty())
.or_else(|| {
std::env::var("MISARDEV_BASE_URL")
.ok()
.filter(|u| !u.is_empty())
})
.unwrap_or_else(|| DEFAULT_BASE_URL.to_owned())
.trim_end_matches('/')
.to_owned();
let mut headers = HeaderMap::new();
for (name, value) in &self.headers {
let (n, v) = transport::header_pair(name, value)?;
headers.insert(n, v);
}
let http = match self.http {
Some(h) => h,
None => reqwest::Client::builder()
.build()
.map_err(|e| MisarDevError::Config(e.to_string()))?,
};
Ok(MisarDev {
transport: Arc::new(Transport {
api_key,
base_url,
max_retries: self.max_retries.unwrap_or(3).max(1),
timeout: self.timeout.unwrap_or(Duration::from_secs(60)),
headers,
http,
}),
})
}
}