use crate::client::http;
use git_features::io;
use std::{
sync::mpsc::{Receiver, SyncSender},
thread,
};
mod remote;
pub struct Curl {
req: SyncSender<remote::Request>,
res: Receiver<remote::Response>,
handle: Option<thread::JoinHandle<Result<(), curl::Error>>>,
}
impl Curl {
fn restore_thread_after_failure(&mut self) -> http::Error {
let err_that_brought_thread_down = self
.handle
.take()
.expect("thread handle present")
.join()
.expect("handler thread should never panic")
.expect_err("something should have gone wrong with curl (we join on error only)");
let (handle, req, res) = remote::new();
self.handle = Some(handle);
self.req = req;
self.res = res;
err_that_brought_thread_down.into()
}
fn make_request(
&mut self,
url: &str,
headers: impl IntoIterator<Item = impl AsRef<str>>,
upload: bool,
) -> Result<http::PostResponse<io::pipe::Reader, io::pipe::Reader, io::pipe::Writer>, http::Error> {
let mut list = curl::easy::List::new();
for header in headers {
list.append(header.as_ref())?;
}
if self
.req
.send(remote::Request {
url: url.to_owned(),
headers: list,
upload,
})
.is_err()
{
return Err(self.restore_thread_after_failure());
}
let remote::Response {
headers,
body,
upload_body,
} = match self.res.recv() {
Ok(res) => res,
Err(_) => return Err(self.restore_thread_after_failure()),
};
Ok(http::PostResponse {
post_body: upload_body,
headers,
body,
})
}
}
impl Default for Curl {
fn default() -> Self {
let (handle, req, res) = remote::new();
Curl {
handle: Some(handle),
req,
res,
}
}
}
#[allow(clippy::type_complexity)]
impl crate::client::http::Http for Curl {
type Headers = io::pipe::Reader;
type ResponseBody = io::pipe::Reader;
type PostBody = io::pipe::Writer;
fn get(
&mut self,
url: &str,
headers: impl IntoIterator<Item = impl AsRef<str>>,
) -> Result<http::GetResponse<Self::Headers, Self::ResponseBody>, http::Error> {
self.make_request(url, headers, false).map(Into::into)
}
fn post(
&mut self,
url: &str,
headers: impl IntoIterator<Item = impl AsRef<str>>,
) -> Result<http::PostResponse<Self::Headers, Self::ResponseBody, Self::PostBody>, http::Error> {
self.make_request(url, headers, true)
}
}