use crate::client::auth_middleware::AuthMiddleware;
use crate::client::credentials::Credentials;
use crate::Error;
use crate::{client::auth_middleware, OsClient};
#[cfg(not(target_arch = "wasm32"))]
use reqwest::{NoProxy, Proxy};
use reqwest_middleware::ClientWithMiddleware;
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use url::Url;
#[derive(Clone, Debug)]
pub struct ConfigurationBuilder {
baseurl: String,
user_agent: Option<String>,
retries: u32,
credentials: HashMap<String, Credentials>,
accept_invalid_certificates: bool,
max_bulk_size: u32,
#[cfg(not(target_arch = "wasm32"))]
proxy: bool,
#[cfg(not(target_arch = "wasm32"))]
proxy_url: Option<Proxy>,
#[cfg(not(target_arch = "wasm32"))]
no_proxy_domain: Option<String>,
}
impl Default for ConfigurationBuilder {
fn default() -> Self {
Self {
baseurl: "http://localhost:9200".to_owned(),
user_agent: Some("opensearch-client/0.1.0".to_string()),
credentials: HashMap::new(),
accept_invalid_certificates: false,
max_bulk_size: 200,
#[cfg(not(target_arch = "wasm32"))]
proxy: false,
#[cfg(not(target_arch = "wasm32"))]
proxy_url: None,
#[cfg(not(target_arch = "wasm32"))]
no_proxy_domain: None,
#[cfg(not(test))]
retries: 2,
#[cfg(test)]
retries: 0,
}
}
}
impl ConfigurationBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn base_url(mut self, baseurl: impl Into<String>) -> Self {
self.baseurl = baseurl.into();
self
}
pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
self.user_agent = Some(user_agent.into());
self
}
pub fn accept_invalid_certificates(mut self, accept_invalid_certificates: bool) -> Self {
self.accept_invalid_certificates = accept_invalid_certificates;
self
}
pub fn max_bulk_size(mut self, max_bulk_size: u32) -> Self {
self.max_bulk_size = max_bulk_size;
self
}
pub fn basic_auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
self.credentials.insert(
auth_middleware::nerf_dart(&Url::parse(&self.baseurl).unwrap()),
Credentials::Basic {
username: username.into(),
password: Some(password.into()),
},
);
self
}
pub fn token_auth(mut self, token: impl Into<String>) -> Self {
self.credentials.insert(
auth_middleware::nerf_dart(&Url::parse(&self.baseurl).unwrap()),
Credentials::Token(token.into()),
);
self
}
pub fn legacy_auth(mut self, legacy_auth_token: impl Into<String>) -> Self {
self.credentials.insert(
auth_middleware::nerf_dart(&Url::parse(&self.baseurl).unwrap()),
Credentials::EncodedBasic(legacy_auth_token.into()),
);
self
}
pub fn retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn proxy(mut self, proxy: bool) -> Self {
self.proxy = proxy;
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn proxy_url(mut self, proxy_url: impl AsRef<str>) -> Result<Self, Error> {
match Url::parse(proxy_url.as_ref()) {
Ok(url_info) => {
let username = url_info.username();
let password = url_info.password();
let mut proxy = Proxy::all(url_info.as_ref())?;
if let Some(password_str) = password {
proxy = proxy.basic_auth(username, password_str);
}
proxy = proxy.no_proxy(self.get_no_proxy_domain());
self.proxy_url = Some(proxy);
self.proxy = true;
Ok(self)
}
Err(e) => Err(Error::UrlParseError(e)),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn no_proxy_domain(mut self, no_proxy_domain: impl AsRef<str>) -> Self {
self.no_proxy_domain = Some(no_proxy_domain.as_ref().into());
self
}
pub fn build(self) -> OsClient {
#[cfg(target_arch = "wasm32")]
let client_raw = {
let mut client_core = ClientBuilder::new();
if self.accept_invalid_certificates {
let mut builder = client_raw.clone().builder();
builder = builder.danger_accept_invalid_certs(true);
builder = builder.danger_accept_invalid_hostnames(true);
client_raw = builder.build().unwrap();
}
client_core.build().expect("Fail to build HTTP client.")
};
#[cfg(not(target_arch = "wasm32"))]
let client_raw = {
use reqwest::ClientBuilder;
let mut client_core = ClientBuilder::new()
.user_agent("opensearch-client/0.1.0")
.pool_max_idle_per_host(20)
.timeout(std::time::Duration::from_secs(60 * 5));
if let Some(url) = self.proxy_url {
client_core = client_core.proxy(url);
}
if !self.proxy {
client_core = client_core.no_proxy();
}
if self.accept_invalid_certificates {
client_core = client_core.danger_accept_invalid_certs(true);
client_core = client_core.danger_accept_invalid_hostnames(true);
}
client_core.build().expect("Fail to build HTTP client.")
};
let retry_policy = ExponentialBackoff::builder()
.retry_bounds(
std::time::Duration::from_millis(30),
std::time::Duration::from_millis(100),
)
.build_with_max_retries(self.retries);
let retry_strategy = RetryTransientMiddleware::new_with_policy(retry_policy);
let credentials = Arc::new(self.credentials);
#[allow(unused_mut)]
let mut client_builder = reqwest_middleware::ClientBuilder::new(client_raw.clone())
.with(retry_strategy)
.with(AuthMiddleware(credentials.clone()));
let configuration = Configuration {
base_path: self.baseurl.clone(),
client: client_builder.build(),
bulker: Arc::new(Mutex::new(String::new())),
bulker_size: Arc::new(Mutex::new(0)),
max_bulk_size: self.max_bulk_size,
};
OsClient::new(Arc::new(configuration))
}
#[cfg(not(target_arch = "wasm32"))]
fn get_no_proxy_domain(&self) -> Option<NoProxy> {
if let Some(ref no_proxy_conf) = self.no_proxy_domain {
if !no_proxy_conf.is_empty() {
return NoProxy::from_string(no_proxy_conf);
}
}
NoProxy::from_env().or(None)
}
}
#[derive(Debug, Clone)]
pub struct Configuration {
pub(crate) base_path: String,
pub(crate) client: ClientWithMiddleware,
pub(crate) bulker: Arc<Mutex<String>>,
pub(crate) bulker_size: Arc<Mutex<u32>>,
pub(crate) max_bulk_size: u32,
}
impl Configuration {
pub fn base_path(&self) -> &str {
&self.base_path
}
pub fn client(&self) -> &ClientWithMiddleware {
&self.client
}
pub fn bulker(&self) -> Arc<Mutex<String>> {
Arc::clone(&self.bulker)
}
pub fn bulker_size(&self) -> Arc<Mutex<u32>> {
Arc::clone(&self.bulker_size)
}
pub fn max_bulk_size(&self) -> u32 {
self.max_bulk_size
}
}
impl Configuration {
pub fn new() -> Configuration {
Configuration::default()
}
}
impl Default for Configuration {
fn default() -> Self {
Configuration {
base_path: "http://localhost:9200".to_owned(),
client: reqwest_middleware::ClientBuilder::new(reqwest::Client::new()).build(),
bulker: Arc::new(Mutex::new(String::new())),
bulker_size: Arc::new(Mutex::new(0)),
max_bulk_size: 100,
}
}
}