-
Notifications
You must be signed in to change notification settings - Fork 327
Expand file tree
/
Copy pathmiddleware.rs
More file actions
127 lines (106 loc) · 3.56 KB
/
middleware.rs
File metadata and controls
127 lines (106 loc) · 3.56 KB
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tide::http::mime;
use tide::utils::{After, Before};
use tide::{Middleware, Next, Request, Response, Result, StatusCode};
#[derive(Debug)]
struct User {
name: String,
}
#[derive(Clone, Default, Debug)]
struct UserDatabase;
impl UserDatabase {
async fn find_user(&self) -> Option<User> {
Some(User {
name: "nori".into(),
})
}
}
// This is an example of a function middleware that uses the
// application state. Because it depends on a specific request state,
// it would likely be closely tied to a specific application
async fn user_loader(mut request: Request, next: Next) -> Result {
if let Some(user) = request.state::<UserDatabase>().find_user().await {
tide::log::trace!("user loaded", {user: user.name});
request.set_ext(user);
Ok(next.run(request).await)
// this middleware only needs to run before the endpoint, so
// it just passes through the result of Next
} else {
// do not run endpoints, we could not find a user
Ok(Response::new(StatusCode::Unauthorized))
}
}
// This is an example of middleware that keeps its own state and could
// be provided as a third party crate
#[derive(Default)]
struct RequestCounterMiddleware {
requests_counted: Arc<AtomicUsize>,
}
impl RequestCounterMiddleware {
fn new(start: usize) -> Self {
Self {
requests_counted: Arc::new(AtomicUsize::new(start)),
}
}
}
struct RequestCount(usize);
#[tide::utils::async_trait]
impl Middleware for RequestCounterMiddleware {
async fn handle(&self, mut req: Request, next: Next) -> Result {
let count = self.requests_counted.fetch_add(1, Ordering::Relaxed);
tide::log::trace!("request counter", { count: count });
req.set_ext(RequestCount(count));
let mut res = next.run(req).await;
res.insert_header("request-number", count.to_string());
Ok(res)
}
}
const NOT_FOUND_HTML_PAGE: &str = "<html><body>
<h1>uh oh, we couldn't find that document</h1>
<p>
probably, this would be served from the file system or
included with `include_bytes!`
</p>
</body></html>";
const INTERNAL_SERVER_ERROR_HTML_PAGE: &str = "<html><body>
<h1>whoops! it's not you, it's us</h1>
<p>
we're very sorry, but something seems to have gone wrong on our end
</p>
</body></html>";
#[async_std::main]
async fn main() -> Result<()> {
// tide::log::start();
let mut app = tide::with_state(UserDatabase::default());
app.with(After(|response: Response| async move {
let response = match response.status() {
StatusCode::NotFound => Response::builder(404)
.content_type(mime::HTML)
.body(NOT_FOUND_HTML_PAGE)
.build(),
StatusCode::InternalServerError => Response::builder(500)
.content_type(mime::HTML)
.body(INTERNAL_SERVER_ERROR_HTML_PAGE)
.build(),
_ => response,
};
Ok(response)
}));
app.with(user_loader);
app.with(RequestCounterMiddleware::new(0));
app.with(Before(|mut request: Request| async move {
request.set_ext(std::time::Instant::now());
request
}));
app.at("/").get(|req: Request| async move {
let count: &RequestCount = req.ext().unwrap();
let user: &User = req.ext().unwrap();
Ok(format!(
"Hello {}, this was request number {}!",
user.name, count.0
))
});
app.listen("127.0.0.1:8080").await?;
Ok(())
}