1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! Per-request proxy routing strategy.
//!
//! The [`ProxyStrategy`] trait is the proxy-side analogue of
//! [`crate::retry_strategy::RetryStrategy`]: an opt-in, per-request
//! decision hook that decides which categorical "kind" a request
//! belongs to. The crate then looks the kind up in
//! [`crate::configuration::Configuration::proxies_by_kind`] and routes
//! the request through the matching proxy list, lazily building a
//! secondary HTTP client on first use and dropping it automatically
//! once no in-flight request still holds a clone.
//!
//! This module is purely additive — no behavior changes when no
//! strategy is set on the [`Website`](crate::website::Website). Default
//! `proxy_strategy = None` keeps every existing call site identical to
//! today.
//!
//! # Composing with `RetryStrategy`
//!
//! [`RetryStrategy`](crate::retry_strategy::RetryStrategy) decides
//! *when* to retry and what overall configuration to apply.
//! `ProxyStrategy` decides *which proxy* a single request goes through.
//! The two compose: a retry strategy may swap the entire proxy list
//! between attempts; the proxy strategy then routes within whatever
//! list is current.
//!
//! # Concurrency
//!
//! [`ProxyStrategy::route`] takes `&self` and is shared across tasks
//! via [`SharedProxyStrategy`] (`Arc<dyn ProxyStrategy>`). Use atomics
//! or [`arc_swap`] inside your impl when you need per-strategy state —
//! mutexes are not required and not recommended on the hot path.
//!
//! # Example
//!
//! ```no_run
//! use std::sync::Arc;
//! use spider::configuration::ProxyKind;
//! use spider::proxy_strategy::{ProxyStrategy, ProxyRouteContext, SharedProxyStrategy};
//! use spider::utils::media_asset::is_media_asset_url;
//!
//! struct AssetRouter;
//! impl ProxyStrategy for AssetRouter {
//! fn route(&self, ctx: &ProxyRouteContext) -> ProxyKind {
//! if is_media_asset_url(ctx.url) {
//! ProxyKind::MediaAsset
//! } else {
//! ProxyKind::Default
//! }
//! }
//! }
//! let _strategy: SharedProxyStrategy = Arc::new(AssetRouter);
//! ```
use crateProxyKind;
use Arc;
/// Borrowed context for a single routing decision.
///
/// All fields borrow from caller-owned storage so dispatching the
/// strategy is allocation-free. Add fields here in a backward-compatible
/// way (the struct is not `#[non_exhaustive]` yet — promote to that on
/// the next minor bump if desired).
/// A pluggable strategy for routing requests to a proxy kind.
///
/// Implementations are object-safe and shared via `Arc<dyn ProxyStrategy>`.
/// Returning [`ProxyKind::Default`] (or any kind not present in
/// [`crate::configuration::Configuration::proxies_by_kind`]) keeps the
/// existing fast path — no secondary client is built, no allocation,
/// no behavior change.
///
/// # Example
///
/// See the [module docs](self) for a worked example pairing this with
/// [`crate::utils::media_asset::is_media_asset_url`].
/// Shared handle to a [`ProxyStrategy`], cheap to clone across tasks.
pub type SharedProxyStrategy = ;