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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::collections::HashMap;

use futures::stream::Stream;
use telegram_bot::types::{InlineQuery, Message, MessageKind, Update, UpdateKind};
use telegram_bot::Api;
use tokio_core::reactor::Core;

pub struct BotWrapper<B: BotHandler> {
    api: Api,
    core: Core,
    commands: HashMap<String, Box<dyn Fn(&Api, &Message) -> ()>>,
    handler: B,
}

impl BotWrapper<NoBotHandler> {
    pub fn new(token: String) -> BotWrapper<NoBotHandler> {
        let core = Core::new().expect("Failed to execute tokio core");

        let api = Api::configure(token.clone())
            .build(core.handle())
            .expect("Failed to spawn bot threads");
        BotWrapper {
            api,
            core,
            commands: HashMap::new(),
            handler: NoBotHandler,
        }
    }
}

impl<B: BotHandler> BotWrapper<B> {
    fn handle_update(
        api: &Api,
        commands: &HashMap<String, Box<dyn Fn(&Api, &Message) -> ()>>,
        update: Update,
        handler: &B
    ) {
        if let UpdateKind::Message(ref msg) = update.kind {
            if let MessageKind::Text {
                ref data,
                entities: _,
            } = msg.kind
            {
                let data = data.clone().split_off(1);
                let data = data.split_whitespace().next().unwrap_or("");
                commands.get(data).map(|command| command(api, msg));
                return;
            }
        }

        match update.kind {
            UpdateKind::InlineQuery(query) => handler.inline_query(api, query),
            _ => ()
        }
    }

    pub fn new_with_handler(token: String, handler: B) -> BotWrapper<B> {
        let core = Core::new().expect("Failed to execute tokio core");

        let api = Api::configure(token.clone())
            .build(core.handle())
            .expect("Failed to spawn bot threads");
        BotWrapper {
            api,
            core,
            commands: HashMap::new(),
            handler,
        }
    }

    pub fn run(self) {
        let BotWrapper {
            api,
            mut core,
            commands,
            handler,
        } = self;
        let update_stream = api
            .stream()
            .for_each(|update| Ok(BotWrapper::handle_update(&api, &commands, update, &handler)));

        core.run(update_stream).expect("Failed to run core reactor");
    }

    pub fn command<F>(&mut self, command: String, handle: F)
    where
        F: 'static + Fn(&Api, &Message) -> (),
    {
        self.commands.insert(command, Box::new(handle));
    }
}

#[allow(unused_variables)]
pub trait BotHandler {
    fn inline_query(&self, api: &Api, query: InlineQuery) {}
}

pub struct NoBotHandler;
impl BotHandler for NoBotHandler {}