dce_router/
protocol.rs

1use std::fmt::Debug;
2use dce_util::mixed::{DceErr, DceResult};
3use crate::request::{Context, Response};
4use crate::serializer::{Deserializer, Serializable, Serialized, Serializer};
5use log::{error, warn};
6use std::any::Any;
7use std::collections::HashMap;
8use std::ops::{Deref, DerefMut};
9use std::sync::Arc;
10use crate::api::{ApiTrait, Method};
11use crate::router::{CODE_NOT_FOUND, Router};
12#[cfg(feature = "async")]
13use async_trait::async_trait;
14
15
16pub const HEAD_PATH_NAME: &'static str = "$#path#";
17pub const HEAD_ID_NAME: &'static str = "$#id#";
18#[cfg(feature = "session")]
19pub const HEAD_SID_NAME: &'static str = "Session-Id";
20
21
22#[derive(Debug)]
23pub struct Meta<Req, Resp> {
24    req: Option<Req>,
25    resp: Option<Response<Resp>>,
26    heads: HashMap<String, String>,
27    resp_heads: HashMap<String, String>,
28}
29
30impl<Req, Resp> Meta<Req, Resp> {
31    pub fn new(req: Req, heads: HashMap<String, String>) -> Self {
32        Self { req: Some(req), resp: None, heads, resp_heads: Default::default() }
33    }
34    
35    pub fn req(&self) -> DceResult<&Req> {
36        self.req.as_ref().ok_or_else(|| DceErr::closed0("Invalid empty request"))
37    }
38    
39    pub fn req_mut(&mut self) -> &mut Option<Req> {
40        &mut self.req
41    }
42    
43    pub fn resp_mut(&mut self) -> &mut Option<Response<Resp>> {
44        &mut self.resp
45    }
46    
47    pub fn heads(&self) -> &HashMap<String, String> {
48        &self.heads
49    }
50    
51    pub fn resp_heads(&self) -> &HashMap<String, String> {
52        &self.resp_heads
53    }
54    
55    pub fn resp_heads_mut(&mut self) -> &mut HashMap<String, String> {
56        &mut self.resp_heads
57    }
58}
59
60
61#[cfg_attr(feature = "async", async_trait)]
62pub trait RoutableProtocol: From<Self::Req> + Into<Self::Resp> + Deref<Target = Meta<Self::Req, Self::Resp>> + DerefMut + Debug {
63    type Req;
64    type Resp: Debug;
65
66    #[cfg(feature = "async")]
67    async fn body(&mut self) -> DceResult<Serialized>;
68    #[cfg(not(feature = "async"))]
69    fn body(&mut self) -> DceResult<Serialized>;
70    fn pack_resp(&self, serialized: Serialized) -> Self::Resp;
71
72    fn path(&self) -> &str {
73        self.heads.get(HEAD_PATH_NAME).map_or("", |v| v.as_str())
74    }
75
76    fn id(&self) -> Option<&str> {
77        self.heads.get(HEAD_ID_NAME).map(|v| v.as_str())
78    }
79
80    #[cfg(feature = "async")]
81    async fn handle(self, router: Arc<Router<Self>>, context_data: HashMap<String, Box<dyn Any + Send>>) -> Option<Self::Resp> {
82        let mut context = Context::new(router, self, context_data);
83        let result = Router::route(&mut context).await;
84        context.take_rp()?.handle_result(result, &mut context)
85    }
86
87    #[cfg(not(feature = "async"))]
88    fn handle(self, router: Arc<Router<Self>>, context_data: HashMap<String, Box<dyn Any + Send>>) -> Option<Self::Resp> {
89        let mut context = Context::new(router, self, context_data);
90        let result = Router::route(&mut context);
91        context.take_rp()?.handle_result(result, &mut context)
92    }
93
94    fn api_match(&self, apis: &[&'static (dyn ApiTrait<Self> + Send + Sync)]) -> DceResult<&'static (dyn ApiTrait<Self> + Send + Sync)> {
95        apis.iter().find(|n| n.method_match(self)).map(|a| *a)
96            .ok_or_else(|| DceErr::openly(CODE_NOT_FOUND, format!(r#"Path "{}" cannot match any Api by Method"#, self.path())))
97    }
98
99    fn deserializer<'a, ReqDto>(deserializers: &'a [Box<dyn Deserializer<ReqDto> + Send + Sync>], _context: &Context<Self>) -> DceResult<&'a Box<dyn Deserializer<ReqDto> + Send + Sync>> {
100        deserializers.first().ok_or_else(|| DceErr::closed0("No deserializer configured"))
101    }
102
103    fn serializer<'a, RespDto>(serializers: &'a [Box<dyn Serializer<RespDto> + Send + Sync>], _context: &Context<Self>) -> DceResult<&'a Box<dyn Serializer<RespDto> + Send + Sync>> {
104        serializers.last().ok_or_else(|| DceErr::closed0("No serializer configured"))
105    }
106
107    fn deserialize<ReqDto>(serializers: &[Box<dyn Deserializer<ReqDto> + Send + Sync>], seq: Serialized, context: &Context<Self>) -> DceResult<ReqDto> {
108        Self::deserializer(serializers, context)?.deserialize(seq)
109    }
110
111    fn serialize<RespDto>(serializers: &[Box<dyn Serializer<RespDto> + Send + Sync>], dto: Serializable<RespDto>, context: &Context<Self>) -> DceResult<Serialized> {
112        Self::serializer(serializers, context)?.serialize(dto)
113    }
114
115    fn pack_responsible<RespDto: 'static>(
116        context: &Context<Self>,
117        serializers: &[Box<dyn Serializer<RespDto> + Send + Sync>],
118        responsible: Serializable<RespDto>,
119    ) -> DceResult<Option<Response<Self::Resp>>> {
120        Self::serialize(serializers, responsible, &context).map(|sd| Some(Response::Serialized(sd)))
121    }
122
123    // Parse the "method" object and "extras" properties of Api. Protocol developers can implement the "parse_api_method" method in the protocol implementation 
124    // and delete the prop_tuples member that has been parsed into the Method. The remaining members will be used as extras Map members
125    fn parse_api_method_and_extras(prop_tuples: Vec<(&'static str, Box<dyn Any + Send + Sync>)>) -> (Option<Box<dyn Method<Self> + Send + Sync>>, HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
126        let mut prop_mapping: HashMap<_, _> = prop_tuples.into_iter().collect();
127        (Self::parse_api_method(&mut prop_mapping), prop_mapping)
128    }
129
130    // Protocol developers could override implement this method and should remove the parsed prop_tuples member
131    fn parse_api_method(_prop_mapping: &mut HashMap<&'static str, Box<dyn Any + Send + Sync>>) -> Option<Box<dyn Method<Self> + Send + Sync>> {
132        None
133    }
134
135    fn try_print_err(response: &DceResult<()>) {
136        if let Err(error) = response {
137            match error {
138                DceErr::Openly(err) => warn!("code {}, {}", err.code, err.message),
139                DceErr::Closed(err) => error!("code {}, {}", err.code, err.message),
140            };
141        }
142    }
143
144    fn err_into(mut self, err: DceErr) -> Self::Resp {
145        self.resp = Some(Response::Raw(self.pack_resp(Serialized::String(err.to_responsible()))));
146        self.into()
147    }
148
149    fn handle_result(self, result: DceResult<()>, context: &mut Context<Self>) -> Option<Self::Resp> {
150        Self::try_print_err(&result);
151        if ! context.api().map_or_else(|| self.id().is_none(), |a| a.unresponsive()) {
152            return Some(match result {
153                Ok(_) => self.into(),
154                Err(err) => self.err_into(err),
155            });
156        }
157        None
158    }
159
160    #[cfg(feature = "session")]
161    fn sid(&self) -> Option<&str> {
162        self.heads.get(HEAD_SID_NAME).map(String::as_str)
163    }
164
165    #[cfg(feature = "session")]
166    fn set_resp_sid(&mut self, sid: String) {
167        self.resp_heads.insert(HEAD_SID_NAME.to_string(), sid);
168    }
169
170    #[cfg(feature = "session")]
171    fn get_resp_sid(&mut self) -> Option<&String> {
172        self.resp_heads.get(HEAD_SID_NAME)
173    }
174
175    #[cfg(feature = "session")]
176    fn set_session<Rp: RoutableProtocol + Debug + 'static>(context: &mut Context<Rp>, value: Box<dyn Any + Send>) {
177        context.put_data("$#session#".to_string(), value);
178    }
179
180    #[cfg(feature = "session")]
181    fn session<S: 'static, Rp: RoutableProtocol + Debug + 'static>(context: &mut Context<Rp>) -> DceResult<&mut S> {
182        context.get_as_mut("$#session#")
183    }
184}