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
//! Middleware is code that runs before and after the routes.
//! They can be used to Log Requests, Ratelimit Requests, add Analytics, etc.
//! For more information, see the [Middleware Example](https://github.com/Basicprogrammer10/afire/blob/main/examples/basic/middleware.rs).

use std::{any::type_name, rc::Rc};

use crate::{error::Result, trace::emoji, Request, Response, Server};

/// A response from a middleware handler
pub enum MiddleResult {
    /// Continue to the next middleware
    Continue,
    /// Stop the middleware chain
    Abort,
    /// Stop the middleware chain and send this response
    Send(Response),
}

/// Trait used to implement Middleware, which is code that runs before and after the routes - potentially modifying the request and response.
/// You can use Middleware to Log Requests, Ratelimit Requests, add Analytics, etc.
///
/// There are two types of hooks: raw and non-raw.
/// The raw hooks are passed a [`Result`], and their default implementation calls the non-raw hooks if the Result is Ok.
/// This allows you to handle errors (like page not found), while maintaining a clean API for middleware that doesn't need to handle errors.
///
/// ## Hooks
/// - [`Middleware::pre_raw`]
/// - [`Middleware::pre`]
/// - [`Middleware::post_raw`]
/// - [`Middleware::post`]
/// - [`Middleware::end_raw`]
/// - [`Middleware::end`]
///
pub trait Middleware {
    /// Middleware to run before routes.
    /// Because this is the `raw` version of [`Middleware::pre`], it is passed a [`Result`].
    /// The default implementation calls [`Middleware::pre`] if the [`Result`] is [`Ok`].
    fn pre_raw(&self, req: &mut Result<Request>) -> MiddleResult {
        if let Ok(req) = req {
            return self.pre(req);
        }
        MiddleResult::Continue
    }

    /// Middleware to run Before Routes
    fn pre(&self, _req: &mut Request) -> MiddleResult {
        MiddleResult::Continue
    }

    /// Middleware to run after routes.
    /// Because this is the `raw` version of [`Middleware::post`], it is passed a [`Result`].
    /// The default implementation calls [`Middleware::post`] if the [`Result`] is [`Ok`].
    fn post_raw(&self, req: Result<Rc<Request>>, res: &mut Result<Response>) -> MiddleResult {
        if let (Ok(req), Ok(res)) = (req, res) {
            return self.post(&req, res);
        }
        MiddleResult::Continue
    }

    /// Middleware to run After Routes
    fn post(&self, _req: &Request, _res: &mut Response) -> MiddleResult {
        MiddleResult::Continue
    }

    /// Middleware to run after the response has been handled.
    /// Because this is the `raw` version of [`Middleware::end`], it is passed a [`Result`].
    /// The default implementation calls [`Middleware::end`] if the [`Result`] is [`Ok`].
    fn end_raw(&self, req: &Result<Request>, res: &Result<Response>) {
        if let (Ok(req), Ok(res)) = (req, res) {
            self.end(req, res);
        }
    }

    /// Middleware ot run after the response has been handled
    fn end(&self, _req: &Request, _res: &Response) {}

    /// Attach Middleware to a Server.
    /// If you want to get a reference to the server's state in your middleware state, you should override this method.
    fn attach<State>(self, server: &mut Server<State>)
    where
        Self: 'static + Send + Sync + Sized,
        State: 'static + Send + Sync,
    {
        trace!("{}Adding Middleware {}", emoji("📦"), type_name::<Self>());

        server.middleware.push(Box::new(self));
    }
}