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:
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};