mrsbfh

Matrix-Rust-SDK-Bot-Framework-Helper
git clone git://archive.git.mtrnord.blog/MTRNord/mrsbfh.git
Log | Files | Refs | README

commit 14048cf9b242f9e3d33aad8e3cd1300c8a563bee
parent 042c76a783c49129bfb1f8c4c6edffed812dafa0
Author: MTRNord <mtrnord1@gmail.com>
Date:   Thu,  7 Jan 2021 19:24:01 +0100

feat: Add commands proc macro and implement in the example bot

Diffstat:
Mexample-bot/src/matrix/sync.rs | 62+++++---------------------------------------------------------
Mmrsbfh-macros/src/lib.rs | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mmrsbfh/src/commands.rs | 3+--
3 files changed, 106 insertions(+), 60 deletions(-)

diff --git a/example-bot/src/matrix/sync.rs b/example-bot/src/matrix/sync.rs @@ -2,9 +2,8 @@ use crate::commands::match_command; use crate::config::Config; use mrsbfh::matrix_sdk::{ events::{ - room::member::MemberEventContent, - room::message::{MessageEventContent, TextMessageEventContent}, - StrippedStateEvent, SyncMessageEvent, + room::member::MemberEventContent, room::message::MessageEventContent, StrippedStateEvent, + SyncMessageEvent, }, Client, EventEmitter, SyncRoom, }; @@ -27,63 +26,12 @@ impl Bot { } } +#[mrsbfh::commands::commands] #[mrsbfh::utils::autojoin] #[async_trait] impl EventEmitter for Bot { async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent<MessageEventContent>) { - if let SyncRoom::Joined(room) = room { - let msg_body = if let SyncMessageEvent { - content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), - .. - } = event - { - msg_body.clone() - } else { - String::new() - }; - if msg_body.is_empty() { - return; - } - - let sender = event.sender.clone().to_string(); - - let (tx, mut rx) = mpsc::channel(100); - let room_id = room.read().await.clone().room_id; - - let cloned_config = self.config.clone(); - tokio::spawn(async move { - let mut split = msg_body.split_whitespace(); - - let command_raw = split.next().expect("This is not a command"); - let command = command_raw.to_lowercase(); - info!("Got command: {}", command); - - // Make sure this is immutable - let args: Vec<&str> = split.collect(); - if let Err(e) = match_command( - command.replace("!", "").as_str(), - cloned_config.clone(), - tx, - sender, - args, - ) - .await - { - error!("{}", e); - } - }); - - while let Some(v) = rx.recv().await { - if let Err(e) = self - .client - .clone() - .room_send(&room_id.clone(), v, None) - .await - { - error!("{}", e); - } - } - } + println!("message example") } async fn on_stripped_state_member( @@ -92,6 +40,6 @@ impl EventEmitter for Bot { room_member: &StrippedStateEvent<MemberEventContent>, _: Option<MemberEventContent>, ) { - println!("test") + println!("autojoin example") } } diff --git a/mrsbfh-macros/src/lib.rs b/mrsbfh-macros/src/lib.rs @@ -234,7 +234,7 @@ pub fn autojoin(_: TokenStream, input: TokenStream) -> TokenStream { warn!("Got invite that isn't for us"); return; } - if let SyncRoom::Invited(room) = room { + if let mrsbfh::matrix_sdk::SyncRoom::Invited(room) = room { let room_id = { let room = room.read().await; room.room_id.clone() @@ -274,3 +274,102 @@ pub fn autojoin(_: TokenStream, input: TokenStream) -> TokenStream { TokenStream::from(quote! {#input}) } + +/// Used to generate code to detect commands when we get a message for the bot +/// +/// Requirements: +/// +/// * Tokio +/// * Naming of arguments needs to be EXACTLY like in the example +/// * the async_trait macro needs to be BELOW the commands macro +/// * The match_command MUST be imported +/// +/// ```compile_fail +/// use crate::commands::match_command; +/// +/// #[mrsbfh::commands::commands] +/// #[async_trait] +/// impl EventEmitter for Bot { +/// +/// async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent<MessageEventContent>) { +/// // Your own logic. (Executed BEFORE the commands matching) +/// } +/// } +/// ``` +/// +#[proc_macro_attribute] +pub fn commands(_: TokenStream, input: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(input as syn::ItemImpl); + let items = &mut input.items; + + for item in items { + if let syn::ImplItem::Method(method) = item { + if method.sig.ident.to_string() == "on_room_message" { + let original = method.block.clone(); + let new_block = syn::parse_quote! { + { + #original + + // Command matching logic + if let mrsbfh::matrix_sdk::SyncRoom::Joined(room) = room { + let msg_body = if let mrsbfh::matrix_sdk::events::SyncMessageEvent { + content: mrsbfh::matrix_sdk::events::room::message::MessageEventContent::Text(mrsbfh::matrix_sdk::events::room::message::TextMessageEventContent { body: msg_body, .. }), + .. + } = event + { + msg_body.clone() + } else { + String::new() + }; + if msg_body.is_empty() { + return; + } + + let sender = event.sender.clone().to_string(); + + let (tx, mut rx) = mpsc::channel(100); + let room_id = room.read().await.clone().room_id; + + let cloned_config = self.config.clone(); + tokio::spawn(async move { + let mut split = msg_body.split_whitespace(); + + let command_raw = split.next().expect("This is not a command"); + let command = command_raw.to_lowercase(); + info!("Got command: {}", command); + + // Make sure this is immutable + let args: Vec<&str> = split.collect(); + if let Err(e) = match_command( + command.replace("!", "").as_str(), + cloned_config.clone(), + tx, + sender, + args, + ) + .await + { + error!("{}", e); + } + }); + + while let Some(v) = rx.recv().await { + if let Err(e) = self + .client + .clone() + .room_send(&room_id.clone(), v, None) + .await + { + error!("{}", e); + } + } + } + } + }; + method.block = new_block; + } + } + } + + TokenStream::from(quote! {#input}) +} diff --git a/mrsbfh/src/commands.rs b/mrsbfh/src/commands.rs @@ -1 +1 @@ -pub use mrsbfh_macros::{command, command_generate}; -\ No newline at end of file +pub use mrsbfh_macros::{command, command_generate, commands};