rustacean_roulette/commands/
mod.rs

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