1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::types::{CommandTypes, TelegramCommand};
use crate::{
    client::Context,
    model::{Message, MessageContent, MessageEntity, Update, UpdateContent},
};
use log::{debug, warn};

/// A utility for easily managing commands.
///
/// Refer to the [module-level documentation](index.html) for more detail
pub struct Framework {
    commands: Vec<TelegramCommand>,
    bot_name: String,
}

impl Framework {
    /// Creates a new framework instance given the bot name
    pub fn new(bot_name: &str) -> Self {
        Self {
            commands: Vec::new(),
            bot_name: bot_name.to_owned(),
        }
    }

    fn match_command(&self, message: &Message, name: &str) -> bool {
        if let MessageContent::Text {
            entities,
            content,
        } = &message.content
        {
            for entity in entities {
                if let MessageEntity::BotCommand(ref t) = entity {
                    let t = t.get_text(content);
                    return t == format!("/{}", name)
                        || t == format!("/{}@{} ", name, &self.bot_name);
                }
            }
        }
        false
    }

    #[allow(clippy::needless_pass_by_value)]
    fn fire_message_commands(&self, context: Context, message: Message) {
        for command in &self.commands {
            match command.command.clone() {
                CommandTypes::Default(c) if self.match_command(&message, &command.options.name) => {
                    let ctx = context.clone();
                    let msg = message.clone();
                    let command_name = command.options.name;
                    debug!("calling command {}", &command_name);

                    tokio::spawn(async move {
                        let res = c(ctx, msg).await;
                        if res.is_err() {
                            warn!(
                                "command {} returned error: {}",
                                &command_name,
                                res.unwrap_err().0
                            )
                        }
                    });
                },
                _ => (),
            }
        }
    }

    /// add a command to the registered commands
    pub fn add_command(&mut self, command: &TelegramCommand) {
        self.commands.push(command.clone())
    }

    /// get all registered commands
    pub fn get_commands(&self) -> &Vec<TelegramCommand> {
        &self.commands
    }

    /// fires off all commands matching the content in the update
    pub fn fire_commands(&self, context: Context, update: Update) {
        if let UpdateContent::Message(c) = update.content {
            self.fire_message_commands(context, c);
        }
    }
}