use http_streams_core::{Direction, Progress, ProgressOptions, Side, StreamContext};
use std::sync::Arc;
use std::time::Duration;
pub use http_streams_core::{
StreamErrorHandler as ReqwestStreamErrorHandler, StreamOutcome as ReqwestStreamOutcome,
StreamProgress as ReqwestStreamProgress, StreamProgressHandler as ReqwestStreamProgressHandler,
};
use crate::StreamBodyError;
pub(crate) const INITIAL_CAPACITY: usize = http_streams_core::DEFAULT_BUF_CAPACITY;
const DEFAULT_PROGRESS_INTERVAL: Duration = http_streams_core::DEFAULT_PROGRESS_INTERVAL;
#[non_exhaustive]
pub struct ReqwestStreamOptions {
pub max_obj_len: usize,
pub buf_capacity: usize,
pub on_error: Option<ReqwestStreamErrorHandler>,
pub on_progress: Option<ReqwestStreamProgressHandler>,
pub progress_interval: Option<Duration>,
pub progress_items: Option<u64>,
}
impl Default for ReqwestStreamOptions {
fn default() -> Self {
Self::new()
}
}
impl ReqwestStreamOptions {
pub fn new() -> Self {
Self {
max_obj_len: usize::MAX,
buf_capacity: INITIAL_CAPACITY,
on_error: None,
on_progress: None,
progress_interval: Some(DEFAULT_PROGRESS_INTERVAL),
progress_items: None,
}
}
pub fn max_obj_len(mut self, max_obj_len: usize) -> Self {
self.max_obj_len = max_obj_len;
self
}
pub fn buf_capacity(mut self, buf_capacity: usize) -> Self {
self.buf_capacity = buf_capacity;
self
}
pub fn on_error<F>(mut self, handler: F) -> Self
where
F: Fn(&StreamBodyError) + Send + Sync + 'static,
{
self.on_error = Some(Arc::new(handler));
self
}
pub fn on_progress<F>(mut self, handler: F) -> Self
where
F: Fn(&ReqwestStreamProgress) + Send + Sync + 'static,
{
self.on_progress = Some(Arc::new(handler));
self
}
pub fn progress_interval(mut self, interval: Duration) -> Self {
self.progress_interval = Some(interval);
self
}
pub fn progress_items(mut self, items: u64) -> Self {
self.progress_items = Some(items);
self
}
}
impl ReqwestStreamOptions {
pub(crate) fn progress_options(&self) -> ProgressOptions {
let mut opts = ProgressOptions::new();
opts.on_error = self.on_error.clone();
opts.on_progress = self.on_progress.clone();
opts.progress_interval = self.progress_interval;
opts.progress_items = self.progress_items;
opts
}
}
pub(crate) fn response_progress(
format: &'static str,
response: &reqwest::Response,
options: &ReqwestStreamOptions,
) -> Progress {
let mut context = StreamContext::new(format, Direction::Response, Side::Client)
.status(response.status().as_u16())
.content_length(response.content_length())
.buf_capacity(options.buf_capacity);
if options.max_obj_len != usize::MAX {
context = context.max_obj_len(options.max_obj_len);
}
Progress::new(&context, &options.progress_options())
}
pub(crate) fn decode_response<'b, T, FMT>(
response: reqwest::Response,
format: FMT,
format_name: &'static str,
options: ReqwestStreamOptions,
) -> impl futures::Stream<Item = crate::StreamBodyResult<T>> + Send + 'b
where
FMT: http_streams_core::format::StreamFormatDecode<T>,
FMT::Framer: 'b,
FMT::Parser: 'b,
FMT::Frame: 'b,
{
let progress = response_progress(format_name, &response, &options);
let decode_options = http_streams_core::DecodeOptions::new()
.max_obj_len(options.max_obj_len)
.buf_capacity(options.buf_capacity);
let bytes = http_streams_core::count_bytes(
futures::TryStreamExt::map_err(response.bytes_stream(), std::io::Error::other),
&progress,
);
let items = http_streams_core::decode_stream(
bytes,
format.framer(&decode_options),
format.parser(),
&decode_options,
);
http_streams_core::instrument(
Box::pin(items),
progress,
http_streams_core::Counting::Items,
)
}