Skip to main content

spire_core/worker/
mod.rs

1//! Workers, which handle fetched requests, their [`Outcome`]s, and the
2//! [`middleware`].
3
4pub mod middleware;
5mod outcome;
6
7use std::fmt;
8use std::future::Future;
9
10pub use middleware::WorkerExt;
11pub use outcome::{IntoOutcome, Outcome, Scope};
12
13use crate::context::Context;
14
15/// Handles one request of a crawl.
16///
17/// The worker receives a [`Context`] holding the request and a client for
18/// it. It decides when, and whether, to fetch the response, may queue
19/// further requests, and tells the crawler what to do next.
20pub trait Worker<C>: Send + Sync + 'static {
21    /// Handles the request in `cx`.
22    fn handle(&self, cx: Context<C>) -> impl Future<Output = Outcome> + Send;
23}
24
25/// Creates a [`Worker`] from an async function.
26///
27/// # Examples
28///
29/// ```
30/// use spire_core::backend::Noop;
31/// use spire_core::worker::from_fn;
32/// use spire_core::{Context, Result};
33///
34/// async fn handle(cx: Context<Noop>) -> Result<()> {
35///     let response = cx.response().await?;
36///     println!("status: {}", response.status());
37///     Ok(())
38/// }
39///
40/// let worker = from_fn(handle);
41/// ```
42pub const fn from_fn<F>(f: F) -> FromFn<F> {
43    FromFn(f)
44}
45
46/// A [`Worker`] backed by an async function, created by [`from_fn`].
47#[derive(Clone, Copy)]
48pub struct FromFn<F>(F);
49
50impl<C, F, Fut> Worker<C> for FromFn<F>
51where
52    C: Send + 'static,
53    F: Fn(Context<C>) -> Fut + Send + Sync + 'static,
54    Fut: Future<Output: IntoOutcome> + Send,
55{
56    fn handle(&self, cx: Context<C>) -> impl Future<Output = Outcome> + Send {
57        let future = (self.0)(cx);
58        async move { future.await.into_outcome() }
59    }
60}
61
62impl<F> fmt::Debug for FromFn<F> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.debug_struct("FromFn").finish_non_exhaustive()
65    }
66}