forked from teloxide/teloxide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deep_linking.rs
138 lines (128 loc) · 4.15 KB
/
deep_linking.rs
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! This example demonstrates how to use deep linking in Telegram
//! by making a simple anonymous message bot.
//!
//! Deep linking (links like https://t.me/some_bot?start=123456789)
//! is handled by telegram in the same way as just sending /start {argument}.
//! So, in the StartCommand enum we need to write Start(String)
//! to get the argument, just like in command.rs example.
//!
//! Also, deep linking is only supported with /start command!
//! "https://t.me/some_bot?argument=123456789" will not work
//!
//! https://core.telegram.org/bots/features#deep-linking
use dptree::{case, deps};
use teloxide::{
dispatching::dialogue::{self, InMemStorage},
macros::BotCommands,
prelude::*,
types::{Me, ParseMode},
};
pub type MyDialogue = Dialogue<State, InMemStorage<State>>;
pub type HandlerResult = Result<(), Box<dyn std::error::Error + Send + Sync>>;
#[derive(Clone, PartialEq, Debug, Default)]
pub enum State {
#[default]
Start,
WriteToSomeone {
id: ChatId,
},
}
#[derive(BotCommands, Clone, Debug)]
#[command(rename_rule = "lowercase")]
pub enum StartCommand {
Start(String),
}
#[tokio::main]
async fn main() {
pretty_env_logger::init();
log::info!("Starting deep linking bot...");
let bot = Bot::from_env();
let handler = dialogue::enter::<Update, InMemStorage<State>, State, _>()
.branch(
Update::filter_message()
.filter_command::<StartCommand>()
.branch(case![StartCommand::Start(start)].endpoint(start)),
)
.branch(
Update::filter_message()
.branch(case![State::WriteToSomeone { id }].endpoint(send_message)),
);
Dispatcher::builder(bot, handler)
.dependencies(deps![InMemStorage::<State>::new()])
.enable_ctrlc_handler()
.build()
.dispatch()
.await;
}
pub async fn start(
bot: Bot,
dialogue: MyDialogue,
msg: Message,
start: String, // Available from `case![StartCommand::Start(start)]`
me: Me,
) -> HandlerResult {
if start.is_empty() {
// This means that it is just a regular link like https://t.me/some_bot, or a /start command
bot.send_message(
msg.chat.id,
format!(
"Hello!\n\nThis link allows anyone to message you secretly: {}?start={}",
me.tme_url(),
msg.chat.id
),
)
.await?;
dialogue.exit().await?;
} else {
// And this means that the link is like this: https://t.me/some_bot?start=123456789,
// or a /start 123456789 command
match start.parse::<i64>() {
Ok(id) => {
bot.send_message(msg.chat.id, "Send your message:").await?;
dialogue.update(State::WriteToSomeone { id: ChatId(id) }).await?;
}
Err(_) => {
bot.send_message(msg.chat.id, "Bad link!").await?;
dialogue.exit().await?;
}
}
}
Ok(())
}
pub async fn send_message(
bot: Bot,
id: ChatId, // Available from `State::WriteToSomeone`
msg: Message,
dialogue: MyDialogue,
me: Me,
) -> HandlerResult {
match msg.text() {
Some(text) => {
// Trying to send a message to the user
let sent_result = bot
.send_message(id, format!("You have a new message!\n\n<i>{text}</i>"))
.parse_mode(ParseMode::Html)
.await;
// And if no error is returned, success!
if sent_result.is_ok() {
bot.send_message(
msg.chat.id,
format!(
"Message sent!\n\nYour link is: {}?start={}",
me.tme_url(),
msg.chat.id
),
)
.await?;
} else {
bot.send_message(msg.chat.id, "Error sending message! Maybe user blocked the bot?")
.await?;
}
dialogue.exit().await?;
}
None => {
bot.send_message(msg.chat.id, "This bot can send only text.").await?;
}
};
Ok(())
}