Skip to main content

rustacean_roulette/commands/
mod.rs

1mod peek;
2mod roulette;
3
4use super::Roulette;
5use frankenstein::{
6    client_reqwest::Bot,
7    types::{BotCommand, Message},
8};
9use peek::PeekCommand;
10use roulette::RouletteCommand;
11use tokio::sync::Mutex;
12
13/// A command.
14pub trait Command {
15    /// Trigger word.
16    const TRIGGER: &'static str;
17    /// Help message.
18    const HELP: &'static str;
19    /// Execute the command.
20    async fn execute(bot: &Bot, msg: Message, roulette: &Mutex<Roulette>) -> Option<String>;
21}
22
23/// List of commands. Cheap to clone.
24#[non_exhaustive]
25pub enum Commands {
26    Peek,
27    Roulette,
28}
29
30impl Commands {
31    /// Try to parse the given text to a command.
32    ///
33    /// # Arguments
34    ///
35    /// - `text` - The text to check.
36    /// - `username` - The username of the bot.
37    pub fn parse(text: Option<&String>, username: &str) -> Option<Commands> {
38        let Some(text) = text else {
39            return None;
40        };
41        let text = text.trim();
42        let (command, _arg) = text.split_once(' ').unwrap_or((text, ""));
43
44        // Two possible command formats:
45        // 1. /command <arg>
46        // 2. /command@bot_username <arg>
47
48        // Trim the leading slash
49        let slash = command.starts_with('/');
50        if !slash {
51            return None;
52        }
53        let command = &command[1..];
54
55        // Split out the mention and check if it's the bot
56        let (command, mention) = command.split_once('@').unwrap_or((command, ""));
57        if !mention.is_empty() && mention != username {
58            return None;
59        }
60
61        // Match the command
62        match command {
63            PeekCommand::TRIGGER => Some(Commands::Peek),
64            RouletteCommand::TRIGGER => Some(Commands::Roulette),
65            _ => None,
66        }
67    }
68
69    /// Execute the command.
70    pub async fn execute(
71        &self,
72        bot: &Bot,
73        msg: Message,
74        roulette: &Mutex<Roulette>,
75    ) -> Option<String> {
76        match self {
77            Self::Peek => PeekCommand::execute(bot, msg, roulette).await,
78            Self::Roulette => RouletteCommand::execute(bot, msg, roulette).await,
79        }
80    }
81
82    /// List of commands.
83    pub fn list() -> Vec<BotCommand> {
84        vec![
85            BotCommand {
86                command: PeekCommand::TRIGGER.to_string(),
87                description: PeekCommand::HELP.to_string(),
88            },
89            BotCommand {
90                command: RouletteCommand::TRIGGER.to_string(),
91                description: RouletteCommand::HELP.to_string(),
92            },
93        ]
94    }
95}