use std::{sync::Arc, time::Duration};
use bytes::Bytes;
use scion_quic::h3::client::{H3ResponseBody, Http3Client};
use crate::error::{Error, TimeoutPhase};
pub struct Response {
parts: http::response::Parts,
body: H3ResponseBody,
deadline: tokio::time::Instant,
timeout: Duration,
_connection: Arc<Http3Client>,
}
impl Response {
pub(crate) fn new(
response: http::Response<H3ResponseBody>,
deadline: tokio::time::Instant,
timeout: Duration,
connection: Arc<Http3Client>,
) -> Self {
let (parts, body) = response.into_parts();
Response {
parts,
body,
deadline,
timeout,
_connection: connection,
}
}
#[must_use]
pub fn status(&self) -> http::StatusCode {
self.parts.status
}
#[must_use]
pub fn headers(&self) -> &http::HeaderMap {
&self.parts.headers
}
#[must_use]
pub fn is_success(&self) -> bool {
self.parts.status.is_success()
}
pub async fn bytes(
self,
max_size: Option<usize>,
) -> Result<(Bytes, Option<http::HeaderMap>), Error> {
let collected = tokio::time::timeout_at(self.deadline, self.body.bytes(max_size))
.await
.map_err(|_| {
Error::Timeout {
phase: TimeoutPhase::Body,
timeout: self.timeout,
}
})?
.map_err(|e| Error::from_collect_error(e, max_size))?;
let (body, trailers) = collected;
Ok((body.freeze(), trailers))
}
pub async fn text(
self,
max_size: Option<usize>,
) -> Result<(String, Option<http::HeaderMap>), Error> {
tokio::time::timeout_at(self.deadline, self.body.text(max_size))
.await
.map_err(|_| {
Error::Timeout {
phase: TimeoutPhase::Body,
timeout: self.timeout,
}
})?
.map_err(|e| Error::from_collect_to_string_error(e, max_size))
}
}
impl std::fmt::Debug for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Response")
.field("status", &self.parts.status)
.field("headers", &self.parts.headers)
.finish_non_exhaustive()
}
}