1use blitz_traits::net::{Bytes, NetHandler, NetProvider, NetWaker, Request};
4use blitz_traits::platform::{
5 FetchError, FetchHandler, FetchProvider, FetchRequest, FetchResponse, StatusCode,
6};
7use std::sync::Arc;
8
9pub struct Provider(crate::core::Provider);
11
12impl Provider {
13 pub fn for_scope(
15 self: &Arc<Self>,
16 initiator: blitz_traits::net::Initiator,
17 ) -> Arc<crate::ScopedProvider> {
18 Arc::new(crate::ScopedProvider::new(Arc::clone(self), initiator))
19 }
20
21 pub fn new(waker: Option<Arc<dyn NetWaker>>) -> Self {
22 Self(crate::core::Provider::new(waker))
23 }
24
25 pub fn with_user_agent(waker: Option<Arc<dyn NetWaker>>, user_agent: &str) -> Self {
26 Self(crate::core::Provider::with_user_agent(waker, user_agent))
27 }
28
29 #[cfg(feature = "cookies")]
30 pub fn with_user_agent_and_cookie_provider<C>(
31 waker: Option<Arc<dyn NetWaker>>,
32 user_agent: &str,
33 cookie_provider: Arc<C>,
34 ) -> Self
35 where
36 C: crate::CookieJar,
37 {
38 Self(crate::core::Provider::with_user_agent_and_cookie_provider(
39 waker,
40 user_agent,
41 cookie_provider,
42 ))
43 }
44
45 #[cfg(all(feature = "cache", not(target_arch = "wasm32")))]
46 pub fn with_cache(self, cache: Arc<crate::PrivateCache>) -> Self {
47 Self(self.0.with_cache(cache))
48 }
49
50 #[cfg(all(feature = "cache", not(target_arch = "wasm32")))]
51 pub async fn with_cache_directory(
52 self,
53 directory: impl AsRef<std::path::Path>,
54 ) -> std::io::Result<Self> {
55 self.0.with_cache_directory(directory).await.map(Self)
56 }
57
58 pub fn shared(waker: Option<Arc<dyn NetWaker>>) -> Arc<dyn NetProvider> {
59 crate::core::Provider::shared(waker)
60 }
61
62 pub fn shared_with_user_agent(
63 waker: Option<Arc<dyn NetWaker>>,
64 user_agent: &str,
65 ) -> Arc<dyn NetProvider> {
66 crate::core::Provider::shared_with_user_agent(waker, user_agent)
67 }
68
69 pub fn user_agent(&self) -> &str {
70 self.0.user_agent()
71 }
72 pub fn is_empty(&self) -> bool {
73 self.0.is_empty()
74 }
75 pub fn count(&self) -> usize {
76 self.0.count()
77 }
78
79 #[cfg(all(feature = "cache", not(target_arch = "wasm32")))]
80 pub async fn clear_cache(&self) {
81 self.0.clear_cache().await;
82 }
83
84 #[allow(clippy::type_complexity)]
85 pub fn fetch_with_callback(
86 &self,
87 request: Request,
88 callback: Box<dyn FnOnce(Result<(String, Bytes), ProviderError>) + Send + Sync + 'static>,
89 ) {
90 self.0.fetch_with_callback(
91 request,
92 Box::new(move |result| {
93 callback(result.map_err(ProviderError::from));
94 }),
95 );
96 }
97
98 pub async fn fetch_async(&self, request: Request) -> Result<(String, Bytes), ProviderError> {
99 self.0
100 .fetch_async(request)
101 .await
102 .map_err(ProviderError::from)
103 }
104
105 pub async fn fetch_response_async(
106 &self,
107 request: Request,
108 ) -> Result<FetchResponse, ProviderError> {
109 self.0
110 .fetch_response_async(request)
111 .await
112 .map_err(ProviderError::from)
113 }
114
115 pub async fn fetch_platform_async(
116 &self,
117 request: FetchRequest,
118 ) -> Result<FetchResponse, FetchError> {
119 self.0.fetch_platform_async(request).await
120 }
121}
122
123impl FetchProvider for Provider {
124 fn fetch(&self, request: FetchRequest, handler: Box<dyn FetchHandler>) {
125 FetchProvider::fetch(&self.0, request, handler);
126 }
127}
128
129impl NetProvider for Provider {
130 fn fetch(&self, doc_id: usize, request: Request, handler: Box<dyn NetHandler>) {
131 NetProvider::fetch(&self.0, doc_id, request, handler);
132 }
133}
134
135#[derive(Debug)]
138pub enum ProviderError {
139 Abort,
140 Io(std::io::Error),
141 DataUrl(data_url::DataUrlError),
142 DataUrlBase64(data_url::forgiving_base64::InvalidBase64),
143 Network(String),
144 TlsPolicy(crate::TlsPolicyError),
145 InvalidRequest(String),
146 UnsupportedScheme(String),
147 HttpStatus { status: StatusCode, url: String },
148}
149
150impl From<crate::core::ProviderError> for ProviderError {
151 fn from(error: crate::core::ProviderError) -> Self {
152 use crate::core::ProviderError as Core;
153 match error {
154 Core::Abort => Self::Abort,
155 Core::Io(error) => Self::Io(error),
156 Core::DataUrl(error) => Self::DataUrl(error),
157 Core::DataUrlBase64(error) => Self::DataUrlBase64(error),
158 Core::Network(error) => Self::Network(error),
159 Core::Blocked(reason) => Self::Network(format!("blocked: {reason}")),
160 Core::TlsPolicy(reason) => Self::TlsPolicy(reason),
161 Core::InvalidRequest(error) => Self::InvalidRequest(error),
162 Core::UnsupportedScheme(scheme) => Self::UnsupportedScheme(scheme),
163 Core::HttpStatus { status, url } => Self::HttpStatus { status, url },
164 }
165 }
166}
167
168impl std::fmt::Display for ProviderError {
169 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 match self {
171 Self::Abort => write!(formatter, "request aborted"),
172 Self::Io(error) => write!(formatter, "io error: {error}"),
173 Self::DataUrl(error) => write!(formatter, "data url error: {error:?}"),
174 Self::DataUrlBase64(error) => write!(formatter, "data url base64 error: {error:?}"),
175 Self::Network(error) => write!(formatter, "network error: {error}"),
176 Self::TlsPolicy(reason) => write!(formatter, "TLS policy: {reason}"),
177 Self::InvalidRequest(error) => write!(formatter, "invalid request: {error}"),
178 Self::UnsupportedScheme(scheme) => {
179 write!(formatter, "unsupported URL scheme: {scheme}")
180 }
181 Self::HttpStatus { status, url } => write!(formatter, "HTTP {status} for {url}"),
182 }
183 }
184}
185
186impl std::error::Error for ProviderError {}
187
188impl From<std::io::Error> for ProviderError {
189 fn from(error: std::io::Error) -> Self {
190 Self::Io(error)
191 }
192}
193
194impl From<data_url::DataUrlError> for ProviderError {
195 fn from(error: data_url::DataUrlError) -> Self {
196 Self::DataUrl(error)
197 }
198}
199
200impl From<data_url::forgiving_base64::InvalidBase64> for ProviderError {
201 fn from(error: data_url::forgiving_base64::InvalidBase64) -> Self {
202 Self::DataUrlBase64(error)
203 }
204}