use std::io;
use bon::Builder;
use kithara_events::RequestMethod;
use kithara_net::{Headers, NetError, NetResult, RangeSpec};
use tokio_util::sync::CancellationToken;
use url::Url;
pub type WriterFn = Box<dyn FnMut(&[u8]) -> io::Result<()> + Send>;
pub type OnResponseFn = Box<dyn FnOnce(&Headers) + Send>;
pub type OnCompleteFn = Box<dyn FnOnce(u64, Option<&Headers>, Option<&NetError>) + Send>;
pub(super) type ResponseValidator = fn(&Headers) -> NetResult<()>;
#[derive(Builder)]
#[builder(state_mod(vis = "pub"))]
#[non_exhaustive]
pub struct FetchCmd {
pub cancel: Option<CancellationToken>,
pub headers: Option<Headers>,
pub on_complete: Option<OnCompleteFn>,
pub on_response: Option<OnResponseFn>,
pub range: Option<RangeSpec>,
pub validator: Option<ResponseValidator>,
pub writer: Option<WriterFn>,
pub method: RequestMethod,
pub url: Url,
}
impl FetchCmd {
pub fn get(
url: Url,
) -> FetchCmdBuilder<fetch_cmd_builder::SetUrl<fetch_cmd_builder::SetMethod>> {
Self::builder().method(RequestMethod::Get).url(url)
}
pub fn head(
url: Url,
) -> FetchCmdBuilder<fetch_cmd_builder::SetUrl<fetch_cmd_builder::SetMethod>> {
Self::builder().method(RequestMethod::Head).url(url)
}
}
impl std::fmt::Debug for FetchCmd {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FetchCmd")
.field("method", &self.method)
.field("url", &self.url)
.field("range", &self.range)
.finish_non_exhaustive()
}
}
pub fn reject_html_response(headers: &Headers) -> NetResult<()> {
if let Some(ct) = headers.get("content-type")
&& ct.starts_with("text/html")
{
return Err(NetError::InvalidContentType(ct.to_string()));
}
Ok(())
}