use crate::universal::errors::ClientErr;
use std::convert::TryInto;
use std::io::Read;
use crate::universal::HttpClient;
#[cfg(feature = "reqwest")]
use ::reqwest::Client;
use async_trait::async_trait;
use http::header::HeaderMap;
use http::Method;
use crate::prelude::video::VideoParams;
use crate::universal::form_data::create_form_data;
use crate::prelude::utils::UploadingData;
#[derive(Debug, Clone)]
pub struct ReqwestClient {
pub client: Client,
pub headers: HeaderMap,
}
#[async_trait(?Send)]
impl HttpClient for ReqwestClient {
fn new<U: Into<Option<HeaderMap>>>(headers: U) -> Result<Self, ClientErr> {
let client = Client::builder();
let headers = match headers.into() {
Some(h) => h,
None => HeaderMap::new(),
};
client
.default_headers(headers.clone())
.build()
.map(|c| ReqwestClient { client: c, headers })
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))
}
async fn request(
&self,
request: http::Request<String>,
) -> Result<http::Response<String>, ClientErr> {
let version = request.version().clone();
let req = request.try_into().unwrap();
let resp = self
.client
.execute(req)
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let status_code = resp.status();
let headers = resp.headers().clone();
let content = resp
.text()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let mut build = http::Response::builder();
for header in headers.iter() {
build = build.header(header.0, header.1);
}
build
.status(status_code)
.version(version)
.body(content)
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))
}
async fn video_request(
&self,
request: http::Request<VideoParams>,
) -> Result<http::Response<String>, ClientErr> {
let url = request.uri().to_string();
let method = request.method().clone();
let body = request.body().to_owned();
let req = match method {
Method::GET => Client::new().get(url),
Method::POST => Client::new().post(url),
Method::PUT => Client::new().put(url),
Method::DELETE => Client::new().delete(url),
m @ _ => return Err(ClientErr::HttpClient(format!("invalid method {}", m))),
};
let resp = req
.multipart(create_form_data(body, Vec::new()))
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let version = request.version();
let status_code = resp.status();
let headers = resp.headers().clone();
let content = resp
.text()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let mut build = http::Response::builder();
for header in headers.iter() {
build = build.header(header.0, header.1);
}
build
.status(status_code)
.version(version)
.body(content)
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))
}
async fn resumable_video_request(
&self,
request: http::Request<UploadingData>,
) -> Result<http::Response<String>, ClientErr> {
let url = request.uri().to_string();
let method = request.method().clone();
let body = request.body().to_owned();
let req = match method {
Method::GET => Client::new().get(url),
Method::POST => Client::new().post(url),
Method::PUT => Client::new().put(url),
Method::DELETE => Client::new().delete(url),
Method::PATCH => Client::new().patch(url),
Method::HEAD => Client::new().head(url),
m @ _ => return Err(ClientErr::HttpClient(format!("invalid method {}", m))),
};
let resp = if body.upload_phase == "start".to_string() {
let response = req
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
response
} else if body.upload_phase == "transfer".to_string() {
use std::fs::File;
let mut file = File::open(body.file_path.clone()).unwrap();
let mut buffer = [0; 1048576];
file.read_exact(&mut buffer).unwrap();
let part = reqwest::multipart::Part::bytes(buffer.to_vec());
let form = reqwest::multipart::Form::new().part("video_file_chunk", part);
let response = req
.multipart(form)
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
response
} else if body.upload_phase == "finish".to_string() {
let response = req
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
response
} else if body.upload_phase == "cancel".to_string() {
let response = req
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
response
} else {
let response = req
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
response
};
let status_code = resp.status();
let headers = resp.headers().clone();
let version = request.version();
let content = resp
.text()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let mut build = http::Response::builder();
for header in headers.iter() {
build = build.header(header.0, header.1);
}
build
.status(status_code)
.version(version)
.body(content)
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))
}
async fn upload_by_form_data_request(
&self,
request: http::Request<(Vec<u8>, VideoParams)>,
) -> Result<http::Response<String>, ClientErr> {
let url = request.uri().to_string();
let method = request.method().clone();
let (buffer, params) = request.body().clone();
let req = match method {
Method::GET => Client::new().get(url),
Method::POST => Client::new().post(url),
Method::PUT => Client::new().put(url),
Method::DELETE => Client::new().delete(url),
Method::PATCH => Client::new().patch(url),
Method::HEAD => Client::new().head(url),
m @ _ => return Err(ClientErr::HttpClient(format!("invalid method {}", m))),
};
let part = reqwest::multipart::Part::bytes(buffer);
let form = reqwest::multipart::Form::new()
.part("source", part)
.text("description", params.clone().description)
.text("description", params.clone().title);
let resp = req
.multipart( form)
.send()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
let status_code = resp.status();
let headers = resp.headers().clone();
let version = request.version();
let content = resp
.text()
.await
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))?;
println!("facebook api {}", content.clone());
let mut build = http::Response::builder();
for header in headers.iter() {
build = build.header(header.0, header.1);
}
build
.status(status_code)
.version(version)
.body(content)
.map_err(|e| ClientErr::HttpClient(format!("{:?}", e)))
}
}