Skip to main content

bios_sdk_invoke/
clients.rs

1use std::fmt::Display;
2
3use serde::Serialize;
4use tardis::{
5    basic::{dto::TardisContext, error::TardisError, result::TardisResult},
6    web::{
7        poem_openapi::types::{ParseFromJSON, ToJSON},
8        web_client::TardisHttpResponse,
9        web_resp::TardisResp,
10    },
11    TardisFuns, TardisFunsInst,
12};
13
14use crate::invoke_constants::TARDIS_CONTEXT;
15
16#[cfg(feature = "spi_base")]
17pub mod base_spi_client;
18#[cfg(feature = "spi_kv")]
19pub mod spi_kv_client;
20#[cfg(feature = "spi_log")]
21pub mod spi_log_client;
22#[cfg(feature = "spi_search")]
23pub mod spi_search_client;
24#[cfg(feature = "spi_stats")]
25pub mod spi_stats_client;
26
27#[cfg(feature = "iam")]
28pub mod iam_client;
29
30#[cfg(feature = "event")]
31pub mod event_client;
32pub mod flow_client;
33
34#[macro_export]
35///
36///
37/// # Usage
38/// as if `Client` is some type implemented trait `SimpleInvokeClient`
39/// ```no_run, ignore
40/// # pub struct Client<'a> {
41/// #     base_url: &'a str,
42/// #     ctx: &'a TardisContext,
43/// #     funs: &'a TardisFunsInst,
44/// # }
45/// #
46/// # impl<'a> Client<'a> {
47/// #     pub fn new(base_url: &'a str, ctx: &'a TardisContext, funs: &'a TardisFunsInst) -> Self {
48/// #         Self { base_url, funs, ctx }
49/// #     }
50/// # }
51/// #
52/// # impl SimpleInvokeClient for Client<'_> {
53/// #     const DOMAIN_CODE: &'static str = "crate::consts::DOMAIN_CODE";
54/// #
55/// #     fn get_ctx(&self) -> &tardis::basic::dto::TardisContext {
56/// #         self.ctx
57/// #     }
58/// #
59/// #     fn get_base_url(&self) -> &str {
60/// #         self.base_url
61/// #     }
62/// # }
63///
64/// impl_tardis_api_client!{
65///     Client<'_>:
66///     // <function_name>  <method>    <path>                                  <query> <response type>
67///     { my_get_method,    get         ["/path", patharg, "path2", patharg2]   {code}  String}
68///     //                                   query can be optional, if type not specified, it will be `&str`
69///     { paginate_msg_log, post ["/ct/msg"] {page_number?: u32, page_size?} ReachMessageAddReq => String }
70///     // query can omitted
71///     { add_message, post ["/ct/msg"] ReachMessageAddReq => String }
72///     { delete_test, delete ["/delete/some/msg"] String }
73/// }
74/// ```
75macro_rules! impl_tardis_api_client {
76    ($Client:ty: $({$($defs: tt)*})*) => {
77        impl $Client {
78            $(
79                $crate::tardis_api!{$($defs)*}
80            )*
81        }
82    }
83}
84
85#[macro_export]
86///
87///
88/// ```ignore,no_run
89/// tardis_api!{
90///     mail_pwd_send, put ["/cc/msg/mail", mail] {message, subject} () => ()
91/// }
92/// ```
93macro_rules! tardis_api {
94    /*
95       enter
96     */
97    ($fn_name:ident, $($tt:tt)*) => {
98        $crate::tardis_api!($fn_name @method $($tt)*);
99    };
100    /*
101        method
102     */
103    ($fn_name:ident @method $method:ident $($tt:tt)*) => {
104        $crate::tardis_api!($fn_name @path $method {} {} $($tt)*);
105    };
106    /*
107        path
108     */
109    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [] $($tt:tt)*) => {
110        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)*} {$($path,)*} {;} $($tt)*);
111    };
112    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next:ident, $($rest_path:tt)*] $($tt:tt)*) => {
113        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)* $next: &str,} {$($path,)* $next,} [$($rest_path)*] $($tt)*);
114    };
115    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next:ident $(,)?] $($tt:tt)*) => {
116        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)* $next: &str,} {$($path,)* $next,} [] $($tt)*);
117    };
118    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next:literal, $($rest_path:tt)*] $($tt:tt)*) => {
119        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)*} {$($path,)* $next,} [$($rest_path)*] $($tt)*);
120    };
121    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next:literal $(,)?] $($tt:tt)*) => {
122        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)*} {$($path,)* $next,} [] $($tt)*);
123    };
124    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next_ident:ident:$next_type:ty, $($rest_path:tt)*] $($tt:tt)*) => {
125        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)* $next_ident:$next_type,} {$($path,)* $next_ident.to_string().as_str(),} [$($rest_path)*] $($tt)*);
126    };
127    ($fn_name:ident @path $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} [$next_ident:ident:$next_type:ty $(,)?] $($tt:tt)*) => {
128        $crate::tardis_api!($fn_name @path $method {$($args_i:$args_t,)* $next_ident:$next_type,} {$($path,)* $next_ident.to_string().as_str(),} [] $($tt)*);
129    };
130    /*
131        query
132        fn_name @query method {args} {paths} {query1, query2, ; optional_query1, optional_query2} {rest_querys} tt
133     */
134    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {} $($tt:tt)*) => {
135        $crate::tardis_api!($fn_name @build $method {$($args_i:$args_t,)*} {$($path,)*} {$($query,)*;$($optional_query,)*} $($tt)*);
136    };
137    // for ident:type
138    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next_ident:ident:$next_type:ty, $($rest_query:tt)*} $($tt:tt)*) => {
139        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next_ident:$next_type,} {$($path,)*} {$($query,)* (stringify!($next_ident), $next_ident), ; $($optional_query,)*} {$($rest_query)*} $($tt)*);
140    };
141    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next_ident:ident:$next_type:ty $(,)?} $($tt:tt)*) => {
142        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next_ident:$next_type,} {$($path,)*} {$($query,)* (stringify!($next_ident), $next_ident), ; $($optional_query,)*} {} $($tt)*);
143    };
144    // for ident?:type
145    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next_ident:ident?:$next_type:ty, $($rest_query:tt)*} $($tt:tt)*) => {
146        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next_ident:Option<$next_type>,} {$($path,)*} {$($query,)* ; $($optional_query,)* (stringify!($next_ident),  $next_ident), } {$($rest_query)*} $($tt)*);
147    };
148    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next_ident:ident?:$next_type:ty $(,)?} $($tt:tt)*) => {
149        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next_ident:Option<$next_type>,} {$($path,)*} {$($query,)* ; $($optional_query,)* (stringify!($next_ident),  $next_ident), } {} $($tt)*);
150    };
151    // for ident
152    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next:ident $(,)?} $($tt:tt)*) => {
153        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next:&str, } {$($path,)*} {$($query,)* (stringify!($next), $next), ; $($optional_query,)*} {} $($tt)*);
154    };
155    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next:ident, $($rest_query:tt)*} $($tt:tt)*) => {
156        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next:&str, } {$($path,)*} {$($query,)* (stringify!($next), $next), ; $($optional_query,)*} {$($rest_query)*} $($tt)*);
157    };
158    // for ident?
159    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next:ident? $(,)?} $($tt:tt)*) => {
160        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next:Option<&str>, } {$($path,)*} {$($query,)* ; $($optional_query,)* (stringify!($next), $next), } {} $($tt)*);
161    };
162    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} {$next:ident?, $($rest_query:tt)*} $($tt:tt)*) => {
163        $crate::tardis_api!($fn_name @query $method {$($args_i:$args_t,)* $next:Option<&str>, } {$($path,)*} {$($query,)* ; $($optional_query,)* (stringify!($next), $next), } {$($rest_query)*} $($tt)*);
164    };
165    // no query args
166    ($fn_name:ident @query $method:ident {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {;} $($tt:tt)*) => {
167        $crate::tardis_api!($fn_name @build $method {$($args_i:$args_t,)*} {$($path,)*} {;} $($tt)*);
168    };
169    /*
170        build
171     */
172    ($fn_name:ident @build get {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} $Resp:ty) => {
173        #[allow(unused_mut)]
174        pub async fn $fn_name(&self, $($args_i:$args_t,)*) -> tardis::basic::result::TardisResult<$Resp> {
175            use $crate::clients::SimpleInvokeClient;
176            use tardis::web::web_resp::TardisResp;
177            let mut query = $crate::clients::QueryBuilder::new();
178            $(
179                {
180                    let q = $query;
181                    query.add(q.0, q.1);
182                }
183            )*
184            $(
185                {
186                    let q = $optional_query;
187                    query.add_optional(q.0, q.1);
188                }
189            )*
190            let url = self.get_url(&[$($path,)*], query.as_ref());
191            let header = self.get_tardis_context_header()?;
192            let resp = self.get_funs().web_client().get::<TardisResp<$Resp>>(&url, vec![header]).await?;
193            Self::extract_response(resp)
194        }
195    };
196    ($fn_name:ident @build post {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} $Body:ty => $Resp:ty) => {
197        #[allow(unused_mut)]
198        pub async fn $fn_name(&self, $($args_i:$args_t,)* body: &$Body) -> tardis::basic::result::TardisResult<$Resp> {
199            use $crate::clients::SimpleInvokeClient;
200            use tardis::web::web_resp::TardisResp;
201            let mut query = $crate::clients::QueryBuilder::new();
202            $(
203                {
204                    let q = $query;
205                    query.add(q.0, q.1);
206                }
207            )*
208            $(
209                {
210                    let q = $optional_query;
211                    query.add_optional(q.0, q.1);
212                }
213            )*
214            let url = self.get_url(&[$($path,)*], query.as_ref());
215            let header = self.get_tardis_context_header()?;
216            let resp = self.get_funs().web_client().post::<$Body, TardisResp<$Resp>>(&url, body, vec![header]).await?;
217            Self::extract_response(resp)
218        }
219    };
220    ($fn_name:ident @build put {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} $Body:ty => $Resp:ty) => {
221        #[allow(unused_mut)]
222        pub async fn $fn_name(&self, $($args_i:$args_t,)* body: &$Body) -> tardis::basic::result::TardisResult<$Resp> {
223            use $crate::clients::SimpleInvokeClient;
224            use tardis::web::web_resp::TardisResp;
225            let mut query = $crate::clients::QueryBuilder::new();
226            $(
227                {
228                    let q = $query;
229                    query.add(q.0, q.1);
230                }
231            )*
232            $(
233                {
234                    let q = $optional_query;
235                    query.add_optional(q.0, q.1);
236                }
237            )*
238            let url = self.get_url(&[$($path,)*], query.as_ref());
239            let header = self.get_tardis_context_header()?;
240            let resp = self.get_funs().web_client().put::<$Body, TardisResp<$Resp>>(&url, body, vec![header]).await?;
241            Self::extract_response(resp)
242        }
243    };
244    ($fn_name:ident @build delete {$($args_i:ident:$args_t:ty,)*} {$($path:expr,)*} {$($query:expr,)*;$($optional_query:expr,)*} $Resp:ty) => {
245        #[allow(unused_mut)]
246        pub async fn $fn_name(&self, $($args_i:$args_t),*) -> tardis::basic::result::TardisResult<$Resp> {
247            use $crate::clients::SimpleInvokeClient;
248            use tardis::web::web_resp::TardisResp;
249            let mut query = $crate::clients::QueryBuilder::new();
250            $(
251                {
252                    let q = $query;
253                    query.add(q.0, q.1);
254                }
255            )*
256            $(
257                {
258                    let q = $optional_query;
259                    query.add_optional(q.0, q.1);
260                }
261            )*
262            let url = self.get_url(&[$($path,)*], query.as_ref());
263            let header = self.get_tardis_context_header()?;
264            let resp = self.get_funs().web_client().delete::<TardisResp<$Resp>>(&url, vec![header]).await?;
265            Self::extract_response(resp)
266        }
267    };
268}
269
270#[derive(Debug, Default)]
271pub struct QueryBuilder {
272    pub inner: String,
273}
274impl AsRef<str> for QueryBuilder {
275    fn as_ref(&self) -> &str {
276        &self.inner
277    }
278}
279impl QueryBuilder {
280    pub fn new() -> Self {
281        Self::default()
282    }
283    pub fn add<T: Display>(&mut self, key: &'static str, val: T) {
284        if !self.inner.is_empty() {
285            self.inner.push('&')
286        }
287        self.inner.push_str(key);
288        self.inner.push('=');
289        self.inner.push_str(&val.to_string());
290    }
291    pub fn add_optional<T: Display>(&mut self, key: &'static str, val: Option<T>) {
292        if let Some(val) = val {
293            self.add(key, val)
294        }
295    }
296}
297pub trait SimpleInvokeClient {
298    const DOMAIN_CODE: &'static str;
299    fn get_ctx(&self) -> &TardisContext;
300    fn get_funs(&self) -> &TardisFunsInst;
301    fn get_base_url(&self) -> &str;
302
303    /*
304     * default implements
305     */
306    fn get_tardis_context_header(&self) -> TardisResult<(String, String)> {
307        let ctx = self.get_ctx();
308        Ok((TARDIS_CONTEXT.to_string(), TardisFuns::crypto.base64.encode(TardisFuns::json.obj_to_string(ctx)?)))
309    }
310    fn get_url(&self, path: &[&str], query: &str) -> String {
311        format!(
312            "{base}/{path}{path_query_spliter}{query}",
313            // domain = Self::DOMAIN_CODE,
314            base = self.get_base_url().trim_end_matches('/'),
315            path = path.join("/").trim_matches('/'),
316            path_query_spliter = if query.is_empty() { "" } else { "?" },
317            query = query
318        )
319    }
320    fn extract_response<T>(resp: TardisHttpResponse<TardisResp<T>>) -> TardisResult<T>
321    where
322        T: ParseFromJSON + ToJSON + Serialize + Send + Sync,
323    {
324        resp.body.map_or_else(
325            || {
326                Err(TardisError::internal_error(
327                    &format!("invoke {domain} encounter an error", domain = Self::DOMAIN_CODE),
328                    "500-invoke-request-error",
329                ))
330            },
331            |b| {
332                b.data.ok_or_else(|| TardisError {
333                    code: b.code,
334                    message: format!(
335                        "simple invoke client call domain [{domain}] encounter an error: {msg}",
336                        domain = Self::DOMAIN_CODE,
337                        msg = b.msg
338                    ),
339                })
340            },
341        )
342    }
343}