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}