reqwest_drive/lib.rs
1#![doc = include_str!("../README.md")]
2
3use std::io;
4use std::path::Path;
5
6pub use reqwest;
7pub use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
8
9mod cache_middleware;
10pub use cache_middleware::{CacheBust, CacheBypass, CachePolicy, DriveCache};
11
12mod throttle_middleware;
13pub use throttle_middleware::{DriveThrottleBackoff, ThrottlePolicy};
14
15use simd_r_drive::DataStore;
16use std::sync::Arc;
17
18/// Initializes only the cache middleware with a file-based data store.
19///
20/// This function creates a new `DriveCache` instance backed by a `DataStore` file.
21///
22/// ## Concurrency
23///
24/// Thread-safe within a single process.
25/// Not multi-process safe when multiple processes use the same cache file concurrently.
26///
27/// # Arguments
28///
29/// * `cache_storage_file` - Path to the file where cached responses are stored.
30/// * `policy` - The cache expiration policy.
31///
32/// # Returns
33///
34/// An `Arc<DriveCache>` instance managing the cache.
35pub fn init_cache(cache_storage_file: &Path, policy: CachePolicy) -> Arc<DriveCache> {
36 Arc::new(DriveCache::new(cache_storage_file, policy))
37}
38
39/// Initializes only the cache middleware using a discovered process-scoped cache location.
40///
41/// This uses a cache group derived from this crate's package name and creates a
42/// process/thread-scoped cache storage file automatically, so callers do not need
43/// to manually provide a cache path.
44///
45/// The underlying cache root is discovered via `CacheRoot::from_discovery()`.
46///
47/// # Errors
48///
49/// Returns an error if cache root discovery, process-scoped directory creation,
50/// or store initialization fails.
51pub fn init_cache_process_scoped(policy: CachePolicy) -> io::Result<Arc<DriveCache>> {
52 Ok(Arc::new(DriveCache::new_process_scoped(policy)?))
53}
54
55/// Initializes both cache and throttle middleware with a file-based data store.
56///
57/// This function creates:
58/// - A `DriveCache` instance for response caching.
59/// - A `DriveThrottleBackoff` instance for rate-limiting and retrying failed requests.
60///
61/// ## Concurrency
62///
63/// The cache component is thread-safe within a process, but the cache file
64/// should not be shared concurrently across multiple processes.
65///
66/// # Arguments
67///
68/// * `cache_storage_file` - Path to the file where cached responses are stored.
69/// * `cache_policy` - The cache expiration policy.
70/// * `throttle_policy` - The throttling and backoff policy.
71///
72/// # Returns
73///
74/// A tuple containing:
75/// - `Arc<DriveCache>` for caching.
76/// - `Arc<DriveThrottleBackoff>` for throttling.
77pub fn init_cache_with_throttle(
78 cache_storage_file: &Path,
79 cache_policy: CachePolicy,
80 throttle_policy: ThrottlePolicy,
81) -> (Arc<DriveCache>, Arc<DriveThrottleBackoff>) {
82 let cache = Arc::new(DriveCache::new(cache_storage_file, cache_policy));
83 let throttle = Arc::new(DriveThrottleBackoff::new(
84 throttle_policy,
85 Arc::clone(&cache),
86 ));
87 (cache, throttle)
88}
89
90/// Initializes cache and throttle middleware using a discovered process-scoped cache location.
91///
92/// This uses a cache group derived from this crate's package name and creates a
93/// process/thread-scoped cache storage file automatically, so callers do not need
94/// to manually provide a cache path.
95///
96/// # Errors
97///
98/// Returns an error if cache root discovery, process-scoped directory creation,
99/// or store initialization fails.
100pub fn init_cache_process_scoped_with_throttle(
101 cache_policy: CachePolicy,
102 throttle_policy: ThrottlePolicy,
103) -> io::Result<(Arc<DriveCache>, Arc<DriveThrottleBackoff>)> {
104 let cache = Arc::new(DriveCache::new_process_scoped(cache_policy)?);
105 let throttle = Arc::new(DriveThrottleBackoff::new(
106 throttle_policy,
107 Arc::clone(&cache),
108 ));
109 Ok((cache, throttle))
110}
111
112/// Initializes only the cache middleware using an **existing** `Arc<DataStore>`.
113///
114/// This function is useful if a shared `DataStore` instance already exists
115/// and should be reused instead of creating a new one.
116///
117/// ## Concurrency
118///
119/// Thread-safe within a process.
120/// Avoid sharing the same underlying store/file concurrently across processes.
121///
122/// # Arguments
123///
124/// * `store` - A shared `Arc<DataStore>` instance.
125/// * `policy` - The cache expiration policy.
126///
127/// # Returns
128///
129/// An `Arc<DriveCache>` instance managing the cache.
130pub fn init_cache_with_drive(store: Arc<DataStore>, policy: CachePolicy) -> Arc<DriveCache> {
131 Arc::new(DriveCache::with_drive_arc(store, policy))
132}
133
134/// Initializes both cache and throttle middleware using an **existing** `Arc<DataStore>`.
135///
136/// This function is useful if a shared `DataStore` instance already exists
137/// and should be reused instead of creating a new one.
138///
139/// ## Concurrency
140///
141/// Thread-safe within a process.
142/// Avoid concurrent multi-process access to the same backing store/file.
143///
144/// # Arguments
145///
146/// * `store` - A shared `Arc<DataStore>` instance.
147/// * `cache_policy` - The cache expiration policy.
148/// * `throttle_policy` - The throttling and backoff policy.
149///
150/// # Returns
151///
152/// A tuple containing:
153/// - `Arc<DriveCache>` for caching.
154/// - `Arc<DriveThrottleBackoff>` for throttling.
155pub fn init_cache_with_drive_and_throttle(
156 store: Arc<DataStore>,
157 cache_policy: CachePolicy,
158 throttle_policy: ThrottlePolicy,
159) -> (Arc<DriveCache>, Arc<DriveThrottleBackoff>) {
160 let cache = Arc::new(DriveCache::with_drive_arc(store, cache_policy));
161 let throttle = Arc::new(DriveThrottleBackoff::new(
162 throttle_policy,
163 Arc::clone(&cache),
164 ));
165 (cache, throttle)
166}
167
168/// Initializes only the throttle middleware without any cache or data store.
169///
170/// This mode applies request throttling and retry/backoff logic only.
171/// No persistent storage is required.
172///
173/// # Arguments
174///
175/// * `throttle_policy` - The throttling and backoff policy.
176///
177/// # Returns
178///
179/// An `Arc<DriveThrottleBackoff>` instance for throttling requests.
180///
181/// # Example
182///
183/// ```no_run
184/// use reqwest_drive::{init_throttle, ThrottlePolicy};
185/// use reqwest_middleware::ClientBuilder;
186///
187/// #[tokio::main]
188/// async fn main() {
189/// let throttle = init_throttle(ThrottlePolicy {
190/// base_delay_ms: 200,
191/// adaptive_jitter_ms: 100,
192/// max_concurrent: 2,
193/// max_retries: 2,
194/// });
195///
196/// let client = ClientBuilder::new(reqwest::Client::new())
197/// .with_arc(throttle)
198/// .build();
199///
200/// let response = client.get("https://httpbin.org/get").send().await.unwrap();
201/// assert!(response.status().is_success());
202/// }
203/// ```
204pub fn init_throttle(throttle_policy: ThrottlePolicy) -> Arc<DriveThrottleBackoff> {
205 Arc::new(DriveThrottleBackoff::without_cache(throttle_policy))
206}
207
208/// Initializes a `reqwest` client with both cache and throttle middleware.
209///
210/// This function constructs a `ClientWithMiddleware` by attaching:
211/// - A `DriveCache` instance for caching HTTP responses.
212/// - A `DriveThrottleBackoff` instance for request throttling and backoff handling.
213///
214/// ## Arguments
215///
216/// * `cache` - A shared `Arc<DriveCache>` instance for caching responses.
217/// * `throttle` - A shared `Arc<DriveThrottleBackoff>` instance for throttling requests.
218///
219/// ## Returns
220///
221/// A `ClientWithMiddleware` instance that includes both caching and throttling.
222///
223/// ## Example
224///
225/// ```rust
226/// use reqwest_drive::{init_cache_with_throttle, init_client_with_cache_and_throttle, CachePolicy, ThrottlePolicy};
227/// use reqwest_middleware::ClientWithMiddleware;
228/// use std::time::Duration;
229/// use tempfile::tempdir;
230///
231/// #[tokio::main]
232/// async fn main() {
233/// let temp_dir = tempdir().unwrap();
234/// let cache_path = temp_dir.path().join("cache_storage.bin");
235///
236/// let cache_policy = CachePolicy {
237/// default_ttl: Duration::from_secs(60),
238/// respect_headers: true,
239/// cache_status_override: None,
240/// };
241///
242/// let throttle_policy = ThrottlePolicy {
243/// base_delay_ms: 200,
244/// adaptive_jitter_ms: 100,
245/// max_concurrent: 2,
246/// max_retries: 2,
247/// };
248///
249/// let (cache, throttle) = init_cache_with_throttle(&cache_path, cache_policy, throttle_policy);
250///
251/// let client: ClientWithMiddleware = init_client_with_cache_and_throttle(cache, throttle);
252///
253/// let response = client.get("https://httpbin.org/get").send().await.unwrap();
254///
255/// assert!(response.status().is_success());
256/// }
257/// ```
258pub fn init_client_with_cache_and_throttle(
259 cache: Arc<DriveCache>,
260 throttle: Arc<DriveThrottleBackoff>,
261) -> ClientWithMiddleware {
262 ClientBuilder::new(reqwest::Client::new())
263 .with_arc(cache)
264 .with_arc(throttle)
265 .build()
266}