Reviewed-on: #5 Co-authored-by: traffic95 <traffic95@xeondev.com> Co-committed-by: traffic95 <traffic95@xeondev.com>
125 lines
4.6 KiB
Rust
125 lines
4.6 KiB
Rust
use proc_macro2::TokenStream;
|
|
use quote::{ToTokens, quote};
|
|
use syn::{FnArg, Item, ItemMod, ReturnType, parse_macro_input};
|
|
|
|
pub fn imp(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
const INVALID_FUNCTION_SIGNATURE_MSG: &str = "functions in message handler module should have following signature: fn(&mut MessageContext<'_>, CsReq) -> ScRsp";
|
|
|
|
let module = parse_macro_input!(input as ItemMod);
|
|
let mod_name = &module.ident;
|
|
|
|
let (_, items) = module
|
|
.content
|
|
.as_ref()
|
|
.expect("#[handlers] module should contain message handler functions");
|
|
|
|
let mut output_module = TokenStream::new();
|
|
let mut handler_match_arms = TokenStream::new();
|
|
let mut supports_message_expressions = TokenStream::new();
|
|
|
|
for item in items.iter() {
|
|
let Item::Fn(func) = item else {
|
|
output_module.extend(item.to_token_stream());
|
|
continue;
|
|
};
|
|
|
|
let sig = &func.sig;
|
|
let name = &sig.ident;
|
|
|
|
assert_eq!(sig.inputs.len(), 2, "{}", INVALID_FUNCTION_SIGNATURE_MSG);
|
|
|
|
let argument = match sig.inputs.get(1).as_ref().unwrap() {
|
|
FnArg::Typed(argument) => argument,
|
|
FnArg::Receiver(_) => unreachable!(),
|
|
};
|
|
|
|
output_module.extend(quote! {
|
|
#[::tracing::instrument(skip_all)]
|
|
#func
|
|
});
|
|
|
|
let request_type = argument.ty.as_ref();
|
|
supports_message_expressions.extend(quote! {
|
|
if cmd_id == #request_type::CMD_ID {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
let has_return_message = ReturnType::Default != sig.output;
|
|
|
|
if has_return_message {
|
|
handler_match_arms.extend(quote! {
|
|
#request_type::CMD_ID => {
|
|
let request = match #request_type::decode(&mut ::std::io::Cursor::new(&message.message.blob)) {
|
|
Ok(request) => request,
|
|
Err(err) => {
|
|
::tracing::error!("failed to decode message {}: {}", stringify!(#request_type), err);
|
|
return None;
|
|
}
|
|
};
|
|
|
|
let mut context = super::MessageContext::new(state, session, player, message.request_id);
|
|
let response = #mod_name::#name(&mut context, request).await;
|
|
|
|
::tracing::debug!("client message {} was handled", stringify!(#request_type));
|
|
Some(::trigger_sv::message::AvailableServerProtocolMessage {
|
|
session_id: context.session.id,
|
|
ack_request_id: message.request_id,
|
|
response: Some(response.into()),
|
|
notifies: context.remove_notifies(),
|
|
})
|
|
}
|
|
});
|
|
} else {
|
|
handler_match_arms.extend(quote! {
|
|
#request_type::CMD_ID => {
|
|
let request = match #request_type::decode(&mut ::std::io::Cursor::new(&message.message.blob)) {
|
|
Ok(request) => request,
|
|
Err(err) => {
|
|
::tracing::error!("failed to decode message {}: {}", stringify!(#request_type), err);
|
|
return None;
|
|
}
|
|
};
|
|
|
|
let mut context = super::MessageContext::new(state, session, player, message.request_id);
|
|
#mod_name::#name(&mut context, request).await;
|
|
|
|
::tracing::debug!("client message {} was handled", stringify!(#request_type));
|
|
Some(::trigger_sv::message::AvailableServerProtocolMessage {
|
|
session_id: context.session.id,
|
|
ack_request_id: message.request_id,
|
|
response: None,
|
|
notifies: context.remove_notifies(),
|
|
})
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
quote! {
|
|
pub fn supports_message(cmd_id: u16) -> bool {
|
|
use ::trigger_protocol::*;
|
|
|
|
#supports_message_expressions
|
|
false
|
|
}
|
|
|
|
pub async fn handle_message(state: &'static crate::AppState, session: &crate::session::GameSession, player: &mut crate::NapPlayer, message: ::trigger_sv::message::ForwardClientProtocolMessage) -> Option<::trigger_sv::message::AvailableServerProtocolMessage> {
|
|
use ::trigger_protocol::*;
|
|
use ::trigger_encoding::{Encodeable, Decodeable};
|
|
|
|
match message.message.cmd_id {
|
|
#handler_match_arms
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
mod #mod_name {
|
|
use super::MessageContext;
|
|
use ::trigger_protocol::*;
|
|
|
|
#output_module
|
|
}
|
|
}
|
|
.into()
|
|
}
|