amiya/context.rs
1use {
2 crate::{Middleware, Request, Response, Result},
3 http_types::Body,
4 std::{borrow::Cow, collections::HashMap, sync::Arc},
5};
6
7/// The context middleware works on.
8#[allow(missing_debug_implementations)]
9pub struct Context<'x, Ex> {
10 /// The incoming http request, without body. You can use [`Context::body`] method to get body.
11 ///
12 /// [`Context::body`]: #method.body
13 pub req: &'x Request,
14 /// The output http response, you can directly edit it
15 pub resp: &'x mut Response,
16 /// User defined extra data
17 pub ex: &'x mut Ex,
18 pub(crate) body: &'x mut Option<Body>,
19 pub(crate) remain_path: &'x str,
20 pub(crate) router_matches: &'x mut HashMap<Cow<'static, str>, String>,
21 pub(crate) tail: &'x [Arc<dyn Middleware<Ex>>],
22}
23
24impl<'x, Ex> Context<'x, Ex>
25where
26 Ex: Send + Sync + 'static,
27{
28 /// Run all inner middleware, this method drives the middleware system.
29 ///
30 /// Notice that you are **not must** call this func in all middleware. if you do not call it
31 /// inner middleware will simply not be executed.
32 ///
33 /// A second call to this method on the same instance will do nothing and directly returns a
34 /// `Ok(())`.
35 ///
36 /// ## Errors
37 ///
38 /// it returns inner middleware execute result.
39 pub async fn next(&mut self) -> Result {
40 if let Some((current, tail)) = self.tail.split_first() {
41 self.tail = tail;
42 let next_ctx = Context {
43 req: self.req,
44 body: self.body,
45 resp: self.resp,
46 ex: self.ex,
47 remain_path: self.remain_path,
48 router_matches: self.router_matches,
49 tail,
50 };
51 current.handle(next_ctx).await
52 } else {
53 Ok(())
54 }
55 }
56
57 /// Get incoming request body data. Only the first call will return `Some`.
58 pub fn body(&mut self) -> Option<Body> {
59 self.body.take()
60 }
61
62 /// The path the next router can match.
63 ///
64 /// It's differ from `Context.req.url().path()`, path returned by this method will only contains
65 /// sub paths that haven't matched by any [`Router`] middleware.
66 ///
67 /// See [`examples/router.rs`] for a example.
68 ///
69 /// [`Router`]: middleware/struct.Router.html
70 /// [`examples/router.rs`]: https://github.com/7sDream/amiya/blob/master/examples/router.rs
71 #[must_use]
72 pub fn path(&self) -> &str {
73 self.remain_path
74 }
75
76 /// The path argument of `name`.
77 ///
78 /// Will be set if a router's any item `{name}` is matched.
79 ///
80 /// See *[Router - Any Item]* for more detail.
81 ///
82 /// ## Examples
83 ///
84 /// See [`examples/arg.rs`] for a example.
85 ///
86 /// [Router - Any Item]: middleware/struct.Router.html#any-item
87 /// [`examples/arg.rs`]: https://github.com/7sDream/amiya/blob/master/examples/arg.rs
88 pub fn arg<K: AsRef<str>>(&self, name: K) -> Option<&str> {
89 self.router_matches.get(name.as_ref()).map(String::as_str)
90 }
91}