use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::parse;
fn is_app_state_type(ty: &syn::Type) -> bool {
if let syn::Type::Path(type_path) = ty {
if type_path.qself.is_none() {
let segments: Vec<_> = type_path.path.segments.iter().collect();
if let Some(last) = segments.last() {
return last.ident == "AppState" && last.arguments.is_none();
}
}
}
false
}
pub fn ws_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
let path = match parse::parse_route_path(attr) {
Ok(p) => p,
Err(err) => return err,
};
let input_fn = match parse::parse_async_handler(item) {
Ok(f) => f,
Err(err) => return err,
};
let fn_name = &input_fn.sig.ident;
let vis = &input_fn.vis;
let upgrade_name = format_ident!("__autumn_ws_upgrade_{}", fn_name);
let route_info_name = format_ident!("__autumn_route_info_{}", fn_name);
let mut extractor_params = Vec::new();
let mut call_args = Vec::new();
for arg in &input_fn.sig.inputs {
if let syn::FnArg::Typed(pat_type) = arg {
if is_app_state_type(&pat_type.ty) {
call_args.push(quote! { __autumn_state.clone() });
} else {
let pat = &pat_type.pat;
extractor_params.push(arg.clone());
call_args.push(quote! { #pat });
}
}
}
let upgrade_handler = if extractor_params.is_empty() {
quote! {
#[doc(hidden)]
#vis async fn #upgrade_name(
__autumn_ws: ::autumn_web::ws::WebSocketUpgrade,
::autumn_web::reexports::axum::extract::State(__autumn_state): ::autumn_web::reexports::axum::extract::State<::autumn_web::AppState>,
) -> impl ::autumn_web::reexports::axum::response::IntoResponse {
let __autumn_shutdown = __autumn_state.shutdown_token();
let handler = #fn_name(#(#call_args),*).await;
__autumn_ws.on_upgrade(move |socket| async move {
::autumn_web::ws::WsHandler::handle(handler, socket, __autumn_shutdown).await;
})
}
}
} else {
quote! {
#[doc(hidden)]
#vis async fn #upgrade_name(
__autumn_ws: ::autumn_web::ws::WebSocketUpgrade,
::autumn_web::reexports::axum::extract::State(__autumn_state): ::autumn_web::reexports::axum::extract::State<::autumn_web::AppState>,
#(#extractor_params),*
) -> impl ::autumn_web::reexports::axum::response::IntoResponse {
let __autumn_shutdown = __autumn_state.shutdown_token();
let handler = #fn_name(#(#call_args),*).await;
__autumn_ws.on_upgrade(move |socket| async move {
::autumn_web::ws::WsHandler::handle(handler, socket, __autumn_shutdown).await;
})
}
}
};
quote! {
#input_fn
#upgrade_handler
#[doc(hidden)]
#vis fn #route_info_name() -> ::autumn_web::Route {
::autumn_web::Route {
method: ::autumn_web::reexports::http::Method::GET,
path: #path,
handler: ::autumn_web::reexports::axum::routing::get(#upgrade_name),
name: ::core::stringify!(#fn_name),
}
}
}
}