use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Block, Expr, Token};
pub(super) struct WatchCfgFileArgs {
title: String,
files: Expr,
reload_block: Block,
}
impl Parse for WatchCfgFileArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let title = input.parse::<syn::LitStr>()?.value();
let _: Token![,] = input.parse()?;
let files = input.parse::<Expr>()?;
let _: Token![,] = input.parse()?;
let reload_block = input.parse()?;
Ok(WatchCfgFileArgs {
title,
files,
reload_block,
})
}
}
pub(super) fn watch_cfg_file_macro(args: WatchCfgFileArgs) -> TokenStream {
let WatchCfgFileArgs {
title,
files,
reload_block,
} = args;
let reload_block = &reload_block.stmts;
let expanded = quote! {
log::debug!("watch {} cfg file: {:?} ...", #title, #files);
tokio::spawn({
async move {
let (_watcher, receiver) = watch_cfg_file(#files).expect(&format!("watch {} cfg file error", #title));
let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
loop {
interval.tick().await;
match receiver.try_recv() {
Ok(event_result) => {
match event_result {
Ok(events) => {
for event in events {
log::debug!("{} cfg file change event: {:?} {:?}", #title, event, #files);
}
log::debug!("reload from {} cfg file: {:?} ...", #title, #files);
#( #reload_block )*
}
Err(e) => {
log::warn!("error receiving {} cfg file events: {:?} {:?}", #title, #files, e);
}
}
}
Err(std::sync::mpsc::TryRecvError::Empty) => {
continue;
}
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
log::debug!("{} cfg file watcher channel closed, exiting watcher loop: {:?}", #title, #files);
break;
}
}
}
log::debug!("{} cfg file watcher task finished: {:?}", #title, #files);
}
});
};
TokenStream::from(expanded)
}