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) }}
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)
}
}