extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, AttributeArgs, ItemFn, Lit, NestedMeta, ReturnType};
#[proc_macro_attribute]
pub fn server(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as AttributeArgs);
let mut input = parse_macro_input!(input as ItemFn);
let attrs = &input.attrs;
let vis = &input.vis;
let sig = &mut input.sig;
let body = &input.block;
let mut listen: String = "127.0.0.1:8080".into();
if args.len() > 0 {
listen = match &args[0] {
NestedMeta::Lit(Lit::Str(lit)) => lit.value(),
_ => unreachable!(),
};
}
sig.output = ReturnType::Default;
let output = quote!(
use vujio_client::*;
use vujio_server::*;
#(#attrs)*
#vis #sig -> vujio_server::Result<()> {
let client_bundle = client::bundle(
"src/main.ts",
&client::BundlerConfig {
minify: true,
compat: false,
source_maps: cfg!(debug_assertions),
},
);
let state = AppState { client_bundle };
let mut app = vujio_server::with_state(state);
app.at("/").get(async move |_req: vujio_server::Request<AppState>| -> vujio_server::Result {
Ok(vujio_server::Response::builder(200)
.body("<!DOCTYPE html><html><head><title></title><script src=\"bundle\"></script></head><body></body></html>")
.content_type(mime::HTML)
.build())
});
app.at("/bundle").get(async move |req: vujio_server::Request<AppState>| -> vujio_server::Result<String> {
Ok(req.state().client_bundle.clone())
});
app.at("/ws")
.get(WebSocket::new(|_request, mut stream| async move {
while let Some(Ok(Message::Text(input))) = stream.next().await {
}
Ok(())
}));
#body;
app.at("/favicon.ico").get(async move |_req: vujio_server::Request<AppState>| -> vujio_server::Result {
Ok(vujio_server::Response::builder(404).content_type(mime::ICO).build())
});
println!("Listen {}", #listen);
app.listen(#listen).await?;
Ok(())
}
);
output.into()
}
#[proc_macro_attribute]
pub fn get_html(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as AttributeArgs);
let mut input = parse_macro_input!(input as ItemFn);
let attrs = &input.attrs;
let vis = &input.vis;
let sig = &mut input.sig;
let body = &input.block;
let mut app_path = format!("/{}", sig.ident.to_string());
if args.len() > 0 {
app_path = match &args[0] {
NestedMeta::Lit(Lit::Str(lit)) => lit.value(),
_ => unreachable!(),
};
}
let function_ident = sig.ident.clone();
sig.output = ReturnType::Default;
let output = quote!(
app.at(#app_path).get(#function_ident);
#(#attrs)*
#vis #sig -> vujio_server::Result {
let result: String = (async move || {
#body
})().await;
Ok(vujio_server::Response::builder(200)
.body(result)
.content_type(mime::HTML)
.build())
}
);
output.into()
}