add rpc_handler macro

This commit is contained in:
Aiden McClelland
2022-09-29 15:11:40 -06:00
parent fcee8eddce
commit aee1d7f753
13 changed files with 188 additions and 143 deletions

View File

@@ -8,10 +8,13 @@ macro_rules! macro_try {
}
mod command;
mod rpc_handler;
mod rpc_server;
mod run_cli;
pub use command::build::build as build_command;
pub use rpc_handler::build::build as build_rpc_handler;
pub use rpc_handler::RpcHandlerArgs;
pub use rpc_server::build::build as build_rpc_server;
pub use rpc_server::RpcServerArgs;
pub use run_cli::build::build as build_run_cli;

View File

@@ -0,0 +1,129 @@
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::spanned::Spanned;
use super::*;
pub fn build(args: RpcHandlerArgs) -> TokenStream {
let mut command = args.command;
let mut arguments = std::mem::replace(
&mut command.segments.last_mut().unwrap().arguments,
PathArguments::None,
);
let command_module = command.clone();
if let PathArguments::AngleBracketed(a) = &mut arguments {
a.args.push(syn::parse2(quote! { _ }).unwrap());
}
command.segments.push(PathSegment {
ident: Ident::new("rpc_handler", command.span()),
arguments,
});
let ctx = args.ctx;
let parent_data = if let Some(data) = args.parent_data {
quote! { #data }
} else {
quote! { () }
};
let status_fn = args.status_fn.unwrap_or_else(|| {
syn::parse2(quote! { |_| ::rpc_toolkit::hyper::StatusCode::OK }).unwrap()
});
let middleware_name_clone = (0..)
.map(|i| {
Ident::new(
&format!("__rpc_toolkit__rpc_handler__middleware_clone_{}", i),
Span::call_site(),
)
})
.take(args.middleware.len());
let middleware_name_clone2 = middleware_name_clone.clone();
let middleware_name_clone3 = middleware_name_clone.clone();
let middleware_name_clone4 = middleware_name_clone.clone();
let middleware_name_pre = (0..)
.map(|i| Ident::new(&format!("middleware_pre_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name_pre2 = middleware_name_pre.clone();
let middleware_name_post = (0..)
.map(|i| Ident::new(&format!("middleware_post_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name_post_inv = middleware_name_post
.clone()
.collect::<Vec<_>>()
.into_iter()
.rev();
let middleware_name = (0..)
.map(|i| Ident::new(&format!("middleware_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name2 = middleware_name.clone();
let middleware = args.middleware.iter();
let res = quote! {
{
let __rpc_toolkit__rpc_handler__context = #ctx;
let __rpc_toolkit__rpc_handler__parent_data = #parent_data;
let __rpc_toolkit__rpc_handler__status_fn = #status_fn;
#(
let #middleware_name_clone = ::std::sync::Arc::new(#middleware);
)*
let res: ::rpc_toolkit::RpcHandler = ::std::sync::Arc::new(move |mut req| {
let ctx = __rpc_toolkit__rpc_handler__context.clone();
let parent_data = __rpc_toolkit__rpc_handler__parent_data.clone();
let metadata = #command_module::Metadata::default();
#(
let #middleware_name_clone3 = #middleware_name_clone2.clone();
)*
::rpc_toolkit::futures::FutureExt::boxed(async move {
#(
let #middleware_name_pre = match ::rpc_toolkit::rpc_server_helpers::constrain_middleware(&*#middleware_name_clone4)(&mut req, metadata).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let (mut req_parts, req_body) = req.into_parts();
let (mut res_parts, _) = ::rpc_toolkit::hyper::Response::new(()).into_parts();
let rpc_req = ::rpc_toolkit::rpc_server_helpers::make_request(&req_parts, req_body).await;
match rpc_req {
Ok(mut rpc_req) => {
#(
let #middleware_name_post = match #middleware_name_pre2(&mut req_parts, &mut rpc_req).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let mut rpc_res = match ::rpc_toolkit::serde_json::from_value(::rpc_toolkit::serde_json::Value::Object(rpc_req.params)) {
Ok(params) => #command(ctx, parent_data, &req_parts, &mut res_parts, ::rpc_toolkit::yajrc::RpcMethod::as_str(&rpc_req.method), params).await,
Err(e) => Err(e.into())
};
#(
let #middleware_name = match #middleware_name_post_inv(&mut res_parts, &mut rpc_res).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let mut res = ::rpc_toolkit::rpc_server_helpers::to_response(
&req_parts.headers,
res_parts,
Ok((
rpc_req.id,
rpc_res,
)),
__rpc_toolkit__rpc_handler__status_fn,
)?;
#(
#middleware_name2(&mut res).await?;
)*
Ok::<_, ::rpc_toolkit::hyper::http::Error>(res)
}
Err(e) => ::rpc_toolkit::rpc_server_helpers::to_response(
&req_parts.headers,
res_parts,
Err(e),
__rpc_toolkit__rpc_handler__status_fn,
),
}
})
});
res
}
};
// panic!("{}", res);
res
}

View File

@@ -0,0 +1,12 @@
use syn::*;
pub struct RpcHandlerArgs {
pub(crate) command: Path,
pub(crate) ctx: Expr,
pub(crate) parent_data: Option<Expr>,
pub(crate) status_fn: Option<Expr>,
pub(crate) middleware: punctuated::Punctuated<Expr, token::Comma>,
}
pub mod build;
mod parse;

View File

@@ -3,7 +3,7 @@ use syn::punctuated::Punctuated;
use super::*;
impl Parse for RpcServerArgs {
impl Parse for RpcHandlerArgs {
fn parse(input: ParseStream) -> Result<Self> {
let args;
braced!(args in input);
@@ -39,7 +39,7 @@ impl Parse for RpcServerArgs {
let _: token::Comma = args.parse()?;
}
}
Ok(RpcServerArgs {
Ok(RpcHandlerArgs {
command: command.expect("`command` is required"),
ctx: ctx.expect("`context` is required"),
parent_data,

View File

@@ -1,134 +1,23 @@
use proc_macro2::{Span, TokenStream};
use proc_macro2::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use super::*;
pub fn build(args: RpcServerArgs) -> TokenStream {
let mut command = args.command;
let mut arguments = std::mem::replace(
&mut command.segments.last_mut().unwrap().arguments,
PathArguments::None,
pub fn build(mut args: RpcServerArgs) -> TokenStream {
let ctx = std::mem::replace(
&mut args.ctx,
parse2(quote! { __rpc_toolkit__rpc_server__context }).unwrap(),
);
let command_module = command.clone();
if let PathArguments::AngleBracketed(a) = &mut arguments {
a.args.push(syn::parse2(quote! { _ }).unwrap());
}
command.segments.push(PathSegment {
ident: Ident::new("rpc_handler", command.span()),
arguments,
});
let ctx = args.ctx;
let parent_data = if let Some(data) = args.parent_data {
quote! { #data }
} else {
quote! { () }
};
let status_fn = args.status_fn.unwrap_or_else(|| {
syn::parse2(quote! { |_| ::rpc_toolkit::hyper::StatusCode::OK }).unwrap()
});
let middleware_name_clone = (0..)
.map(|i| Ident::new(&format!("middleware_clone_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name_clone2 = middleware_name_clone.clone();
let middleware_name_clone3 = middleware_name_clone.clone();
let middleware_name_clone4 = middleware_name_clone.clone();
let middleware_name_clone5 = middleware_name_clone.clone();
let middleware_name_clone6 = middleware_name_clone.clone();
let middleware_name_pre = (0..)
.map(|i| Ident::new(&format!("middleware_pre_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name_pre2 = middleware_name_pre.clone();
let middleware_name_post = (0..)
.map(|i| Ident::new(&format!("middleware_post_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name_post_inv = middleware_name_post
.clone()
.collect::<Vec<_>>()
.into_iter()
.rev();
let middleware_name = (0..)
.map(|i| Ident::new(&format!("middleware_{}", i), Span::call_site()))
.take(args.middleware.len());
let middleware_name2 = middleware_name.clone();
let middleware = args.middleware.iter();
let handler = crate::rpc_handler::build::build(args);
let res = quote! {
{
let ctx = #ctx;
let parent_data = #parent_data;
let status_fn = #status_fn;
let builder = ::rpc_toolkit::rpc_server_helpers::make_builder(&ctx);
#(
let #middleware_name_clone = ::std::sync::Arc::new(#middleware);
)*
let make_svc = ::rpc_toolkit::hyper::service::make_service_fn(move |_| {
let ctx = ctx.clone();
let parent_data = parent_data.clone();
#(
let #middleware_name_clone3 = #middleware_name_clone2.clone();
)*
async move {
Ok::<_, ::rpc_toolkit::hyper::Error>(::rpc_toolkit::hyper::service::service_fn(move |mut req| {
let ctx = ctx.clone();
let parent_data = parent_data.clone();
let metadata = #command_module::Metadata::default();
#(
let #middleware_name_clone5 = #middleware_name_clone4.clone();
)*
async move {
#(
let #middleware_name_pre = match ::rpc_toolkit::rpc_server_helpers::constrain_middleware(&*#middleware_name_clone6)(&mut req, metadata).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let (mut req_parts, req_body) = req.into_parts();
let (mut res_parts, _) = ::rpc_toolkit::hyper::Response::new(()).into_parts();
let rpc_req = ::rpc_toolkit::rpc_server_helpers::make_request(&req_parts, req_body).await;
match rpc_req {
Ok(mut rpc_req) => {
#(
let #middleware_name_post = match #middleware_name_pre2(&mut req_parts, &mut rpc_req).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let mut rpc_res = match ::rpc_toolkit::serde_json::from_value(::rpc_toolkit::serde_json::Value::Object(rpc_req.params)) {
Ok(params) => #command(ctx, parent_data, &req_parts, &mut res_parts, ::rpc_toolkit::yajrc::RpcMethod::as_str(&rpc_req.method), params).await,
Err(e) => Err(e.into())
};
#(
let #middleware_name = match #middleware_name_post_inv(&mut res_parts, &mut rpc_res).await? {
Ok(a) => a,
Err(res) => return Ok(res),
};
)*
let mut res = ::rpc_toolkit::rpc_server_helpers::to_response(
&req_parts.headers,
res_parts,
Ok((
rpc_req.id,
rpc_res,
)),
status_fn,
)?;
#(
#middleware_name2(&mut res).await?;
)*
Ok::<_, ::rpc_toolkit::hyper::http::Error>(res)
}
Err(e) => ::rpc_toolkit::rpc_server_helpers::to_response(
&req_parts.headers,
res_parts,
Err(e),
status_fn,
),
}
}
}))
}
});
builder.serve(make_svc)
let __rpc_toolkit__rpc_server__context = #ctx;
let __rpc_toolkit__rpc_server__builder = ::rpc_toolkit::rpc_server_helpers::make_builder(&__rpc_toolkit__rpc_server__context);
let handler = #handler;
__rpc_toolkit__rpc_server__builder.serve(::rpc_toolkit::hyper::service::make_service_fn(move |_| {
let handler = handler.clone();
async move { Ok::<_, ::std::convert::Infallible>(::rpc_toolkit::hyper::service::service_fn(move |req| handler(req))) }
}))
}
};
// panic!("{}", res);

View File

@@ -1,12 +1,5 @@
use syn::*;
pub struct RpcServerArgs {
command: Path,
ctx: Expr,
parent_data: Option<Expr>,
status_fn: Option<Expr>,
middleware: punctuated::Punctuated<Expr, token::Comma>,
}
pub type RpcServerArgs = crate::RpcHandlerArgs;
pub mod build;
mod parse;