use crate::body::SdkBody;
use crate::operation;
use crate::pin_mut;
use crate::response::ParseHttpResponse;
use crate::result::{SdkError, SdkSuccess};
use bytes::{Buf, Bytes};
use http_body::Body;
use std::error::Error;
use std::future::Future;
use tracing::trace;
type BoxError = Box<dyn Error + Send + Sync>;
pub trait AsyncMapRequest {
type Error: Into<BoxError> + 'static;
type Future: Future<Output = Result<operation::Request, Self::Error>> + Send + 'static;
fn apply(&self, request: operation::Request) -> Self::Future;
}
pub trait MapRequest {
type Error: Into<BoxError>;
fn apply(&self, request: operation::Request) -> Result<operation::Request, Self::Error>;
}
pub async fn load_response<T, E, O>(
mut response: operation::Response,
handler: &O,
) -> Result<SdkSuccess<T>, SdkError<E>>
where
O: ParseHttpResponse<Output = Result<T, E>>,
{
if let Some(parsed_response) = handler.parse_unloaded(&mut response) {
trace!(response = ?response);
return sdk_result(parsed_response, response);
}
let (http_response, properties) = response.into_parts();
let (parts, body) = http_response.into_parts();
let body = match read_body(body).await {
Ok(body) => body,
Err(err) => {
return Err(SdkError::ResponseError {
raw: operation::Response::from_parts(
http::Response::from_parts(parts, SdkBody::taken()),
properties,
),
err,
});
}
};
let http_response = http::Response::from_parts(parts, Bytes::from(body));
trace!(http_response = ?http_response);
let parsed = handler.parse_loaded(&http_response);
sdk_result(
parsed,
operation::Response::from_parts(http_response.map(SdkBody::from), properties),
)
}
async fn read_body<B: http_body::Body>(body: B) -> Result<Vec<u8>, B::Error> {
let mut output = Vec::new();
pin_mut!(body);
while let Some(buf) = body.data().await {
let mut buf = buf?;
while buf.has_remaining() {
output.extend_from_slice(buf.chunk());
buf.advance(buf.chunk().len())
}
}
Ok(output)
}
fn sdk_result<T, E>(
parsed: Result<T, E>,
raw: operation::Response,
) -> Result<SdkSuccess<T>, SdkError<E>> {
match parsed {
Ok(parsed) => Ok(SdkSuccess { raw, parsed }),
Err(err) => Err(SdkError::ServiceError { raw, err }),
}
}