use once_cell::sync::Lazy;
use reqwest::{
Client, Error, Method, Response,
header::{HeaderMap, HeaderName, HeaderValue},
};
use crate::{
network::{
extension::RequestFormExt, http_method::HttpMethod,
plugin::NetworkPlugin, target::NetworkTarget, task::NetworkTask,
},
system_info::SystemInfo,
warn_log,
};
const NETWORK_LOGGER_DOMAIN: &str = "network";
static CLIENT: Lazy<Client> = Lazy::new(|| {
let sys_info = SystemInfo::new();
match Client::builder()
.use_rustls_tls()
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.user_agent(sys_info.get_user_agent())
.build()
{
Ok(client) => client,
Err(error) => {
warn_log!(
NETWORK_LOGGER_DOMAIN,
"network_client_build_failed_using_fallback error={}",
error
);
Client::new()
}
}
});
pub struct NetworkProvider {
plugins: Vec<Box<dyn NetworkPlugin>>,
}
impl NetworkProvider {
pub fn new(plugins: Vec<Box<dyn NetworkPlugin>>) -> Self {
Self { plugins }
}
pub async fn send_request<T: NetworkTarget>(
&self,
target: &T,
) -> Result<Response, Error> {
let url = format!(
"{}/{}",
target.base_url().trim_end_matches('/'),
target.path().trim_start_matches('/')
);
let mut request = CLIENT.request(
match target.method() {
HttpMethod::Get => Method::GET,
HttpMethod::Post => Method::POST,
HttpMethod::Put => Method::PUT,
HttpMethod::Delete => Method::DELETE,
},
&url,
);
if !target.headers().is_empty() {
let headers = target.headers();
let mut header_map = HeaderMap::new();
for (key, value) in headers {
if let Ok(header_name) = key.parse::<HeaderName>() {
if let Ok(header_value) = value.parse::<HeaderValue>() {
header_map.insert(header_name, header_value);
}
}
}
request = request.headers(header_map);
}
match target.task() {
NetworkTask::RequestPlain => {
}
NetworkTask::RequestJson(json_body) => {
request = request.json(&json_body);
}
NetworkTask::RequestParameters(params) => {
request = request.query(¶ms);
}
NetworkTask::RequestBytesWithParameters(body, params) => {
request = request.query(¶ms).body(body);
}
NetworkTask::RequestMultipart(params) => {
request = request.with_multipart(params).await;
}
NetworkTask::RequestMultipartWithFiles(params, files) => {
request = request
.with_multipart_files(params.clone(), files.clone())
.await;
}
}
for plugin in &self.plugins {
if let Some(cloned_request) = request.try_clone() {
if let Ok(built_request) = cloned_request.build() {
plugin.on_request(&built_request);
}
}
}
let response = request.send().await;
match &response {
Ok(res) => {
for plugin in &self.plugins {
plugin.on_response(res);
}
}
Err(err) => {
for plugin in &self.plugins {
plugin.on_error(err);
}
}
}
response
}
}