use std::convert::TryFrom;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use http::{Request, Response};
use http_body_util::{combinators::BoxBody, BodyExt};
use snafu::ResultExt;
use tower::Service;
use crate::body::OctoBody;
use crate::error::ReqwestSnafu;
type ResBody = BoxBody<Bytes, crate::Error>;
#[derive(Clone, Debug)]
pub struct ReqwestConnector {
client: reqwest::Client,
}
impl ReqwestConnector {
pub fn new(client: reqwest::Client) -> Self {
Self { client }
}
}
impl Service<Request<OctoBody>> for ReqwestConnector {
type Response = Response<ResBody>;
type Error = crate::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<OctoBody>) -> Self::Future {
let client = self.client.clone();
Box::pin(async move {
let (parts, body) = req.into_parts();
let body = reqwest::Body::wrap(body);
let req = Request::from_parts(parts, body);
let req = reqwest::Request::try_from(req).context(ReqwestSnafu)?;
let res = client.execute(req).await.context(ReqwestSnafu)?;
let res: Response<reqwest::Body> = res.into();
let (parts, body) = res.into_parts();
let body: ResBody = body
.map_err(|source| crate::Error::Reqwest {
source,
backtrace: snafu::Backtrace::capture(),
})
.boxed();
Ok(Response::from_parts(parts, body))
})
}
}