use crate::{debug, error, types};
use http_types::headers;
use serde::de;
use std::{collections, time};
#[cfg(not(feature = "picodata_tarantool"))]
use tarantool::{fiber, fiber::r#async::timeout};
#[cfg(feature = "picodata_tarantool")]
use picodata_tarantool::system::tarantool::{fiber, fiber::r#async::timeout};
#[derive(Debug)]
pub struct Response {
url: http_types::Url,
inner: http_types::Response,
timeout: time::Duration,
}
impl debug::BodyWrapper for Response {
fn body_back(&mut self, body: Vec<u8>) {
self.inner.set_body(body);
}
}
impl Response {
pub(crate) fn new(
url: http_types::Url,
inner: http_types::Response,
timeout: time::Duration,
) -> Response {
Self {
url,
inner,
timeout,
}
}
#[inline]
pub fn status(&self) -> http_types::StatusCode {
self.inner.status()
}
#[inline]
pub fn version(&self) -> Option<http_types::Version> {
self.inner.version()
}
#[inline]
pub fn headers(&self) -> types::RefHeaders<'_> {
let mut result = collections::HashMap::with_capacity(32);
for item in self.inner.header_names() {
if let Some(value) = self.inner.header(item) {
result.insert(item, value);
}
}
result
}
#[inline]
pub fn url(&self) -> &http_types::Url {
&self.url
}
pub fn content_length(&self) -> Option<u64> {
self.inner
.header(headers::CONTENT_LENGTH)
.map(|x| x.last().as_str().parse::<u64>().ok())?
}
pub fn extensions(&self) -> &http_types::Extensions {
self.inner.ext()
}
pub fn extensions_mut(&mut self) -> &mut http_types::Extensions {
self.inner.ext_mut()
}
pub fn text(&mut self) -> Result<String, Box<error::Error>> {
fiber::block_on(timeout::timeout(self.timeout, self.inner.body_string())).map_err(|x| {
match x {
timeout::Error::Failed(e) => Box::new(error::Error::HTTP(e)),
timeout::Error::Expired => Box::new(error::Error::Timeout),
}
})
}
pub fn json<T: de::DeserializeOwned>(&mut self) -> Result<T, Box<error::Error>> {
fiber::block_on(timeout::timeout(self.timeout, self.inner.body_json::<T>())).map_err(|x| {
match x {
timeout::Error::Failed(e) => Box::new(error::Error::HTTP(e)),
timeout::Error::Expired => Box::new(error::Error::Timeout),
}
})
}
pub fn bytes(&mut self) -> Result<Vec<u8>, Box<error::Error>> {
fiber::block_on(timeout::timeout(self.timeout, self.inner.body_bytes())).map_err(
|x| match x {
timeout::Error::Failed(e) => Box::new(error::Error::HTTP(e)),
timeout::Error::Expired => Box::new(error::Error::Timeout),
},
)
}
pub fn form<T: de::DeserializeOwned>(&mut self) -> Result<T, Box<error::Error>> {
fiber::block_on(timeout::timeout(self.timeout, self.inner.body_form())).map_err(|x| match x
{
timeout::Error::Failed(e) => Box::new(error::Error::HTTP(e)),
timeout::Error::Expired => Box::new(error::Error::Timeout),
})
}
#[inline]
pub fn wrapped_body(&mut self) -> debug::WrappedBody<'_, Response> {
let b = fiber::block_on(self.inner.take_body().into_bytes())
.map_err(|e| Box::new(error::Error::HTTP(e)));
debug::WrappedBody::new(self, Some(b))
}
}