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}