From a8b1fbd3b79782e9bc00ea856a7dd7fd096f8487 Mon Sep 17 00:00:00 2001 From: Graham Littlewood Date: Mon, 13 Apr 2020 00:22:56 -0400 Subject: [PATCH] Add macro command --- src/commands/cmd_macro.rs | 82 +++++++++++++++++++++++++++++++++++---- src/main.rs | 22 +++++++---- src/traits/command.rs | 2 +- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/commands/cmd_macro.rs b/src/commands/cmd_macro.rs index 5f89e24..7f2bc41 100644 --- a/src/commands/cmd_macro.rs +++ b/src/commands/cmd_macro.rs @@ -8,28 +8,94 @@ use serenity::{ extern crate json; extern crate regex; -use regex::Regex; +use regex::{Regex, Match}; + +use core::option::Option; +use std::collections::HashMap; +use std::string::String; use crate::traits::Command; -pub struct CmdMacro {} +pub struct CmdMacro { + format: Regex, + macros: HashMap +} impl Command for CmdMacro { - fn execute(&self, ctx: &Context, msg: &Message) { - + fn execute(& mut self, ctx: &Context, msg: &Message) { + if let Some(parsed) = self.format.captures(&msg.content) { + if let Some(op) = parsed.get(1) { + let mut response = MessageBuilder::new(); + if op.as_str().to_string().to_lowercase() == "add" { + if self.add(parsed.get(2), parsed.get(3)) { + response.push("Successfully added macro."); + } else { + response.push("Missing macro argument or macro already exists."); + } + } else if op.as_str().to_string().to_lowercase() == "remove" { + if self.remove(parsed.get(2)) { + response.push("Successfully removed macro."); + } else { + response.push("Macro does not exist."); + } + } else { + response.push(self.get(&op.as_str().to_string())); + } + if let Err(why) = msg.channel_id.say(&ctx.http, &response.build()) { + println!("Failed to send macro message {:?}", why); + } + return; + } + } let response = MessageBuilder::new() - .push("Hello World") + .push("Unexpected failure.") .build(); - msg.channel_id.say(&ctx.http, &response); + if let Err(why) = msg.channel_id.say(&ctx.http, &response) { + println!("Failed to send macro failure message {:?}", why); + } } fn valid(&self, ctx: &Context, msg: &Message) -> bool { - return msg.content == "macro"; + return self.format.is_match(&msg.content); } } impl CmdMacro { pub fn new() -> CmdMacro{ - return CmdMacro{}; + return CmdMacro { + format: + Regex::new(r#"^!macro\s+([A-Za-z0-9]+|"[^\s]+"|'[^\s]+')(?:\s+([A-Za-z0-9]+|"[^\s]+"|'[^\s]+')\s+(.+))?"#) + .unwrap(), + macros: HashMap::::new(), // TODO: load map from JSON + }; + } + + fn add<'t>(&mut self, key: Option>, value: Option>) -> bool { + let rk; let rv; + if let Some(k) = key { + rk = k; + if self.macros.get(&key.to_owned()).is_some() { + return false; + } + } else {return false;} + if let Some(v) = value { + rv = v; + } else {return false;} + self.macros.insert(rk.as_str().to_string(), rv.as_str().to_string()); + return true; + } + + fn remove<'t>(&mut self, key: Option>) -> bool { + match key { + Some(k) => return self.macros.remove(&k.as_str().to_string()).is_some(), + None => return false, + } + } + + fn get(&self, key: &String) -> String { + if let Some(s) = self.macros.get(&key.to_owned()) { + return s.to_string(); + } + return "Invalid macro".to_string(); } } diff --git a/src/main.rs b/src/main.rs index b97b56b..9c21032 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,16 +15,23 @@ mod traits; mod commands; //use crate::traits::Command; +struct CommandsKey; + +impl TypeMapKey for CommandsKey { + type Value = std::vec::Vec>; +} struct Handler { pub commands: std::vec::Vec>, } impl EventHandler for Handler { - fn message(&self, ctx: Context, msg: Message) { + fn message(& self, ctx: Context, msg: Message) { + let mut data = ctx.data.write(); + let commands = data.get_mut::().unwrap(); // handle messages let mut count = 0; - for cmd in self.commands.iter() { + for cmd in commands.iter_mut() { if cmd.valid(&ctx, &msg) { count+=1; cmd.execute(&ctx, &msg); @@ -45,10 +52,6 @@ impl Handler { commands: std::vec::Vec::new(), }; } - - pub fn add_command(&mut self, box_cmd: Box) { - self.commands.push(box_cmd); - } } fn main() { @@ -57,9 +60,14 @@ fn main() { .expect("Expected a Discord API token in DISCORD_TOKEN environment variable"); let mut event_handler = Handler::new(); // register commands; - event_handler.add_command(Box::new(commands::CmdMacro::new())); + let mut commands = std::vec::Vec::>::new(); + commands.push(Box::new(commands::CmdMacro::new())); // start bot let mut client = Client::new(&token, event_handler).expect("Error creating client"); + { + let mut data = client.data.write(); + data.insert::(commands); + } if let Err(why) = client.start() { println!("Client error: {:?}", why); } diff --git a/src/traits/command.rs b/src/traits/command.rs index 24940fe..a94c483 100644 --- a/src/traits/command.rs +++ b/src/traits/command.rs @@ -5,6 +5,6 @@ use serenity::{ }; pub trait Command: std::marker::Sync + std::marker::Send { - fn execute(&self, ctx: &Context, msg: &Message); + fn execute(& mut self, ctx: &Context, msg: &Message); fn valid(&self, ctx: &Context, msg: &Message) -> bool; }