Skip to main content

dce_router/
api.rs

1use std::{any::Any, collections::HashMap, future::Future, ops::{BitAnd, BitOr}, pin::Pin};
2
3use dce_util::result::{DceResult, DceVoid, OK_VOID};
4
5use crate::{context::{Context, Request}, protocol::RoutableProtocol, router::RouteMatch};
6
7pub const MARK_PATH_PART_SEPARATOR: &str     = "/";
8pub const MARK_SUFFIX_SEPARATOR: &str       = "|";
9pub const MARK_SUFFIX_BOUNDARY: &str        = ".";
10pub const MARK_VARIABLE_OPENER: &str        = "{";
11pub const MARK_VARIABLE_CLOSING: &str       = "}";
12pub const MARK_VAR_TYPE_OPTIONAL: &str       = "?";
13pub const MARK_VAR_TYPE_EMPTABLE_VECTOR: &str = "*";
14pub const MARK_VAR_TYPE_VECTOR: &str         = "+";
15const EXTRA_SERVE_ADDR_KEY: &str = "$#BIND-HOSTS#";
16
17pub struct Api<Rp: RoutableProtocol + 'static> {
18    pub methods: Methods,
19    pub path: &'static str,
20    pub suffixes: Vec<Suffix>,
21    pub id: Option<&'static str>,
22    pub omission: bool,
23    pub responsive: bool,
24    pub redirect: Option<&'static str>,
25    pub name: &'static str,
26    pub extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
27    pub handler: Option<Handler<Rp>>,
28}
29
30impl<Rp: RoutableProtocol + 'static> Api<Rp> {
31    pub fn by_methods(mut self, methods: Methods) -> Self {
32        self.methods = methods;
33        self
34    }
35
36    pub fn by_id(mut self, id: &'static str) -> Self {
37        self.id = Some(id);
38        self
39    }
40
41    pub fn as_omission(mut self) -> Self {
42        self.omission = true;
43        self
44    }
45
46    pub fn as_responsive(mut self) -> Self {
47        self.responsive = true;
48        self
49    }
50
51    pub fn as_unresponsive(mut self) -> Self {
52        self.responsive = false;
53        self
54    }
55
56    pub fn by_redirect(mut self, redirect: &'static str) -> Self {
57        self.redirect = Some(redirect);
58        self
59    }
60
61    pub fn by_name(mut self, name: &'static str) -> Self {
62        self.name = name;
63        self
64    }
65
66    pub fn with(mut self, key: &'static str, val: Box<dyn Any + Send + Sync>) -> Self {
67        self.extras.insert(key, val);
68        self
69    }
70
71    pub fn append(mut self, key: &'static str, mut items: Vec<Box<dyn Any + Send + Sync>>) -> Self {
72        if !self.extras.contains_key(key) {
73            self.extras.insert(key, Box::new(items));
74        } else if let Some(val) = self.extras.get_mut(key) {
75            if let Some(exists) = val.downcast_mut::<Vec<Box<dyn Any + Send + Sync>>>() {
76                exists.append(&mut items);
77            } else {
78		        panic!(r#"Api with path "{}" was already has an extra keyd by "{}", but is not a vector value."#, self.path, key);
79            }
80        }
81        self
82    }
83
84    pub fn extra_by(&self, key: &str) -> Option<&Box<dyn Any + Send + Sync>> {
85        self.extras.get(key)
86    }
87
88    pub fn extras_by(&self, key: &str) -> Option<&Vec<Box<dyn Any + Send + Sync>>> {
89        self.extras.get(key).map(|v| v.downcast_ref::<Vec<Box<dyn Any + Send + Sync>>>()).flatten()
90    }
91
92    pub fn bind_hosts(self, hosts: Vec<String>) -> Self {
93        self.append(EXTRA_SERVE_ADDR_KEY, hosts.into_iter().map(|h| Box::new(h) as Box<dyn Any + Send + Sync>).collect::<Vec<_>>())
94    }
95
96    pub fn hosts(&self) -> Vec<&str> {
97        self.extras_by(EXTRA_SERVE_ADDR_KEY).map_or_else(|| vec![], |vs| vs.iter()
98            .filter_map(|v| v.downcast_ref::<String>().map(|s| s.as_str())).collect::<Vec<_>>())
99    }
100
101    pub fn bind_handler(mut self, handler: Handler<Rp>) -> Self {
102        self.handler = Some(handler);
103        self
104    }
105
106    pub fn upgrade(mut self) -> Self {
107        if self.suffixes.len() > 0 {
108            panic!(r#"Please define the suffixes in the end of "Path" but not defined directly"#)
109        }
110        let last_part_from = self.path.rfind(MARK_PATH_PART_SEPARATOR)
111            .map(|i| i + MARK_PATH_PART_SEPARATOR.len()).unwrap_or(0);
112        if let Some(bound_index) = self.path[last_part_from..].find(MARK_SUFFIX_BOUNDARY) {
113            self.suffixes = self.path[last_part_from + bound_index + MARK_SUFFIX_BOUNDARY.len() ..]
114                .split(MARK_SUFFIX_SEPARATOR).map(|s| Suffix(s)).collect();
115            self.path = &self.path[..last_part_from+bound_index];
116        } else {
117            self.suffixes = vec![Suffix("")];
118        }
119        if self.path.starts_with(MARK_PATH_PART_SEPARATOR) {
120		    panic!(r#"Api.Path "{}" cannot be start with "{}""#, MARK_PATH_PART_SEPARATOR, self.path)
121        }
122        self
123    }
124
125    pub fn new(path: &'static str) -> Self {
126        Self::new_with(path, Methods(0), vec![], false, None, true, None, "", Default::default(), None)
127    }
128
129    pub fn new_with(
130        path: &'static str,
131        methods: Methods,
132        suffixes: Vec<Suffix>,
133        omission: bool,
134        id: Option<&'static str>,
135        responsive: bool,
136        redirect: Option<&'static str>,
137        name: &'static str,
138        extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
139        handler: Option<Handler<Rp>>,
140    ) -> Self {
141        Self { path, responsive, methods, suffixes, id, omission, redirect, name, extras, handler, }
142    }
143}
144
145impl<Rp: RoutableProtocol + 'static> Api<Rp> {
146    pub fn sync_handle(&self, ctx: &mut Context<Rp>, routed: RouteMatch<'_, Rp>) -> DceVoid {
147        if let Some(Hook::Sync(hook)) = routed.pre_hook {
148            hook(ctx)?
149        }
150        if let Some(Handler::Sync(handler)) = &self.handler {
151            handler(Request::new(ctx))?;
152        }
153        if let Some(Hook::Sync(hook)) = routed.post_hook {
154            hook(ctx)?
155        }
156        OK_VOID
157    }
158
159    pub async fn handle(&self, ctx: &mut Context<Rp>, routed: RouteMatch<'_, Rp>) -> DceVoid {
160        if let Some(pre_hook) = routed.pre_hook {            
161            match pre_hook {
162                Hook::Async(hook) => hook(ctx).await?,
163                Hook::Sync(hook) => hook(ctx)?,
164            };
165        }
166        if let Some(handler) = &self.handler {
167            let req = Request::new(ctx);
168            match handler {
169                Handler::Async(handler) => handler(req).await?,
170                Handler::Sync(handler) => handler(req)?,
171            };
172        }
173        if let Some(post_hook) = routed.post_hook {            
174            match post_hook {
175                Hook::Async(hook) => hook(ctx).await?,
176                Hook::Sync(hook) => hook(ctx)?,
177            };
178        }
179        OK_VOID
180    }
181}
182
183pub enum Handler<Rp: RoutableProtocol + 'static> {
184    Sync(for<'a> fn(Request<'a, Rp>) -> DceResult<()>),
185    Async(Box<dyn for<'a> Fn(Request<'a, Rp>) -> Pin<Box<dyn Future<Output = DceResult<()>> + Send + 'a>> + Send + Sync>),
186}
187
188pub enum Hook<Rp: RoutableProtocol + 'static> {
189    Sync(for<'a> fn(&'a mut Context<Rp>) -> DceResult<()>),
190    Async(Box<dyn for<'a> Fn(&'a mut Context<Rp>) -> Pin<Box<dyn Future<Output = DceResult<()>> + Send + 'a>> + Send + Sync>),
191}
192
193
194#[derive(Clone, Eq, PartialEq, Hash, Debug)]
195pub struct Suffix(pub &'static str);
196
197impl AsRef<str> for Suffix {
198    fn as_ref(&self) -> &str {
199        self.0
200    }
201}
202
203#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
204pub struct Methods(pub u16);
205
206impl BitOr for Methods {
207    type Output = Self;
208
209    fn bitor(self, rhs: Self) -> Self::Output {
210        Self(self.0 | rhs.0)
211    }
212}
213
214impl BitAnd for Methods {
215    type Output = Self;
216
217    fn bitand(self, rhs: Self) -> Self::Output {
218        Self(self.0 & rhs.0)
219    }
220}