apub_core/
session.rs

1//! Types and traits governing whether requests should procede
2
3use std::future::Future;
4use url::Url;
5
6/// Describes types that track requests
7///
8/// The Session type can be included by downstream client implementations as a generic middleware
9/// interface for deciding when requests should or should not continue.
10///
11/// An included [`RequestCountSession`] type is included, which simply counts how many requests the
12/// session has observed and indicates future requests shouldn't be executed after it's limit is
13/// hit.
14pub trait Session {
15    /// Returns false if a request to the given URL should not procede
16    fn should_procede(&mut self, url: &Url) -> bool;
17
18    /// Update the session from a successful request
19    fn mark_success(&mut self, url: &Url);
20
21    /// Update the session from a failed request
22    fn mark_failure(&mut self, url: &Url);
23}
24
25/// Describes types that can produce Sessions
26pub trait SessionFactory {
27    /// The Session being produced
28    type Session: Session;
29
30    /// Produce the session
31    fn build_session(&self) -> Self::Session;
32}
33
34/// A Session that limits the total number of requests allowed to procede
35///
36/// This type is useful in the case of resolving dependencies of an object. A limit can be set that
37/// decides when the resolver has recursed too far.
38pub struct RequestCountSession {
39    count: usize,
40    max_requests: usize,
41}
42
43/// A simple error type that occurs when a session decides not to procede with a request
44#[derive(Clone, Debug)]
45pub struct SessionError;
46
47/// A simple guard method that can be used by downstream client and repo implementations for
48/// guarding their requests
49pub async fn guard<Fut, T, E, S>(fut: Fut, url: &Url, mut session: S) -> Result<T, E>
50where
51    Fut: Future<Output = Result<T, E>>,
52    E: From<SessionError>,
53    S: Session,
54{
55    if !session.should_procede(url) {
56        return Err(SessionError.into());
57    }
58
59    match fut.await {
60        Ok(t) => {
61            session.mark_success(url);
62            Ok(t)
63        }
64        Err(e) => {
65            session.mark_failure(url);
66            Err(e)
67        }
68    }
69}
70
71impl RequestCountSession {
72    /// Create a new RequestCountSession with a maximum number of allowed requests
73    ///
74    /// Generically, this session should be created new for each set of client requests
75    pub fn max(max_requests: usize) -> Self {
76        Self {
77            count: 0,
78            max_requests,
79        }
80    }
81}
82
83impl std::fmt::Display for SessionError {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(f, "SessionError")
86    }
87}
88
89impl std::error::Error for SessionError {}
90
91impl Session for RequestCountSession {
92    fn should_procede(&mut self, _: &Url) -> bool {
93        self.count < self.max_requests
94    }
95
96    fn mark_success(&mut self, _: &Url) {
97        self.count += 1;
98    }
99
100    fn mark_failure(&mut self, _: &Url) {
101        self.count += 1;
102    }
103}
104
105impl Session for () {
106    fn should_procede(&mut self, _: &Url) -> bool {
107        true
108    }
109
110    fn mark_success(&mut self, _: &Url) {}
111    fn mark_failure(&mut self, _: &Url) {}
112}
113
114impl<'a, T> Session for &'a mut T
115where
116    T: Session,
117{
118    fn should_procede(&mut self, url: &Url) -> bool {
119        T::should_procede(self, url)
120    }
121
122    fn mark_success(&mut self, url: &Url) {
123        T::mark_success(self, url)
124    }
125
126    fn mark_failure(&mut self, url: &Url) {
127        T::mark_failure(self, url)
128    }
129}
130
131impl<T> Session for Box<T>
132where
133    T: Session,
134{
135    fn should_procede(&mut self, url: &Url) -> bool {
136        T::should_procede(self, url)
137    }
138
139    fn mark_success(&mut self, url: &Url) {
140        T::mark_success(self, url)
141    }
142
143    fn mark_failure(&mut self, url: &Url) {
144        T::mark_failure(self, url)
145    }
146}
147
148impl<T, U> Session for (T, U)
149where
150    T: Session,
151    U: Session,
152{
153    fn should_procede(&mut self, url: &Url) -> bool {
154        self.0.should_procede(url) && self.1.should_procede(url)
155    }
156
157    fn mark_success(&mut self, url: &Url) {
158        self.0.mark_success(url);
159        self.1.mark_success(url);
160    }
161
162    fn mark_failure(&mut self, url: &Url) {
163        self.0.mark_failure(url);
164        self.1.mark_failure(url);
165    }
166}
167
168impl<T, U, V> Session for (T, U, V)
169where
170    T: Session,
171    U: Session,
172    V: Session,
173{
174    fn should_procede(&mut self, url: &Url) -> bool {
175        self.0.should_procede(url) && self.1.should_procede(url) && self.2.should_procede(url)
176    }
177
178    fn mark_success(&mut self, url: &Url) {
179        self.0.mark_success(url);
180        self.1.mark_success(url);
181        self.2.mark_success(url);
182    }
183
184    fn mark_failure(&mut self, url: &Url) {
185        self.0.mark_failure(url);
186        self.1.mark_failure(url);
187        self.2.mark_failure(url);
188    }
189}
190
191impl<T, U, V, W> Session for (T, U, V, W)
192where
193    T: Session,
194    U: Session,
195    V: Session,
196    W: Session,
197{
198    fn should_procede(&mut self, url: &Url) -> bool {
199        self.0.should_procede(url)
200            && self.1.should_procede(url)
201            && self.2.should_procede(url)
202            && self.3.should_procede(url)
203    }
204
205    fn mark_success(&mut self, url: &Url) {
206        self.0.mark_success(url);
207        self.1.mark_success(url);
208        self.2.mark_success(url);
209        self.3.mark_success(url);
210    }
211
212    fn mark_failure(&mut self, url: &Url) {
213        self.0.mark_failure(url);
214        self.1.mark_failure(url);
215        self.2.mark_failure(url);
216        self.3.mark_failure(url);
217    }
218}
219
220impl<T, U, V, W, X> Session for (T, U, V, W, X)
221where
222    T: Session,
223    U: Session,
224    V: Session,
225    W: Session,
226    X: Session,
227{
228    fn should_procede(&mut self, url: &Url) -> bool {
229        self.0.should_procede(url)
230            && self.1.should_procede(url)
231            && self.2.should_procede(url)
232            && self.3.should_procede(url)
233            && self.4.should_procede(url)
234    }
235
236    fn mark_success(&mut self, url: &Url) {
237        self.0.mark_success(url);
238        self.1.mark_success(url);
239        self.2.mark_success(url);
240        self.3.mark_success(url);
241        self.4.mark_success(url);
242    }
243
244    fn mark_failure(&mut self, url: &Url) {
245        self.0.mark_failure(url);
246        self.1.mark_failure(url);
247        self.2.mark_failure(url);
248        self.3.mark_failure(url);
249        self.4.mark_failure(url);
250    }
251}
252
253impl<T, U, V, W, X, Y> Session for (T, U, V, W, X, Y)
254where
255    T: Session,
256    U: Session,
257    V: Session,
258    W: Session,
259    X: Session,
260    Y: Session,
261{
262    fn should_procede(&mut self, url: &Url) -> bool {
263        self.0.should_procede(url)
264            && self.1.should_procede(url)
265            && self.2.should_procede(url)
266            && self.3.should_procede(url)
267            && self.4.should_procede(url)
268            && self.5.should_procede(url)
269    }
270
271    fn mark_success(&mut self, url: &Url) {
272        self.0.mark_success(url);
273        self.1.mark_success(url);
274        self.2.mark_success(url);
275        self.3.mark_success(url);
276        self.4.mark_success(url);
277        self.5.mark_success(url);
278    }
279
280    fn mark_failure(&mut self, url: &Url) {
281        self.0.mark_failure(url);
282        self.1.mark_failure(url);
283        self.2.mark_failure(url);
284        self.3.mark_failure(url);
285        self.4.mark_failure(url);
286        self.5.mark_failure(url);
287    }
288}
289
290impl<T, U, V, W, X, Y, Z> Session for (T, U, V, W, X, Y, Z)
291where
292    T: Session,
293    U: Session,
294    V: Session,
295    W: Session,
296    X: Session,
297    Y: Session,
298    Z: Session,
299{
300    fn should_procede(&mut self, url: &Url) -> bool {
301        self.0.should_procede(url)
302            && self.1.should_procede(url)
303            && self.2.should_procede(url)
304            && self.3.should_procede(url)
305            && self.4.should_procede(url)
306            && self.5.should_procede(url)
307            && self.6.should_procede(url)
308    }
309
310    fn mark_success(&mut self, url: &Url) {
311        self.0.mark_success(url);
312        self.1.mark_success(url);
313        self.2.mark_success(url);
314        self.3.mark_success(url);
315        self.4.mark_success(url);
316        self.5.mark_success(url);
317        self.6.mark_success(url);
318    }
319
320    fn mark_failure(&mut self, url: &Url) {
321        self.0.mark_failure(url);
322        self.1.mark_failure(url);
323        self.2.mark_failure(url);
324        self.3.mark_failure(url);
325        self.4.mark_failure(url);
326        self.5.mark_failure(url);
327        self.6.mark_failure(url);
328    }
329}