Skip to main content

millipede_core/
handler.rs

1//! Request handler and middleware contracts.
2
3use std::future::Future;
4use std::sync::Arc;
5
6use futures_util::future::BoxFuture;
7
8use crate::errors::CrawlError;
9use crate::request::Request;
10
11/// Processes an owned request context.
12pub trait RequestHandler<C>: Send + Sync + 'static {
13    /// Processes `ctx` and returns its eventual outcome.
14    fn handle(&self, ctx: C) -> BoxFuture<'static, Result<(), CrawlError>>;
15}
16
17impl<C, F, Fut> RequestHandler<C> for F
18where
19    F: Fn(C) -> Fut + Send + Sync + 'static,
20    Fut: Future<Output = Result<(), CrawlError>> + Send + 'static,
21{
22    fn handle(&self, ctx: C) -> BoxFuture<'static, Result<(), CrawlError>> {
23        Box::pin((self)(ctx))
24    }
25}
26
27/// Transforms a request context before its matched handler runs.
28pub trait Middleware<C>: Send + Sync + 'static {
29    /// Runs before the matched handler; receives the context by value and returns it (possibly
30    /// mutated). An error short-circuits the request.
31    fn run(&self, ctx: C) -> BoxFuture<'static, Result<C, CrawlError>>;
32}
33
34impl<C, F, Fut> Middleware<C> for F
35where
36    F: Fn(C) -> Fut + Send + Sync + 'static,
37    Fut: Future<Output = Result<C, CrawlError>> + Send + 'static,
38{
39    fn run(&self, ctx: C) -> BoxFuture<'static, Result<C, CrawlError>> {
40        Box::pin((self)(ctx))
41    }
42}
43
44/// Owned payload handed to the failure handler when a request permanently fails.
45#[derive(Debug, Clone)]
46#[non_exhaustive]
47pub struct FailedRequestContext {
48    /// The request that permanently failed.
49    pub request: Arc<Request>,
50    /// The final error produced while processing the request.
51    pub error: Arc<CrawlError>,
52    /// The number of retry attempts made before the permanent failure.
53    pub retry_count: u32,
54}
55
56impl FailedRequestContext {
57    /// Creates a failure-handler context.
58    pub fn new(request: Arc<Request>, error: Arc<CrawlError>, retry_count: u32) -> Self {
59        Self {
60            request,
61            error,
62            retry_count,
63        }
64    }
65}
66
67/// Handles a request after it has permanently failed.
68pub trait FailedRequestHandler: Send + Sync + 'static {
69    /// Processes a permanently failed request.
70    fn handle(&self, ctx: FailedRequestContext) -> BoxFuture<'static, Result<(), CrawlError>>;
71}
72
73impl<F, Fut> FailedRequestHandler for F
74where
75    F: Fn(FailedRequestContext) -> Fut + Send + Sync + 'static,
76    Fut: Future<Output = Result<(), CrawlError>> + Send + 'static,
77{
78    fn handle(&self, ctx: FailedRequestContext) -> BoxFuture<'static, Result<(), CrawlError>> {
79        Box::pin((self)(ctx))
80    }
81}