use std::fmt;
use bytes::Bytes;
use futures_core::Stream;
use futures_util::TryStreamExt;
use http_body_util::BodyDataStream;
use serde::de::DeserializeOwned;
use crate::{Body, Error, HeaderMap, MaybeSend, StatusCode};
pub struct Response {
inner: http::Response<Body>,
}
impl Response {
pub fn status(&self) -> StatusCode {
self.inner.status()
}
pub fn headers(&self) -> &HeaderMap {
self.inner.headers()
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
self.inner.headers_mut()
}
pub async fn bytes(self) -> Result<Bytes, Error> {
self.inner
.into_body()
.collect_bytes()
.await
.map_err(Error::body)
}
pub async fn text(self) -> Result<String, Error> {
let bytes = self.bytes().await?;
Ok(match String::from_utf8(bytes.to_vec()) {
Ok(text) => text,
Err(error) => String::from_utf8_lossy(error.as_bytes()).into_owned(),
})
}
pub async fn json<T: DeserializeOwned>(self) -> Result<T, Error> {
let bytes = self.bytes().await?;
serde_json::from_slice(&bytes).map_err(Error::decode)
}
pub fn bytes_stream(self) -> impl Stream<Item = Result<Bytes, Error>> + MaybeSend + 'static {
BodyDataStream::new(self.inner.into_body()).map_err(Error::body)
}
pub fn events(self) -> crate::sse::Events {
crate::sse::Events::from_response(self)
}
#[cfg(all(feature = "fs", not(target_family = "wasm")))]
pub async fn save_to(self, path: impl AsRef<std::path::Path>) -> Result<u64, Error> {
crate::download::save_to(self.bytes_stream(), path.as_ref()).await
}
#[cfg(all(feature = "fs", not(target_family = "wasm")))]
pub fn into_async_read(self) -> impl tokio::io::AsyncRead + Send + Unpin + 'static {
crate::download::BodyReader::new(self.bytes_stream())
}
pub fn into_http(self) -> http::Response<Body> {
self.inner
}
}
impl From<http::Response<Body>> for Response {
fn from(inner: http::Response<Body>) -> Self {
Self { inner }
}
}
impl fmt::Debug for Response {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Response")
.field("status", &self.inner.status())
.field("headers", self.inner.headers())
.finish_non_exhaustive()
}
}