dce_router/
api.rs

1use std::any::Any;
2use std::cmp::Ordering;
3use std::collections::{BTreeSet, HashMap};
4use std::fmt::{Debug, Formatter};
5use crate::serializer::{Deserializer, Serializer};
6use crate::request::{Request, Context, Response};
7use dce_util::mixed::DceResult;
8#[cfg(feature = "async")]
9use std::future::Future;
10use std::ops::Deref;
11#[cfg(feature = "async")]
12use std::pin::Pin;
13#[cfg(feature = "async")]
14use async_trait::async_trait;
15use crate::protocol::RoutableProtocol;
16use crate::router::{PATH_PART_SEPARATOR, SUFFIX_BOUNDARY};
17
18
19const SUFFIX_SEPARATOR: char = '|';
20
21
22#[derive(Debug)]
23pub struct Api<Rp, ReqDto, RespDto>
24    where Rp: RoutableProtocol + Send + Sync + Debug + 'static,
25          ReqDto: 'static,
26          RespDto: 'static
27{
28    controller: Controller<Rp, ReqDto, RespDto>,
29    // 渲染器集,定义节点响应支持的渲染方式,如 apis `GET` 请求当后缀为`.html`时以HTTP渲染器渲染,当后缀为`.xml`时以XML渲染器渲染
30    /// Renderer vector, a response could to render by different way,
31    /// for example an `GET` request could render to html when url suffix is `.html`, or render to xml when url suffix is `.xml`
32    deserializers: Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>>,
33    serializers: Vec<Box<dyn Serializer<RespDto> + Send + Sync>>,
34    // `method` 用于定义当前节点支持的请求方式,如定义`Http`请求仅支持`["OPTION", "POST"]`
35    /// Define supported request methods for current Api, for example define the `Http` request only support `["OPTION", "POST"]` methods
36    method: Option<Box<dyn Method<Rp> + Send + Sync>>,
37    path: &'static str,
38    suffixes: BTreeSet<Suffix>,
39    id: &'static str,
40    omission: bool,
41    redirect: &'static str,
42    name: &'static str,
43    unresponsive: bool,
44    // 扩展属性,可用于定义如校验方式等通用节点配置
45    /// Extends properties, can be used to define general api configs such as verification methods
46    extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
47}
48
49impl<Rp, ReqDto, RespDto> Api<Rp, ReqDto, RespDto>
50    where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
51          ReqDto: 'static,
52          RespDto: 'static
53{
54    pub fn new(
55        controller: Controller<Rp, ReqDto, RespDto>,
56        deserializers: Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>>,
57        serializers: Vec<Box<dyn Serializer<RespDto> + Send + Sync>>,
58        method: Option<Box<dyn Method<Rp> + Send + Sync>>,
59        path: &'static str,
60        id: &'static str,
61        omission: bool,
62        redirect: &'static str,
63        name: &'static str,
64        unresponsive: bool,
65        extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
66    ) -> Self {
67        let mut path = path.trim_matches(PATH_PART_SEPARATOR);
68        let mut suffixes = BTreeSet::from([Suffix("")]);
69        if let Some(last_part_from) = path.rfind(PATH_PART_SEPARATOR).map_or_else(|| Some(0), |i| Some(i + 1)) {
70            let last_part = &path[last_part_from..];
71            if let Some(bound_index) = last_part.find(SUFFIX_BOUNDARY) {
72                suffixes = last_part[bound_index + 1 ..].split(SUFFIX_SEPARATOR).map(Suffix).collect();
73                path = &path[0.. last_part_from + bound_index];
74            }
75        }
76        Api { controller, deserializers, serializers, method, path, suffixes, id, omission, redirect, name, unresponsive, extras, }
77    }
78
79    pub fn controller(&self) -> &Controller<Rp, ReqDto, RespDto> {
80        &self.controller
81    }
82
83    pub fn deserializers(&self) -> &Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>> {
84        &self.deserializers
85    }
86
87    pub fn serializers(&self) -> &Vec<Box<dyn Serializer<RespDto> + Send + Sync>> {
88        &self.serializers
89    }
90}
91
92#[cfg_attr(feature = "async", async_trait)]
93pub trait ApiTrait<Rp: RoutableProtocol> {
94    fn method(&self) -> &Option<Box<dyn Method<Rp> + Send + Sync>>;
95    fn path(&self) -> &'static str;
96    fn suffixes(&self) -> &BTreeSet<Suffix>;
97    fn id(&self) -> &'static str;
98    fn omission(&self) -> bool;
99    fn redirect(&self) -> &'static str;
100    fn name(&self) -> &'static str;
101    fn unresponsive(&self) -> bool;
102    fn extras(&self) -> &HashMap<&'static str, Box<dyn Any + Send + Sync>>;
103    fn method_match(&self, rp: &Rp) -> bool;
104    #[cfg(feature = "async")]
105    async fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()>;
106    #[cfg(not(feature = "async"))]
107    fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()>;
108}
109
110#[cfg_attr(feature = "async", async_trait)]
111impl<Rp, ReqDto, RespDto> ApiTrait<Rp> for Api<Rp, ReqDto, RespDto>
112    where Rp: RoutableProtocol + Send + Sync + Debug + 'static,
113          ReqDto: 'static,
114          RespDto: 'static
115{
116    fn method(&self) -> &Option<Box<dyn Method<Rp> + Send + Sync>> {
117        &self.method
118    }
119
120    fn path(&self) -> &'static str {
121        self.path
122    }
123
124    fn suffixes(&self) -> &BTreeSet<Suffix> {
125        &self.suffixes
126    }
127
128    fn id(&self) -> &'static str {
129        self.id
130    }
131
132    fn omission(&self) -> bool {
133        self.omission
134    }
135
136    fn redirect(&self) -> &'static str {
137        self.redirect
138    }
139
140    fn name(&self) -> &'static str {
141        self.name
142    }
143
144    fn unresponsive(&self) -> bool {
145        self.unresponsive
146    }
147
148    fn extras(&self) -> &HashMap<&'static str, Box<dyn Any + Send + Sync>> {
149        &self.extras
150    }
151
152    fn method_match(&self, rp: &Rp) -> bool {
153        match &self.method {
154            Some(method) => method.req_match(rp),
155            _ => true
156        }
157    }
158
159    #[cfg(feature = "async")]
160    async fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()> {
161        if context.router().before_controller().is_some() {
162            match context.router().clone().before_controller() {
163                Some(EventHandler::Sync(func)) => func(context)?,
164                Some(EventHandler::Async(func)) => func(context).await?,
165                _ => {},
166            };
167        }
168        let req = Request::new(self, context);
169        *context.rp_mut().resp_mut() = match &self.controller {
170            Controller::Async(controller) => controller(req).await,
171            Controller::Sync(controller) => controller(req),
172        }?;
173        if context.router().after_controller().is_some() {
174            match context.router().clone().after_controller() {
175                Some(EventHandler::Sync(func)) => func(context)?,
176                Some(EventHandler::Async(func)) => func(context).await?,
177                _ => {},
178            };
179        }
180        Ok(())
181    }
182
183    #[cfg(not(feature = "async"))]
184    fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()> {
185        if context.router().before_controller().is_some() {
186            if let Some(EventHandler::Sync(func)) = context.router().clone().before_controller() { func(context)?; }
187        }
188        let req = Request::new(self, context);
189        let Controller::Sync(controller) = &self.controller;
190        *context.rp_mut().resp_mut() = controller(req)?;
191        if context.router().after_controller().is_some() {
192            if let Some(crate::api::EventHandler::Sync(func)) = context.router().clone().after_controller() { func(context)?; }
193        }
194        Ok(())
195    }
196}
197
198impl<Rp: RoutableProtocol> Debug for dyn ApiTrait<Rp> + Send + Sync + 'static {
199    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
200        f.write_str(format!(r#"Api{{method: {:?}, path: "{}", suffixes: {:?}, id: "{}", omission: {}, redirect: "{}", name: "{}", unresponsive: {}, extras: {:?}}}"#,
201                            self.method(), self.path(), self.suffixes(), self.id(), self.omission(), self.redirect(), self.name(), self.unresponsive(), self.extras()).as_str())
202    }
203}
204
205
206#[derive(Debug, Clone, Eq, PartialEq)]
207pub struct Suffix(&'static str);
208
209impl Deref for Suffix {
210    type Target = str;
211
212    fn deref(&self) -> &Self::Target {
213        self.0
214    }
215}
216
217impl PartialOrd<Self> for Suffix {
218    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
219        Some(self.cmp(other))
220    }
221}
222
223impl Ord for Suffix {
224    fn cmp(&self, other: &Self) -> Ordering {
225        let compound_diff = self.0.chars().filter(|c| SUFFIX_BOUNDARY.eq_ignore_ascii_case(c)).count() as isize
226            - other.0.chars().filter(|c| SUFFIX_BOUNDARY.eq_ignore_ascii_case(c)).count() as isize;
227        // put complex suffix front, and simple back
228        if compound_diff > 0 {
229            return Ordering::Less;
230        } else if compound_diff < 0 {
231            return Ordering::Greater;
232        }
233        self.0.cmp(other.0)
234    }
235}
236
237
238pub trait Method<Rp> {
239    fn to_string(&self) -> String;
240    fn req_match(&self, raw: &Rp) -> bool;
241}
242
243impl<Rp> Debug for dyn Method<Rp> + Send + Sync + 'static {
244    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245        f.write_str(self.to_string().as_str())
246    }
247}
248
249
250pub enum Controller<Rp, ReqDto, RespDto>
251    where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
252          ReqDto: 'static,
253          RespDto: 'static {
254    Sync(fn(Request<'_, Rp, ReqDto, RespDto>) -> DceResult<Option<Response<Rp::Resp>>>),
255    #[cfg(feature = "async")]
256    Async(Box<dyn Fn(Request<'_, Rp, ReqDto, RespDto>) -> Pin<Box<dyn Future<Output = DceResult<Option<Response<Rp::Resp>>>> + Send + '_>> + Send + Sync>),
257}
258
259impl<Rp, ReqDto, RespDto> Debug for Controller<Rp, ReqDto, RespDto>
260    where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
261          ReqDto: 'static,
262          RespDto: 'static {
263    fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
264        formatter.write_str(format!("{} controller", match &self {
265            Controller::Sync(_) => "A sync",
266            #[cfg(feature = "async")]
267            _ => "An async"
268        }).as_str())
269    }
270}
271
272
273pub enum EventHandler<Rp: RoutableProtocol + 'static> {
274    Sync(fn(&mut Context<Rp>) -> DceResult<()>),
275    #[cfg(feature = "async")]
276    Async(Box<dyn for <'a> Fn(&'a mut Context<Rp>) -> Pin<Box<dyn Future<Output = DceResult<()>> + Send + 'a>> + Send + Sync>),
277}
278
279impl<Rp: RoutableProtocol + 'static> Debug for EventHandler<Rp> {
280    fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
281        formatter.write_str(format!("{} function", match &self {
282            EventHandler::Sync(_) => "A sync",
283            #[cfg(feature = "async")]
284            _ => "An async"
285        }).as_str())
286    }
287}