1use std::collections::HashMap;
2
3use futures::stream::Stream;
4use telegram_bot::types::{InlineQuery, Message, MessageKind, Update, UpdateKind};
5use telegram_bot::Api;
6use tokio_core::reactor::Core;
7
8pub struct BotWrapper<B: BotHandler> {
9 api: Api,
10 core: Core,
11 commands: HashMap<String, Box<dyn Fn(&Api, &Message) -> ()>>,
12 handler: B,
13}
14
15impl BotWrapper<NoBotHandler> {
16 pub fn new(token: String) -> BotWrapper<NoBotHandler> {
17 let core = Core::new().expect("Failed to execute tokio core");
18
19 let api = Api::configure(token.clone())
20 .build(core.handle())
21 .expect("Failed to spawn bot threads");
22 BotWrapper {
23 api,
24 core,
25 commands: HashMap::new(),
26 handler: NoBotHandler,
27 }
28 }
29}
30
31impl<B: BotHandler> BotWrapper<B> {
32 fn handle_update(
33 api: &Api,
34 commands: &HashMap<String, Box<dyn Fn(&Api, &Message) -> ()>>,
35 update: Update,
36 handler: &B
37 ) {
38 if let UpdateKind::Message(ref msg) = update.kind {
39 if let MessageKind::Text {
40 ref data,
41 entities: _,
42 } = msg.kind
43 {
44 let data = data.clone().split_off(1);
45 let data = data.split_whitespace().next().unwrap_or("");
46 commands.get(data).map(|command| command(api, msg));
47 return;
48 }
49 }
50
51 match update.kind {
52 UpdateKind::InlineQuery(query) => handler.inline_query(api, query),
53 _ => ()
54 }
55 }
56
57 pub fn new_with_handler(token: String, handler: B) -> BotWrapper<B> {
58 let core = Core::new().expect("Failed to execute tokio core");
59
60 let api = Api::configure(token.clone())
61 .build(core.handle())
62 .expect("Failed to spawn bot threads");
63 BotWrapper {
64 api,
65 core,
66 commands: HashMap::new(),
67 handler,
68 }
69 }
70
71 pub fn run(self) {
72 let BotWrapper {
73 api,
74 mut core,
75 commands,
76 handler,
77 } = self;
78 let update_stream = api
79 .stream()
80 .for_each(|update| Ok(BotWrapper::handle_update(&api, &commands, update, &handler)));
81
82 core.run(update_stream).expect("Failed to run core reactor");
83 }
84
85 pub fn command<F>(&mut self, command: String, handle: F)
86 where
87 F: 'static + Fn(&Api, &Message) -> (),
88 {
89 self.commands.insert(command, Box::new(handle));
90 }
91}
92
93#[allow(unused_variables)]
94pub trait BotHandler {
95 fn inline_query(&self, api: &Api, query: InlineQuery) {}
96}
97
98pub struct NoBotHandler;
99impl BotHandler for NoBotHandler {}