rpc_toolkit_macro_internals/rpc_handler/
build.rs

1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3use syn::spanned::Spanned;
4
5use super::*;
6
7pub fn build(args: RpcHandlerArgs) -> TokenStream {
8    let mut command = args.command;
9    let mut arguments = std::mem::replace(
10        &mut command.segments.last_mut().unwrap().arguments,
11        PathArguments::None,
12    );
13    let command_module = command.clone();
14    if let PathArguments::AngleBracketed(a) = &mut arguments {
15        a.args.push(syn::parse2(quote! { _ }).unwrap());
16    }
17    command.segments.push(PathSegment {
18        ident: Ident::new("rpc_handler", command.span()),
19        arguments,
20    });
21    let ctx = args.ctx;
22    let parent_data = if let Some(data) = args.parent_data {
23        quote! { #data }
24    } else {
25        quote! { () }
26    };
27    let status_fn = args.status_fn.unwrap_or_else(|| {
28        syn::parse2(quote! { |_| ::rpc_toolkit::hyper::StatusCode::OK }).unwrap()
29    });
30    let middleware_name_clone = (0..)
31        .map(|i| {
32            Ident::new(
33                &format!("__rpc_toolkit__rpc_handler__middleware_clone_{}", i),
34                Span::call_site(),
35            )
36        })
37        .take(args.middleware.len());
38    let middleware_name_clone2 = middleware_name_clone.clone();
39    let middleware_name_clone3 = middleware_name_clone.clone();
40    let middleware_name_clone4 = middleware_name_clone.clone();
41    let middleware_name_pre = (0..)
42        .map(|i| Ident::new(&format!("middleware_pre_{}", i), Span::call_site()))
43        .take(args.middleware.len());
44    let middleware_name_pre2 = middleware_name_pre.clone();
45    let middleware_name_post = (0..)
46        .map(|i| Ident::new(&format!("middleware_post_{}", i), Span::call_site()))
47        .take(args.middleware.len());
48    let middleware_name_post_inv = middleware_name_post
49        .clone()
50        .collect::<Vec<_>>()
51        .into_iter()
52        .rev();
53    let middleware_name = (0..)
54        .map(|i| Ident::new(&format!("middleware_{}", i), Span::call_site()))
55        .take(args.middleware.len());
56    let middleware_name2 = middleware_name.clone();
57    let middleware = args.middleware.iter();
58    let res = quote! {
59        {
60            let __rpc_toolkit__rpc_handler__context = #ctx;
61            let __rpc_toolkit__rpc_handler__parent_data = #parent_data;
62            let __rpc_toolkit__rpc_handler__status_fn = #status_fn;
63            #(
64                let #middleware_name_clone = ::std::sync::Arc::new(#middleware);
65            )*
66            let res: ::rpc_toolkit::RpcHandler = ::std::sync::Arc::new(move |mut req| {
67                let ctx = __rpc_toolkit__rpc_handler__context.clone();
68                let parent_data = __rpc_toolkit__rpc_handler__parent_data.clone();
69                let metadata = #command_module::Metadata::default();
70                #(
71                    let #middleware_name_clone3 = #middleware_name_clone2.clone();
72                )*
73                ::rpc_toolkit::futures::FutureExt::boxed(async move {
74                    #(
75                        let #middleware_name_pre = match ::rpc_toolkit::rpc_server_helpers::constrain_middleware(&*#middleware_name_clone4)(&mut req, metadata).await? {
76                            Ok(a) => a,
77                            Err(res) => return Ok(res),
78                        };
79                    )*
80                    let (mut req_parts, req_body) = req.into_parts();
81                    let (mut res_parts, _) = ::rpc_toolkit::hyper::Response::new(()).into_parts();
82                    let rpc_req = ::rpc_toolkit::rpc_server_helpers::make_request(&req_parts, req_body).await;
83                    match rpc_req {
84                        Ok(mut rpc_req) => {
85                            #(
86                                let #middleware_name_post = match #middleware_name_pre2(&mut req_parts, &mut rpc_req).await? {
87                                    Ok(a) => a,
88                                    Err(res) => return Ok(res),
89                                };
90                            )*
91                            let mut rpc_res = match ::rpc_toolkit::serde_json::from_value(::rpc_toolkit::serde_json::Value::Object(rpc_req.params)) {
92                                Ok(params) => #command(ctx, parent_data, &req_parts, &mut res_parts, ::rpc_toolkit::yajrc::RpcMethod::as_str(&rpc_req.method), params).await,
93                                Err(e) => Err(e.into())
94                            };
95                            #(
96                                let #middleware_name = match #middleware_name_post_inv(&mut res_parts, &mut rpc_res).await? {
97                                    Ok(a) => a,
98                                    Err(res) => return Ok(res),
99                                };
100                            )*
101                            let mut res = ::rpc_toolkit::rpc_server_helpers::to_response(
102                                &req_parts.headers,
103                                res_parts,
104                                Ok((
105                                    rpc_req.id,
106                                    rpc_res,
107                                )),
108                                __rpc_toolkit__rpc_handler__status_fn,
109                            )?;
110                            #(
111                                #middleware_name2(&mut res).await?;
112                            )*
113                            Ok::<_, ::rpc_toolkit::hyper::http::Error>(res)
114                        }
115                        Err(e) => ::rpc_toolkit::rpc_server_helpers::to_response(
116                            &req_parts.headers,
117                            res_parts,
118                            Err(e),
119                            __rpc_toolkit__rpc_handler__status_fn,
120                        ),
121                    }
122                })
123            });
124            res
125        }
126    };
127    // panic!("{}", res);
128    res
129}