mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-10 20:12:25 +01:00
Merge pull request #148 from teloxide/rework-dispatching
Rework teloxide::dispatching
This commit is contained in:
commit
3290d6db59
157 changed files with 3630 additions and 1280 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -3,4 +3,9 @@
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
examples/target
|
examples/ping_pong_bot/target
|
||||||
|
examples/dialogue_bot/target
|
||||||
|
examples/multiple_handlers_bot/target
|
||||||
|
examples/admin_bot/target
|
||||||
|
examples/guess_a_number_bot/target
|
||||||
|
examples/simple_commands_bot/target
|
|
@ -20,10 +20,14 @@ mime = "0.3.16"
|
||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
thiserror = "1.0.9"
|
thiserror = "1.0.9"
|
||||||
async-trait = "0.1.22"
|
async-trait = "0.1.22"
|
||||||
duang = "0.1.2"
|
|
||||||
futures = "0.3.1"
|
futures = "0.3.1"
|
||||||
pin-project = "0.4.6"
|
pin-project = "0.4.6"
|
||||||
serde_with_macros = "1.0.1"
|
serde_with_macros = "1.0.1"
|
||||||
either = "1.5.3"
|
either = "1.5.3"
|
||||||
|
|
||||||
teloxide-macros = { path = "teloxide-macros" }
|
teloxide-macros = { path = "teloxide-macros" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
smart-default = "0.6.0"
|
||||||
|
rand = "0.7.3"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
|
9
examples/README.md
Normal file
9
examples/README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Examples
|
||||||
|
Just enter the directory (for example, `cd dialogue_bot`) and execute `cargo run` to run an example. Don't forget to initialise the `TELOXIDE_TOKEN` environmental variable.
|
||||||
|
|
||||||
|
- [ping_pong_bot](ping_pong_bot) - Answers "pong" to each incoming message.
|
||||||
|
- [simple_commands_bot](simple_commands_bot) - Shows how to deal with bot's commands.
|
||||||
|
- [guess_a_number_bot](guess_a_number_bot) - The "guess a number" game.
|
||||||
|
- [dialogue_bot](dialogue_bot) - Drive a dialogue with a user using a type-safe finite automaton.
|
||||||
|
- [admin_bot](admin_bot) - A bot, which can ban, kick, and mute on a command.
|
||||||
|
- [multiple_handlers_bot](multiple_handlers_bot) - Shows how multiple dispatcher's handlers relate to each other.
|
16
examples/admin_bot/Cargo.toml
Normal file
16
examples/admin_bot/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "admin_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["p0lunin <dmytro.polunin@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
teloxide = { path = "../../" }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
203
examples/admin_bot/src/main.rs
Normal file
203
examples/admin_bot/src/main.rs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
// TODO: simplify this and use typed command variants (see https://github.com/teloxide/teloxide/issues/152).
|
||||||
|
|
||||||
|
use teloxide::{
|
||||||
|
prelude::*, types::ChatPermissions, utils::command::BotCommand,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Derive BotCommand to parse text with a command into this enumeration.
|
||||||
|
//
|
||||||
|
// 1. rename = "lowercase" turns all the commands into lowercase letters.
|
||||||
|
// 2. `description = "..."` specifies a text before all the commands.
|
||||||
|
//
|
||||||
|
// That is, you can just call Command::descriptions() to get a description of
|
||||||
|
// your commands in this format:
|
||||||
|
// %GENERAL-DESCRIPTION%
|
||||||
|
// %PREFIX%%COMMAND% - %DESCRIPTION%
|
||||||
|
#[derive(BotCommand)]
|
||||||
|
#[command(
|
||||||
|
rename = "lowercase",
|
||||||
|
description = "Use commands in format /%command% %num% %unit%"
|
||||||
|
)]
|
||||||
|
enum Command {
|
||||||
|
#[command(description = "kick user from chat.")]
|
||||||
|
Kick,
|
||||||
|
#[command(description = "ban user in chat.")]
|
||||||
|
Ban,
|
||||||
|
#[command(description = "mute user in chat.")]
|
||||||
|
Mute,
|
||||||
|
|
||||||
|
Help,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates time of user restriction.
|
||||||
|
fn calc_restrict_time(num: i32, unit: &str) -> Result<i32, &str> {
|
||||||
|
match unit {
|
||||||
|
"h" | "hours" => Ok(num * 3600),
|
||||||
|
"m" | "minutes" => Ok(num * 60),
|
||||||
|
"s" | "seconds" => Ok(num),
|
||||||
|
_ => Err("Allowed units: h, m, s"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse arguments after a command.
|
||||||
|
fn parse_args(args: Vec<&str>) -> Result<(i32, &str), &str> {
|
||||||
|
let num = match args.get(0) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err("Use command in format /%command% %num% %unit%"),
|
||||||
|
};
|
||||||
|
let unit = match args.get(1) {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err("Use command in format /%command% %num% %unit%"),
|
||||||
|
};
|
||||||
|
|
||||||
|
match num.parse::<i32>() {
|
||||||
|
Ok(n) => Ok((n, unit)),
|
||||||
|
Err(_) => Err("input positive number!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse arguments into a user restriction duration.
|
||||||
|
fn parse_time_restrict(args: Vec<&str>) -> Result<i32, &str> {
|
||||||
|
let (num, unit) = parse_args(args)?;
|
||||||
|
calc_restrict_time(num, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ctx = DispatcherHandlerCtx<Message>;
|
||||||
|
|
||||||
|
// Mute a user with a replied message.
|
||||||
|
async fn mute_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
||||||
|
match ctx.update.reply_to_message() {
|
||||||
|
Some(msg1) => match parse_time_restrict(args) {
|
||||||
|
// Mute user temporarily...
|
||||||
|
Ok(time) => {
|
||||||
|
ctx.bot
|
||||||
|
.restrict_chat_member(
|
||||||
|
ctx.update.chat_id(),
|
||||||
|
msg1.from().expect("Must be MessageKind::Common").id,
|
||||||
|
ChatPermissions::default(),
|
||||||
|
)
|
||||||
|
.until_date(ctx.update.date + time)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
// ...or permanently
|
||||||
|
Err(_) => {
|
||||||
|
ctx.bot
|
||||||
|
.restrict_chat_member(
|
||||||
|
ctx.update.chat_id(),
|
||||||
|
msg1.from().unwrap().id,
|
||||||
|
ChatPermissions::default(),
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
ctx.reply_to("Use this command in reply to another message")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick a user with a replied message.
|
||||||
|
async fn kick_user(ctx: &Ctx) -> Result<(), RequestError> {
|
||||||
|
match ctx.update.reply_to_message() {
|
||||||
|
Some(mes) => {
|
||||||
|
// bot.unban_chat_member can also kicks a user from a group chat.
|
||||||
|
ctx.bot
|
||||||
|
.unban_chat_member(ctx.update.chat_id(), mes.from().unwrap().id)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
ctx.reply_to("Use this command in reply to another message")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ban a user with replied message.
|
||||||
|
async fn ban_user(ctx: &Ctx, args: Vec<&str>) -> Result<(), RequestError> {
|
||||||
|
match ctx.update.reply_to_message() {
|
||||||
|
Some(message) => match parse_time_restrict(args) {
|
||||||
|
// Mute user temporarily...
|
||||||
|
Ok(time) => {
|
||||||
|
ctx.bot
|
||||||
|
.kick_chat_member(
|
||||||
|
ctx.update.chat_id(),
|
||||||
|
message.from().expect("Must be MessageKind::Common").id,
|
||||||
|
)
|
||||||
|
.until_date(ctx.update.date + time)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
// ...or permanently
|
||||||
|
Err(_) => {
|
||||||
|
ctx.bot
|
||||||
|
.kick_chat_member(
|
||||||
|
ctx.update.chat_id(),
|
||||||
|
message.from().unwrap().id,
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
ctx.reply_to("Use this command in a reply to another message!")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle all messages.
|
||||||
|
async fn handle_command(ctx: Ctx) -> Result<(), RequestError> {
|
||||||
|
if ctx.update.chat.is_group() {
|
||||||
|
// The same as DispatcherHandlerResult::exit(Ok(())). If you have more
|
||||||
|
// handlers, use DispatcherHandlerResult::next(...)
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(text) = ctx.update.text() {
|
||||||
|
// Parse text into a command with args.
|
||||||
|
let (command, args): (Command, Vec<&str>) = match Command::parse(text) {
|
||||||
|
Some(tuple) => tuple,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match command {
|
||||||
|
Command::Help => {
|
||||||
|
ctx.answer(Command::descriptions()).send().await?;
|
||||||
|
}
|
||||||
|
Command::Kick => {
|
||||||
|
kick_user(&ctx).await?;
|
||||||
|
}
|
||||||
|
Command::Ban => {
|
||||||
|
ban_user(&ctx, args).await?;
|
||||||
|
}
|
||||||
|
Command::Mute => {
|
||||||
|
mute_user(&ctx, args).await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting admin_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
Dispatcher::new(bot)
|
||||||
|
.message_handler(&handle_command)
|
||||||
|
.dispatch()
|
||||||
|
.await
|
||||||
|
}
|
18
examples/dialogue_bot/Cargo.toml
Normal file
18
examples/dialogue_bot/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "dialogue_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
smart-default = "0.6.0"
|
||||||
|
parse-display = "0.1.1"
|
||||||
|
teloxide = { path = "../../" }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
209
examples/dialogue_bot/src/main.rs
Normal file
209
examples/dialogue_bot/src/main.rs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
// This is a bot that asks your full name, your age, your favourite kind of
|
||||||
|
// music and sends all the gathered information back.
|
||||||
|
//
|
||||||
|
// # Example
|
||||||
|
// ```
|
||||||
|
// - Let's start! First, what's your full name?
|
||||||
|
// - Luke Skywalker
|
||||||
|
// - What a wonderful name! Your age?
|
||||||
|
// - 26
|
||||||
|
// - Good. Now choose your favourite music
|
||||||
|
// *A keyboard of music kinds is displayed*
|
||||||
|
// *You select Metal*
|
||||||
|
// - Metal
|
||||||
|
// - Fine. Your full name: Luke Skywalker, your age: 26, your favourite music: Metal
|
||||||
|
// ```
|
||||||
|
|
||||||
|
#![allow(clippy::trivial_regex)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate smart_default;
|
||||||
|
|
||||||
|
use teloxide::{
|
||||||
|
prelude::*,
|
||||||
|
types::{KeyboardButton, ReplyKeyboardMarkup},
|
||||||
|
};
|
||||||
|
|
||||||
|
use parse_display::{Display, FromStr};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [Favourite music kinds]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Display, FromStr)]
|
||||||
|
enum FavouriteMusic {
|
||||||
|
Rock,
|
||||||
|
Metal,
|
||||||
|
Pop,
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FavouriteMusic {
|
||||||
|
fn markup() -> ReplyKeyboardMarkup {
|
||||||
|
ReplyKeyboardMarkup::default().append_row(vec![
|
||||||
|
KeyboardButton::new("Rock"),
|
||||||
|
KeyboardButton::new("Metal"),
|
||||||
|
KeyboardButton::new("Pop"),
|
||||||
|
KeyboardButton::new("Other"),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [A type-safe finite automaton]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ReceiveAgeState {
|
||||||
|
full_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ReceiveFavouriteMusicState {
|
||||||
|
data: ReceiveAgeState,
|
||||||
|
age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Display)]
|
||||||
|
#[display(
|
||||||
|
"Your full name: {data.data.full_name}, your age: {data.age}, your \
|
||||||
|
favourite music: {favourite_music}"
|
||||||
|
)]
|
||||||
|
struct ExitState {
|
||||||
|
data: ReceiveFavouriteMusicState,
|
||||||
|
favourite_music: FavouriteMusic,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SmartDefault)]
|
||||||
|
enum Dialogue {
|
||||||
|
#[default]
|
||||||
|
Start,
|
||||||
|
ReceiveFullName,
|
||||||
|
ReceiveAge(ReceiveAgeState),
|
||||||
|
ReceiveFavouriteMusic(ReceiveFavouriteMusicState),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [Control a dialogue]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
type Ctx<State> = DialogueHandlerCtx<Message, State>;
|
||||||
|
type Res = Result<DialogueStage<Dialogue>, RequestError>;
|
||||||
|
|
||||||
|
async fn start(ctx: Ctx<()>) -> Res {
|
||||||
|
ctx.answer("Let's start! First, what's your full name?")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(Dialogue::ReceiveFullName)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn full_name(ctx: Ctx<()>) -> Res {
|
||||||
|
match ctx.update.text() {
|
||||||
|
None => {
|
||||||
|
ctx.answer("Please, send me a text message!").send().await?;
|
||||||
|
next(Dialogue::ReceiveFullName)
|
||||||
|
}
|
||||||
|
Some(full_name) => {
|
||||||
|
ctx.answer("What a wonderful name! Your age?")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(Dialogue::ReceiveAge(ReceiveAgeState {
|
||||||
|
full_name: full_name.to_owned(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn age(ctx: Ctx<ReceiveAgeState>) -> Res {
|
||||||
|
match ctx.update.text().unwrap().parse() {
|
||||||
|
Ok(age) => {
|
||||||
|
ctx.answer("Good. Now choose your favourite music:")
|
||||||
|
.reply_markup(FavouriteMusic::markup())
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(Dialogue::ReceiveFavouriteMusic(
|
||||||
|
ReceiveFavouriteMusicState {
|
||||||
|
data: ctx.dialogue,
|
||||||
|
age,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
ctx.answer("Oh, please, enter a number!").send().await?;
|
||||||
|
next(Dialogue::ReceiveAge(ctx.dialogue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn favourite_music(ctx: Ctx<ReceiveFavouriteMusicState>) -> Res {
|
||||||
|
match ctx.update.text().unwrap().parse() {
|
||||||
|
Ok(favourite_music) => {
|
||||||
|
ctx.answer(format!(
|
||||||
|
"Fine. {}",
|
||||||
|
ExitState {
|
||||||
|
data: ctx.dialogue.clone(),
|
||||||
|
favourite_music
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
ctx.answer("Oh, please, enter from the keyboard!")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(Dialogue::ReceiveFavouriteMusic(ctx.dialogue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_message(ctx: Ctx<Dialogue>) -> Res {
|
||||||
|
match ctx {
|
||||||
|
DialogueHandlerCtx {
|
||||||
|
bot,
|
||||||
|
update,
|
||||||
|
dialogue: Dialogue::Start,
|
||||||
|
} => start(DialogueHandlerCtx::new(bot, update, ())).await,
|
||||||
|
DialogueHandlerCtx {
|
||||||
|
bot,
|
||||||
|
update,
|
||||||
|
dialogue: Dialogue::ReceiveFullName,
|
||||||
|
} => full_name(DialogueHandlerCtx::new(bot, update, ())).await,
|
||||||
|
DialogueHandlerCtx {
|
||||||
|
bot,
|
||||||
|
update,
|
||||||
|
dialogue: Dialogue::ReceiveAge(s),
|
||||||
|
} => age(DialogueHandlerCtx::new(bot, update, s)).await,
|
||||||
|
DialogueHandlerCtx {
|
||||||
|
bot,
|
||||||
|
update,
|
||||||
|
dialogue: Dialogue::ReceiveFavouriteMusic(s),
|
||||||
|
} => favourite_music(DialogueHandlerCtx::new(bot, update, s)).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [Run!]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
run().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting dialogue_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
Dispatcher::new(bot)
|
||||||
|
.message_handler(&DialogueDispatcher::new(|ctx| async move {
|
||||||
|
handle_message(ctx)
|
||||||
|
.await
|
||||||
|
.expect("Something wrong with the bot!")
|
||||||
|
}))
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
|
}
|
15
examples/guess_a_number_bot/Cargo.toml
Normal file
15
examples/guess_a_number_bot/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "guess_a_number_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
smart-default = "0.6.0"
|
||||||
|
rand = "0.7.3"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
teloxide = { path = "../../" }
|
116
examples/guess_a_number_bot/src/main.rs
Normal file
116
examples/guess_a_number_bot/src/main.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// This is a guess-a-number game!
|
||||||
|
//
|
||||||
|
// # Example
|
||||||
|
// ```
|
||||||
|
// - Hello
|
||||||
|
// - Let's play a game! Guess a number from 1 to 10 (inclusively).
|
||||||
|
// - 4
|
||||||
|
// - No.
|
||||||
|
// - 3
|
||||||
|
// - No.
|
||||||
|
// - Blablabla
|
||||||
|
// - Oh, please, send me a text message!
|
||||||
|
// - 111
|
||||||
|
// - Oh, please, send me a number in the range [1; 10]!
|
||||||
|
// - 5
|
||||||
|
// - Congratulations! You won!
|
||||||
|
// ```
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate smart_default;
|
||||||
|
|
||||||
|
use teloxide::prelude::*;
|
||||||
|
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [A type-safe finite automaton]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[derive(SmartDefault)]
|
||||||
|
enum Dialogue {
|
||||||
|
#[default]
|
||||||
|
Start,
|
||||||
|
ReceiveAttempt(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [Control a dialogue]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
async fn handle_message(
|
||||||
|
ctx: DialogueHandlerCtx<Message, Dialogue>,
|
||||||
|
) -> Result<DialogueStage<Dialogue>, RequestError> {
|
||||||
|
match ctx.dialogue {
|
||||||
|
Dialogue::Start => {
|
||||||
|
ctx.answer(
|
||||||
|
"Let's play a game! Guess a number from 1 to 10 (inclusively).",
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(Dialogue::ReceiveAttempt(thread_rng().gen_range(1, 11)))
|
||||||
|
}
|
||||||
|
Dialogue::ReceiveAttempt(secret) => match ctx.update.text() {
|
||||||
|
None => {
|
||||||
|
ctx.answer("Oh, please, send me a text message!")
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(ctx.dialogue)
|
||||||
|
}
|
||||||
|
Some(text) => match text.parse::<u8>() {
|
||||||
|
Ok(attempt) => match attempt {
|
||||||
|
x if !(1..=10).contains(&x) => {
|
||||||
|
ctx.answer(
|
||||||
|
"Oh, please, send me a number in the range [1; \
|
||||||
|
10]!",
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(ctx.dialogue)
|
||||||
|
}
|
||||||
|
x if x == secret => {
|
||||||
|
ctx.answer("Congratulations! You won!").send().await?;
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
ctx.answer("No.").send().await?;
|
||||||
|
next(ctx.dialogue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
ctx.answer(
|
||||||
|
"Oh, please, send me a number in the range [1; 10]!",
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
next(ctx.dialogue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [Run!]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
run().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting guess_a_number_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
Dispatcher::new(bot)
|
||||||
|
.message_handler(&DialogueDispatcher::new(|ctx| async move {
|
||||||
|
handle_message(ctx)
|
||||||
|
.await
|
||||||
|
.expect("Something wrong with the bot!")
|
||||||
|
}))
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
|
}
|
13
examples/multiple_handlers_bot/Cargo.toml
Normal file
13
examples/multiple_handlers_bot/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "multiple_handlers_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
teloxide = { path = "../../" }
|
49
examples/multiple_handlers_bot/src/main.rs
Normal file
49
examples/multiple_handlers_bot/src/main.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// This example demonstrates the ability of Dispatcher to deal with multiple
|
||||||
|
// handlers.
|
||||||
|
|
||||||
|
use teloxide::prelude::*;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
run().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting multiple_handlers_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
// Create a dispatcher with multiple handlers of different types. This will
|
||||||
|
// print One! and Two! on every incoming UpdateKind::Message.
|
||||||
|
Dispatcher::<RequestError>::new(bot)
|
||||||
|
// This is the first UpdateKind::Message handler, which will be called
|
||||||
|
// after the Update handler below.
|
||||||
|
.message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
log::info!("Two!");
|
||||||
|
DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
})
|
||||||
|
// Remember: handler of Update are called first.
|
||||||
|
.update_handler(&|ctx: DispatcherHandlerCtx<Update>| async move {
|
||||||
|
log::info!("One!");
|
||||||
|
DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
})
|
||||||
|
// This handler will be called right after the first UpdateKind::Message
|
||||||
|
// handler, because it is registered after.
|
||||||
|
.message_handler(&|_ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
// The same as DispatcherHandlerResult::exit(Ok(()))
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
// This handler will never be called, because the UpdateKind::Message
|
||||||
|
// handler above terminates the pipeline.
|
||||||
|
.message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
log::info!("This will never be printed!");
|
||||||
|
DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
})
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Note: if this bot receive, for example, UpdateKind::ChannelPost, it will
|
||||||
|
// only print "One!", because the UpdateKind::Message handlers will not be
|
||||||
|
// called.
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
use futures::stream::StreamExt;
|
|
||||||
use teloxide::{
|
|
||||||
dispatching::{
|
|
||||||
chat::{ChatUpdate, ChatUpdateKind, Dispatcher},
|
|
||||||
update_listeners::polling_default,
|
|
||||||
SessionState,
|
|
||||||
},
|
|
||||||
requests::Request,
|
|
||||||
Bot,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let bot = &Bot::new("1061598315:AAErEDodTsrqD3UxA_EvFyEfXbKA6DT25G0");
|
|
||||||
let mut updater = Box::pin(polling_default(bot));
|
|
||||||
let handler = |_, upd: ChatUpdate| async move {
|
|
||||||
if let ChatUpdateKind::Message(m) = upd.kind {
|
|
||||||
let msg = bot.send_message(m.chat.id, "pong");
|
|
||||||
msg.send().await.unwrap();
|
|
||||||
}
|
|
||||||
SessionState::Continue(())
|
|
||||||
};
|
|
||||||
let mut dp = Dispatcher::<'_, (), _>::new(handler);
|
|
||||||
println!("Starting the message handler.");
|
|
||||||
loop {
|
|
||||||
let u = updater.next().await.unwrap();
|
|
||||||
match u {
|
|
||||||
Err(e) => eprintln!("Error: {}", e),
|
|
||||||
Ok(u) => {
|
|
||||||
let _ = dp.dispatch(u).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
16
examples/ping_pong_bot/Cargo.toml
Normal file
16
examples/ping_pong_bot/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "ping_pong_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
teloxide = { path = "../../" }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
23
examples/ping_pong_bot/src/main.rs
Normal file
23
examples/ping_pong_bot/src/main.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use teloxide::prelude::*;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
run().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting ping_pong_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
// Create a dispatcher with a single message handler that answers "pong" to
|
||||||
|
// each incoming message.
|
||||||
|
Dispatcher::<RequestError>::new(bot)
|
||||||
|
.message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
ctx.answer("pong").send().await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
|
}
|
14
examples/simple_commands_bot/Cargo.toml
Normal file
14
examples/simple_commands_bot/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "simple_commands_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.8"
|
||||||
|
tokio = "0.2.9"
|
||||||
|
rand = "0.7.3"
|
||||||
|
pretty_env_logger = "0.4.0"
|
||||||
|
teloxide = { path = "../../" }
|
63
examples/simple_commands_bot/src/main.rs
Normal file
63
examples/simple_commands_bot/src/main.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use teloxide::{prelude::*, utils::command::BotCommand};
|
||||||
|
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
#[derive(BotCommand)]
|
||||||
|
#[command(rename = "lowercase", description = "These commands are supported:")]
|
||||||
|
enum Command {
|
||||||
|
#[command(description = "display this text.")]
|
||||||
|
Help,
|
||||||
|
#[command(description = "be a cat.")]
|
||||||
|
Meow,
|
||||||
|
#[command(description = "generate a random number within [0; 1).")]
|
||||||
|
Generate,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_command(
|
||||||
|
ctx: DispatcherHandlerCtx<Message>,
|
||||||
|
) -> Result<(), RequestError> {
|
||||||
|
let text = match ctx.update.text() {
|
||||||
|
Some(text) => text,
|
||||||
|
None => {
|
||||||
|
log::info!("Received a message, but not text.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let command = match Command::parse(text) {
|
||||||
|
Some((command, _)) => command,
|
||||||
|
None => {
|
||||||
|
log::info!("Received a text message, but not a command.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match command {
|
||||||
|
Command::Help => ctx.answer(Command::descriptions()).send().await?,
|
||||||
|
Command::Generate => {
|
||||||
|
ctx.answer(thread_rng().gen_range(0.0, 1.0).to_string())
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Command::Meow => ctx.answer("I am a cat! Meow!").send().await?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
run().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
teloxide::enable_logging!();
|
||||||
|
log::info!("Starting simple_commands_bot!");
|
||||||
|
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
Dispatcher::<RequestError>::new(bot)
|
||||||
|
.message_handler(&handle_command)
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
|
}
|
346
src/bot/api.rs
346
src/bot/api.rs
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod download;
|
mod download;
|
||||||
|
@ -11,24 +12,58 @@ pub struct Bot {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bot {
|
impl Bot {
|
||||||
pub fn new<S>(token: S) -> Self
|
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a
|
||||||
where
|
/// bot's token) and the default [`reqwest::Client`].
|
||||||
S: Into<String>,
|
///
|
||||||
{
|
/// # Panics
|
||||||
Bot {
|
/// If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||||
token: token.into(),
|
///
|
||||||
client: Client::new(),
|
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||||
}
|
pub fn from_env() -> Arc<Self> {
|
||||||
|
Self::new(
|
||||||
|
std::env::var("TELOXIDE_TOKEN")
|
||||||
|
.expect("Cannot get the TELOXIDE_TOKEN env variable"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_client<S>(token: S, client: Client) -> Self
|
/// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a
|
||||||
|
/// bot's token) and your [`reqwest::Client`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If cannot get the `TELOXIDE_TOKEN` environmental variable.
|
||||||
|
///
|
||||||
|
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||||
|
pub fn from_env_with_client(client: Client) -> Arc<Self> {
|
||||||
|
Self::with_client(
|
||||||
|
std::env::var("TELOXIDE_TOKEN")
|
||||||
|
.expect("Cannot get the TELOXIDE_TOKEN env variable"),
|
||||||
|
client,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Bot` with the specified token and the default
|
||||||
|
/// [`reqwest::Client`].
|
||||||
|
///
|
||||||
|
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||||
|
pub fn new<S>(token: S) -> Arc<Self>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
Bot {
|
Self::with_client(token, Client::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Bot` with the specified token and your
|
||||||
|
/// [`reqwest::Client`].
|
||||||
|
///
|
||||||
|
/// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html
|
||||||
|
pub fn with_client<S>(token: S, client: Client) -> Arc<Self>
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
Arc::new(Self {
|
||||||
token: token.into(),
|
token: token.into(),
|
||||||
client,
|
client,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::types::{CallbackQuery, Message};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct ChatUpdate {
|
|
||||||
pub id: i32,
|
|
||||||
|
|
||||||
pub kind: ChatUpdateKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum ChatUpdateKind {
|
|
||||||
Message(Message),
|
|
||||||
EditedMessage(Message),
|
|
||||||
CallbackQuery(CallbackQuery),
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
use super::{
|
|
||||||
super::DispatchResult,
|
|
||||||
storage::{InMemStorage, Storage},
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
dispatching::{
|
|
||||||
chat::{ChatUpdate, ChatUpdateKind},
|
|
||||||
Handler, SessionState,
|
|
||||||
},
|
|
||||||
types::{Update, UpdateKind},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A dispatcher that dispatches updates from chats.
|
|
||||||
pub struct Dispatcher<'a, Session, H> {
|
|
||||||
storage: Box<dyn Storage<Session> + 'a>,
|
|
||||||
handler: H,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Session, H> Dispatcher<'a, Session, H>
|
|
||||||
where
|
|
||||||
Session: Default + 'a,
|
|
||||||
H: Handler<Session, ChatUpdate>,
|
|
||||||
{
|
|
||||||
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
|
|
||||||
/// (a default storage).
|
|
||||||
///
|
|
||||||
/// [`InMemStorage`]: crate::dispatching::private::InMemStorage
|
|
||||||
pub fn new(handler: H) -> Self {
|
|
||||||
Self {
|
|
||||||
storage: Box::new(InMemStorage::default()),
|
|
||||||
handler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a dispatcher with the specified `handler` and `storage`.
|
|
||||||
pub fn with_storage<Stg>(handler: H, storage: Stg) -> Self
|
|
||||||
where
|
|
||||||
Stg: Storage<Session> + 'a,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
storage: Box::new(storage),
|
|
||||||
handler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dispatches a single `update`.
|
|
||||||
///
|
|
||||||
/// ## Returns
|
|
||||||
/// Returns [`DispatchResult::Handled`] if `update` was supplied to a
|
|
||||||
/// handler, and [`DispatchResult::Unhandled`] if it was an update not
|
|
||||||
/// from a chat.
|
|
||||||
///
|
|
||||||
/// [`DispatchResult::Handled`]: crate::dispatching::DispatchResult::Handled
|
|
||||||
/// [`DispatchResult::Unhandled`]:
|
|
||||||
/// crate::dispatching::DispatchResult::Unhandled
|
|
||||||
pub async fn dispatch(&mut self, update: Update) -> DispatchResult {
|
|
||||||
let chat_update = match update.kind {
|
|
||||||
UpdateKind::Message(msg) => ChatUpdate {
|
|
||||||
id: update.id,
|
|
||||||
kind: ChatUpdateKind::Message(msg),
|
|
||||||
},
|
|
||||||
UpdateKind::EditedMessage(msg) => ChatUpdate {
|
|
||||||
id: update.id,
|
|
||||||
kind: ChatUpdateKind::EditedMessage(msg),
|
|
||||||
},
|
|
||||||
UpdateKind::CallbackQuery(query) => ChatUpdate {
|
|
||||||
id: update.id,
|
|
||||||
kind: ChatUpdateKind::CallbackQuery(query),
|
|
||||||
},
|
|
||||||
_ => return DispatchResult::Unhandled,
|
|
||||||
};
|
|
||||||
|
|
||||||
let chat_id = match &chat_update.kind {
|
|
||||||
ChatUpdateKind::Message(msg) => msg.chat.id,
|
|
||||||
ChatUpdateKind::EditedMessage(msg) => msg.chat.id,
|
|
||||||
ChatUpdateKind::CallbackQuery(query) => match &query.message {
|
|
||||||
None => return DispatchResult::Unhandled,
|
|
||||||
Some(msg) => msg.chat.id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let session = self
|
|
||||||
.storage
|
|
||||||
.remove_session(chat_id)
|
|
||||||
.await
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if let SessionState::Continue(session) =
|
|
||||||
self.handler.handle(session, chat_update).await
|
|
||||||
{
|
|
||||||
if self
|
|
||||||
.storage
|
|
||||||
.update_session(chat_id, session)
|
|
||||||
.await
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
panic!(
|
|
||||||
"We previously storage.remove_session() so \
|
|
||||||
storage.update_session() must return None"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DispatchResult::Handled
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
//! Dispatching updates from chats.
|
|
||||||
//!
|
|
||||||
//! There are four main components:
|
|
||||||
//!
|
|
||||||
//! 1. Your session type `Session`, which designates a dialogue state at the
|
|
||||||
//! current moment.
|
|
||||||
//! 2. [`Storage`] that encapsulates all the sessions.
|
|
||||||
//! 3. Your handler of type `H: async Fn(Session, Update) ->
|
|
||||||
//! HandleResult<Session>` that receives an update and turns your session into
|
|
||||||
//! the next state.
|
|
||||||
//! 4. [`Dispatcher`], which encapsulates your handler and [`Storage`], and has
|
|
||||||
//! the [`dispatch(Update) -> DispatchResult`] function.
|
|
||||||
//!
|
|
||||||
//! Every time you call [`.dispatch(update)`] on your dispatcher, the following
|
|
||||||
//! steps are executed:
|
|
||||||
//!
|
|
||||||
//! 1. If a supplied update is not from a chat, return
|
|
||||||
//! [`DispatchResult::Unhandled`].
|
|
||||||
//! 2. If a storage doesn't contain a session from this chat, supply
|
|
||||||
//! `Session::default()` into you handler, otherwise, supply the previous
|
|
||||||
//! session.
|
|
||||||
//! 3. If a handler has returned [`SessionState::Terminate`], remove the
|
|
||||||
//! session from a storage, otherwise force the storage to update the session.
|
|
||||||
//!
|
|
||||||
//! [`Storage`]: crate::dispatching::private::Storage
|
|
||||||
//! [`Dispatcher`]: crate::dispatching::private::Dispatcher
|
|
||||||
//! [`dispatch(Update) -> DispatchResult`]:
|
|
||||||
//! crate::dispatching::private::Dispatcher::dispatch
|
|
||||||
//! [`.dispatch(update)`]: crate::dispatching::private::Dispatcher::dispatch
|
|
||||||
//! [`DispatchResult::Unhandled`]: crate::dispatching::DispatchResult::Unhandled
|
|
||||||
//! [`SessionState::Terminate`]: crate::dispatching::SessionState::Terminate
|
|
||||||
|
|
||||||
// TODO: examples
|
|
||||||
|
|
||||||
mod chat_update;
|
|
||||||
mod dispatcher;
|
|
||||||
mod storage;
|
|
||||||
|
|
||||||
pub use chat_update::*;
|
|
||||||
pub use dispatcher::*;
|
|
||||||
pub use storage::*;
|
|
|
@ -1,32 +0,0 @@
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use super::Storage;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
/// A memory storage based on a hash map. Stores all the sessions directly in
|
|
||||||
/// RAM.
|
|
||||||
///
|
|
||||||
/// ## Note
|
|
||||||
/// All the sessions will be lost after you restart your bot. If you need to
|
|
||||||
/// store them somewhere on a drive, you need to implement a storage
|
|
||||||
/// communicating with a DB.
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
|
||||||
pub struct InMemStorage<Session> {
|
|
||||||
map: HashMap<i64, Session>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
|
||||||
#[async_trait]
|
|
||||||
impl<Session> Storage<Session> for InMemStorage<Session> {
|
|
||||||
async fn remove_session(&mut self, chat_id: i64) -> Option<Session> {
|
|
||||||
self.map.remove(&chat_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_session(
|
|
||||||
&mut self,
|
|
||||||
chat_id: i64,
|
|
||||||
state: Session,
|
|
||||||
) -> Option<Session> {
|
|
||||||
self.map.insert(chat_id, state)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
mod in_mem_storage;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
pub use in_mem_storage::InMemStorage;
|
|
||||||
|
|
||||||
/// A storage of sessions.
|
|
||||||
///
|
|
||||||
/// You can implement this trait for a structure that communicates with a DB and
|
|
||||||
/// be sure that after you restart your bot, all the sessions won't be lost.
|
|
||||||
///
|
|
||||||
/// For a storage based on a simple hash map, see [`InMemStorage`].
|
|
||||||
///
|
|
||||||
/// [`InMemStorage`]: crate::dispatching::private::InMemStorage
|
|
||||||
#[async_trait(?Send)]
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Storage<Session> {
|
|
||||||
/// Removes a session with the specified `chat_id`.
|
|
||||||
///
|
|
||||||
/// Returns `None` if there wasn't such a session, `Some(session)` if a
|
|
||||||
/// `session` was deleted.
|
|
||||||
async fn remove_session(&mut self, chat_id: i64) -> Option<Session>;
|
|
||||||
|
|
||||||
/// Updates a session with the specified `chat_id`.
|
|
||||||
///
|
|
||||||
/// Returns `None` if there wasn't such a session, `Some(session)` if a
|
|
||||||
/// `session` was updated.
|
|
||||||
async fn update_session(
|
|
||||||
&mut self,
|
|
||||||
chat_id: i64,
|
|
||||||
session: Session,
|
|
||||||
) -> Option<Session>;
|
|
||||||
}
|
|
31
src/dispatching/ctx_handlers.rs
Normal file
31
src/dispatching/ctx_handlers.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use std::{future::Future, pin::Pin};
|
||||||
|
|
||||||
|
/// An asynchronous handler of a context.
|
||||||
|
///
|
||||||
|
/// See [the module-level documentation for the design
|
||||||
|
/// overview](crate::dispatching).
|
||||||
|
pub trait CtxHandler<Ctx, Output> {
|
||||||
|
#[must_use]
|
||||||
|
fn handle_ctx<'a>(
|
||||||
|
&'a self,
|
||||||
|
ctx: Ctx,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Output> + 'a>>
|
||||||
|
where
|
||||||
|
Ctx: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Ctx, Output, F, Fut> CtxHandler<Ctx, Output> for F
|
||||||
|
where
|
||||||
|
F: Fn(Ctx) -> Fut,
|
||||||
|
Fut: Future<Output = Output>,
|
||||||
|
{
|
||||||
|
fn handle_ctx<'a>(
|
||||||
|
&'a self,
|
||||||
|
ctx: Ctx,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Fut::Output> + 'a>>
|
||||||
|
where
|
||||||
|
Ctx: 'a,
|
||||||
|
{
|
||||||
|
Box::pin(async move { self(ctx).await })
|
||||||
|
}
|
||||||
|
}
|
97
src/dispatching/dialogue/dialogue_dispatcher.rs
Normal file
97
src/dispatching/dialogue/dialogue_dispatcher.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use crate::dispatching::{
|
||||||
|
dialogue::{
|
||||||
|
DialogueHandlerCtx, DialogueStage, GetChatId, InMemStorage, Storage,
|
||||||
|
},
|
||||||
|
CtxHandler, DispatcherHandlerCtx,
|
||||||
|
};
|
||||||
|
use std::{future::Future, pin::Pin};
|
||||||
|
|
||||||
|
/// A dispatcher of dialogues.
|
||||||
|
///
|
||||||
|
/// Note that `DialogueDispatcher` implements `CtxHandler`, so you can just put
|
||||||
|
/// an instance of this dispatcher into the [`Dispatcher`]'s methods.
|
||||||
|
///
|
||||||
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
|
pub struct DialogueDispatcher<'a, D, H> {
|
||||||
|
storage: Box<dyn Storage<D> + 'a>,
|
||||||
|
handler: H,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D, H> DialogueDispatcher<'a, D, H>
|
||||||
|
where
|
||||||
|
D: Default + 'a,
|
||||||
|
{
|
||||||
|
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
|
||||||
|
/// (a default storage).
|
||||||
|
///
|
||||||
|
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(handler: H) -> Self {
|
||||||
|
Self {
|
||||||
|
storage: Box::new(InMemStorage::default()),
|
||||||
|
handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a dispatcher with the specified `handler` and `storage`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_storage<Stg>(handler: H, storage: Stg) -> Self
|
||||||
|
where
|
||||||
|
Stg: Storage<D> + 'a,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
storage: Box::new(storage),
|
||||||
|
handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D, H, Upd> CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), ()>>
|
||||||
|
for DialogueDispatcher<'a, D, H>
|
||||||
|
where
|
||||||
|
H: CtxHandler<DialogueHandlerCtx<Upd, D>, DialogueStage<D>>,
|
||||||
|
Upd: GetChatId,
|
||||||
|
D: Default,
|
||||||
|
{
|
||||||
|
fn handle_ctx<'b>(
|
||||||
|
&'b self,
|
||||||
|
ctx: DispatcherHandlerCtx<Upd>,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Result<(), ()>> + 'b>>
|
||||||
|
where
|
||||||
|
Upd: 'b,
|
||||||
|
{
|
||||||
|
Box::pin(async move {
|
||||||
|
let chat_id = ctx.update.chat_id();
|
||||||
|
|
||||||
|
let dialogue = self
|
||||||
|
.storage
|
||||||
|
.remove_dialogue(chat_id)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if let DialogueStage::Next(new_dialogue) = self
|
||||||
|
.handler
|
||||||
|
.handle_ctx(DialogueHandlerCtx {
|
||||||
|
bot: ctx.bot,
|
||||||
|
update: ctx.update,
|
||||||
|
dialogue,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.storage
|
||||||
|
.update_dialogue(chat_id, new_dialogue)
|
||||||
|
.await
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"We previously storage.remove_dialogue() so \
|
||||||
|
storage.update_dialogue() must return None"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
190
src/dispatching/dialogue/dialogue_handler_ctx.rs
Normal file
190
src/dispatching/dialogue/dialogue_handler_ctx.rs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
use crate::{
|
||||||
|
dispatching::dialogue::GetChatId,
|
||||||
|
requests::{
|
||||||
|
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage,
|
||||||
|
PinChatMessage, SendAnimation, SendAudio, SendContact, SendDocument,
|
||||||
|
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker,
|
||||||
|
SendVenue, SendVideo, SendVideoNote, SendVoice,
|
||||||
|
},
|
||||||
|
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
|
||||||
|
Bot,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// A context of a [`DialogueDispatcher`]'s message handler.
|
||||||
|
///
|
||||||
|
/// [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||||
|
pub struct DialogueHandlerCtx<Upd, D> {
|
||||||
|
pub bot: Arc<Bot>,
|
||||||
|
pub update: Upd,
|
||||||
|
pub dialogue: D,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Upd, D> DialogueHandlerCtx<Upd, D> {
|
||||||
|
/// Creates a new instance with the provided fields.
|
||||||
|
pub fn new(bot: Arc<Bot>, update: Upd, dialogue: D) -> Self {
|
||||||
|
Self {
|
||||||
|
bot,
|
||||||
|
update,
|
||||||
|
dialogue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance by substituting a dialogue and preserving
|
||||||
|
/// `self.bot` and `self.update`.
|
||||||
|
pub fn with_new_dialogue<Nd>(
|
||||||
|
self,
|
||||||
|
new_dialogue: Nd,
|
||||||
|
) -> DialogueHandlerCtx<Upd, Nd> {
|
||||||
|
DialogueHandlerCtx {
|
||||||
|
bot: self.bot,
|
||||||
|
update: self.update,
|
||||||
|
dialogue: new_dialogue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Upd, D> GetChatId for DialogueHandlerCtx<Upd, D>
|
||||||
|
where
|
||||||
|
Upd: GetChatId,
|
||||||
|
{
|
||||||
|
fn chat_id(&self) -> i64 {
|
||||||
|
self.update.chat_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> DialogueHandlerCtx<Message, D> {
|
||||||
|
pub fn answer<T>(&self, text: T) -> SendMessage
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.send_message(self.chat_id(), text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply_to<T>(&self, text: T) -> SendMessage
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.send_message(self.chat_id(), text)
|
||||||
|
.reply_to_message_id(self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
|
||||||
|
self.bot.send_photo(self.update.chat.id, photo)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_audio(&self, audio: InputFile) -> SendAudio {
|
||||||
|
self.bot.send_audio(self.update.chat.id, audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_animation(&self, animation: InputFile) -> SendAnimation {
|
||||||
|
self.bot.send_animation(self.update.chat.id, animation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_document(&self, document: InputFile) -> SendDocument {
|
||||||
|
self.bot.send_document(self.update.chat.id, document)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_video(&self, video: InputFile) -> SendVideo {
|
||||||
|
self.bot.send_video(self.update.chat.id, video)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_voice(&self, voice: InputFile) -> SendVoice {
|
||||||
|
self.bot.send_voice(self.update.chat.id, voice)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_media_group<T>(&self, media_group: T) -> SendMediaGroup
|
||||||
|
where
|
||||||
|
T: Into<Vec<InputMedia>>,
|
||||||
|
{
|
||||||
|
self.bot.send_media_group(self.update.chat.id, media_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_location(
|
||||||
|
&self,
|
||||||
|
latitude: f32,
|
||||||
|
longitude: f32,
|
||||||
|
) -> SendLocation {
|
||||||
|
self.bot
|
||||||
|
.send_location(self.update.chat.id, latitude, longitude)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_venue<T, U>(
|
||||||
|
&self,
|
||||||
|
latitude: f32,
|
||||||
|
longitude: f32,
|
||||||
|
title: T,
|
||||||
|
address: U,
|
||||||
|
) -> SendVenue
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.send_venue(
|
||||||
|
self.update.chat.id,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
title,
|
||||||
|
address,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
|
||||||
|
self.bot.send_video_note(self.update.chat.id, video_note)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_contact<T, U>(
|
||||||
|
&self,
|
||||||
|
phone_number: T,
|
||||||
|
first_name: U,
|
||||||
|
) -> SendContact
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.send_contact(self.chat_id(), phone_number, first_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_sticker<T>(&self, sticker: InputFile) -> SendSticker {
|
||||||
|
self.bot.send_sticker(self.update.chat.id, sticker)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forward_to<T>(&self, chat_id: T) -> ForwardMessage
|
||||||
|
where
|
||||||
|
T: Into<ChatId>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.forward_message(chat_id, self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_message_text<T>(&self, text: T) -> EditMessageText
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.edit_message_text(
|
||||||
|
ChatOrInlineMessage::Chat {
|
||||||
|
chat_id: self.update.chat.id.into(),
|
||||||
|
message_id: self.update.id,
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_message_caption(&self) -> EditMessageCaption {
|
||||||
|
self.bot.edit_message_caption(ChatOrInlineMessage::Chat {
|
||||||
|
chat_id: self.update.chat.id.into(),
|
||||||
|
message_id: self.update.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_message(&self) -> DeleteMessage {
|
||||||
|
self.bot.delete_message(self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pin_message(&self) -> PinChatMessage {
|
||||||
|
self.bot
|
||||||
|
.pin_chat_message(self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
}
|
16
src/dispatching/dialogue/dialogue_stage.rs
Normal file
16
src/dispatching/dialogue/dialogue_stage.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/// Continue or terminate a dialogue.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||||
|
pub enum DialogueStage<D> {
|
||||||
|
Next(D),
|
||||||
|
Exit,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A shortcut for `Ok(DialogueStage::Next(dialogue))`.
|
||||||
|
pub fn next<E, D>(dialogue: D) -> Result<DialogueStage<D>, E> {
|
||||||
|
Ok(DialogueStage::Next(dialogue))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A shortcut for `Ok(DialogueStage::Exit)`.
|
||||||
|
pub fn exit<E, D>() -> Result<DialogueStage<D>, E> {
|
||||||
|
Ok(DialogueStage::Exit)
|
||||||
|
}
|
13
src/dispatching/dialogue/get_chat_id.rs
Normal file
13
src/dispatching/dialogue/get_chat_id.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use crate::types::Message;
|
||||||
|
|
||||||
|
/// Something that has a chat ID.
|
||||||
|
pub trait GetChatId {
|
||||||
|
#[must_use]
|
||||||
|
fn chat_id(&self) -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetChatId for Message {
|
||||||
|
fn chat_id(&self) -> i64 {
|
||||||
|
self.chat.id
|
||||||
|
}
|
||||||
|
}
|
48
src/dispatching/dialogue/mod.rs
Normal file
48
src/dispatching/dialogue/mod.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//! Dealing with dialogues.
|
||||||
|
//!
|
||||||
|
//! There are four main components:
|
||||||
|
//!
|
||||||
|
//! 1. Your type `D`, which designates a dialogue state at the current
|
||||||
|
//! moment.
|
||||||
|
//! 2. [`Storage`], which encapsulates all the dialogues.
|
||||||
|
//! 3. Your handler, which receives an update and turns your dialogue into the
|
||||||
|
//! next state.
|
||||||
|
//! 4. [`DialogueDispatcher`], which encapsulates your handler, [`Storage`],
|
||||||
|
//! and implements [`CtxHandler`].
|
||||||
|
//!
|
||||||
|
//! You supply [`DialogueDispatcher`] into [`Dispatcher`]. Every time
|
||||||
|
//! [`Dispatcher`] calls `DialogueDispatcher::handle_ctx(...)`, the following
|
||||||
|
//! steps are executed:
|
||||||
|
//!
|
||||||
|
//! 1. If a storage doesn't contain a dialogue from this chat, supply
|
||||||
|
//! `D::default()` into you handler, otherwise, supply the saved session
|
||||||
|
//! from this chat.
|
||||||
|
//! 2. If a handler has returned [`DialogueStage::Exit`], remove the session
|
||||||
|
//! from the storage, otherwise ([`DialogueStage::Next`]) force the storage to
|
||||||
|
//! update the session.
|
||||||
|
//!
|
||||||
|
//! Please, see [examples/dialogue_bot] as an example.
|
||||||
|
//!
|
||||||
|
//! [`Storage`]: crate::dispatching::dialogue::Storage
|
||||||
|
//! [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||||
|
//! [`DialogueStage::Exit`]:
|
||||||
|
//! crate::dispatching::dialogue::DialogueStage::Exit
|
||||||
|
//! [`DialogueStage::Next`]: crate::dispatching::dialogue::DialogueStage::Next
|
||||||
|
//! [`CtxHandler`]: crate::dispatching::CtxHandler
|
||||||
|
//! [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
|
//! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/tree/dev/examples/dialogue_bot
|
||||||
|
|
||||||
|
#![allow(clippy::module_inception)]
|
||||||
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
|
mod dialogue_dispatcher;
|
||||||
|
mod dialogue_handler_ctx;
|
||||||
|
mod dialogue_stage;
|
||||||
|
mod get_chat_id;
|
||||||
|
mod storage;
|
||||||
|
|
||||||
|
pub use dialogue_dispatcher::DialogueDispatcher;
|
||||||
|
pub use dialogue_handler_ctx::DialogueHandlerCtx;
|
||||||
|
pub use dialogue_stage::{exit, next, DialogueStage};
|
||||||
|
pub use get_chat_id::GetChatId;
|
||||||
|
pub use storage::{InMemStorage, Storage};
|
29
src/dispatching/dialogue/storage/in_mem_storage.rs
Normal file
29
src/dispatching/dialogue/storage/in_mem_storage.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use super::Storage;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
/// A memory storage based on a hash map. Stores all the dialogues directly in
|
||||||
|
/// RAM.
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
/// All the dialogues will be lost after you restart your bot. If you need to
|
||||||
|
/// store them somewhere on a drive, you need to implement a storage
|
||||||
|
/// communicating with a DB.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct InMemStorage<D> {
|
||||||
|
map: Mutex<HashMap<i64, D>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait(?Send)]
|
||||||
|
#[async_trait]
|
||||||
|
impl<D> Storage<D> for InMemStorage<D> {
|
||||||
|
async fn remove_dialogue(&self, chat_id: i64) -> Option<D> {
|
||||||
|
self.map.lock().await.remove(&chat_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_dialogue(&self, chat_id: i64, dialogue: D) -> Option<D> {
|
||||||
|
self.map.lock().await.insert(chat_id, dialogue)
|
||||||
|
}
|
||||||
|
}
|
28
src/dispatching/dialogue/storage/mod.rs
Normal file
28
src/dispatching/dialogue/storage/mod.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
mod in_mem_storage;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
pub use in_mem_storage::InMemStorage;
|
||||||
|
|
||||||
|
/// A storage of dialogues.
|
||||||
|
///
|
||||||
|
/// You can implement this trait for a structure that communicates with a DB and
|
||||||
|
/// be sure that after you restart your bot, all the dialogues won't be lost.
|
||||||
|
///
|
||||||
|
/// For a storage based on a simple hash map, see [`InMemStorage`].
|
||||||
|
///
|
||||||
|
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
|
||||||
|
#[async_trait(?Send)]
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Storage<D> {
|
||||||
|
/// Removes a dialogue with the specified `chat_id`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there wasn't such a dialogue, `Some(dialogue)` if a
|
||||||
|
/// `dialogue` was deleted.
|
||||||
|
async fn remove_dialogue(&self, chat_id: i64) -> Option<D>;
|
||||||
|
|
||||||
|
/// Updates a dialogue with the specified `chat_id`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there wasn't such a dialogue, `Some(dialogue)` if a
|
||||||
|
/// `dialogue` was updated.
|
||||||
|
async fn update_dialogue(&self, chat_id: i64, dialogue: D) -> Option<D>;
|
||||||
|
}
|
381
src/dispatching/dispatcher.rs
Normal file
381
src/dispatching/dispatcher.rs
Normal file
|
@ -0,0 +1,381 @@
|
||||||
|
use crate::{
|
||||||
|
dispatching::{
|
||||||
|
error_handlers::ErrorHandler, update_listeners,
|
||||||
|
update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx,
|
||||||
|
DispatcherHandlerResult, LoggingErrorHandler,
|
||||||
|
},
|
||||||
|
types::{
|
||||||
|
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
|
||||||
|
PollAnswer, PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
|
||||||
|
},
|
||||||
|
Bot, RequestError,
|
||||||
|
};
|
||||||
|
use futures::{stream, StreamExt};
|
||||||
|
use std::{fmt::Debug, future::Future, sync::Arc};
|
||||||
|
|
||||||
|
type Handlers<'a, Upd, HandlerE> = Vec<
|
||||||
|
Box<
|
||||||
|
dyn CtxHandler<
|
||||||
|
DispatcherHandlerCtx<Upd>,
|
||||||
|
DispatcherHandlerResult<Upd, HandlerE>,
|
||||||
|
> + 'a,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// One dispatcher to rule them all.
|
||||||
|
///
|
||||||
|
/// See [the module-level documentation for the design
|
||||||
|
/// overview](crate::dispatching).
|
||||||
|
// HandlerE=RequestError doesn't work now, because of very poor type inference.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/27336 for more details.
|
||||||
|
pub struct Dispatcher<'a, HandlerE = RequestError> {
|
||||||
|
bot: Arc<Bot>,
|
||||||
|
|
||||||
|
handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>,
|
||||||
|
|
||||||
|
update_handlers: Handlers<'a, Update, HandlerE>,
|
||||||
|
message_handlers: Handlers<'a, Message, HandlerE>,
|
||||||
|
edited_message_handlers: Handlers<'a, Message, HandlerE>,
|
||||||
|
channel_post_handlers: Handlers<'a, Message, HandlerE>,
|
||||||
|
edited_channel_post_handlers: Handlers<'a, Message, HandlerE>,
|
||||||
|
inline_query_handlers: Handlers<'a, InlineQuery, HandlerE>,
|
||||||
|
chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, HandlerE>,
|
||||||
|
callback_query_handlers: Handlers<'a, CallbackQuery, HandlerE>,
|
||||||
|
shipping_query_handlers: Handlers<'a, ShippingQuery, HandlerE>,
|
||||||
|
pre_checkout_query_handlers: Handlers<'a, PreCheckoutQuery, HandlerE>,
|
||||||
|
poll_handlers: Handlers<'a, Poll, HandlerE>,
|
||||||
|
poll_answer_handlers: Handlers<'a, PollAnswer, HandlerE>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, HandlerE> Dispatcher<'a, HandlerE>
|
||||||
|
where
|
||||||
|
HandlerE: Debug + 'a,
|
||||||
|
{
|
||||||
|
/// Constructs a new dispatcher with this `bot`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(bot: Arc<Bot>) -> Self {
|
||||||
|
Self {
|
||||||
|
bot,
|
||||||
|
handlers_error_handler: Box::new(LoggingErrorHandler::new(
|
||||||
|
"An error from a Dispatcher's handler",
|
||||||
|
)),
|
||||||
|
update_handlers: Vec::new(),
|
||||||
|
message_handlers: Vec::new(),
|
||||||
|
edited_message_handlers: Vec::new(),
|
||||||
|
channel_post_handlers: Vec::new(),
|
||||||
|
edited_channel_post_handlers: Vec::new(),
|
||||||
|
inline_query_handlers: Vec::new(),
|
||||||
|
chosen_inline_result_handlers: Vec::new(),
|
||||||
|
callback_query_handlers: Vec::new(),
|
||||||
|
shipping_query_handlers: Vec::new(),
|
||||||
|
pre_checkout_query_handlers: Vec::new(),
|
||||||
|
poll_handlers: Vec::new(),
|
||||||
|
poll_answer_handlers: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a handler of errors, produced by other handlers.
|
||||||
|
#[must_use]
|
||||||
|
pub fn handlers_error_handler<T>(mut self, val: T) -> Self
|
||||||
|
where
|
||||||
|
T: ErrorHandler<HandlerE> + 'a,
|
||||||
|
{
|
||||||
|
self.handlers_error_handler = Box::new(val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn update_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Update>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Update, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.update_handlers = register_handler(self.update_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn message_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Message, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.message_handlers = register_handler(self.message_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn edited_message_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Message, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.edited_message_handlers =
|
||||||
|
register_handler(self.edited_message_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn channel_post_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Message, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.channel_post_handlers =
|
||||||
|
register_handler(self.channel_post_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn edited_channel_post_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Message, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.edited_channel_post_handlers =
|
||||||
|
register_handler(self.edited_channel_post_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn inline_query_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<InlineQuery, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.inline_query_handlers =
|
||||||
|
register_handler(self.inline_query_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn chosen_inline_result_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<ChosenInlineResult>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<ChosenInlineResult, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.chosen_inline_result_handlers =
|
||||||
|
register_handler(self.chosen_inline_result_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn callback_query_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<CallbackQuery>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<CallbackQuery, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.callback_query_handlers =
|
||||||
|
register_handler(self.callback_query_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn shipping_query_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<ShippingQuery>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<ShippingQuery, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.shipping_query_handlers =
|
||||||
|
register_handler(self.shipping_query_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn pre_checkout_query_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<PreCheckoutQuery>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<PreCheckoutQuery, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.pre_checkout_query_handlers =
|
||||||
|
register_handler(self.pre_checkout_query_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn poll_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Poll>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Poll, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.poll_handlers = register_handler(self.poll_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn poll_answer_handler<H, I>(mut self, h: &'a H) -> Self
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<PollAnswer>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<PollAnswer, HandlerE>> + 'a,
|
||||||
|
{
|
||||||
|
self.poll_answer_handlers =
|
||||||
|
register_handler(self.poll_answer_handlers, h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts your bot with the default parameters.
|
||||||
|
///
|
||||||
|
/// The default parameters are a long polling update listener and log all
|
||||||
|
/// errors produced by this listener).
|
||||||
|
pub async fn dispatch(&'a self) {
|
||||||
|
self.dispatch_with_listener(
|
||||||
|
update_listeners::polling_default(Arc::clone(&self.bot)),
|
||||||
|
&LoggingErrorHandler::new("An error from the update listener"),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts your bot with custom `update_listener` and
|
||||||
|
/// `update_listener_error_handler`.
|
||||||
|
pub async fn dispatch_with_listener<UListener, ListenerE, Eh>(
|
||||||
|
&'a self,
|
||||||
|
update_listener: UListener,
|
||||||
|
update_listener_error_handler: &'a Eh,
|
||||||
|
) where
|
||||||
|
UListener: UpdateListener<ListenerE> + 'a,
|
||||||
|
Eh: ErrorHandler<ListenerE> + 'a,
|
||||||
|
ListenerE: Debug,
|
||||||
|
{
|
||||||
|
let update_listener = Box::pin(update_listener);
|
||||||
|
|
||||||
|
update_listener
|
||||||
|
.for_each_concurrent(None, move |update| async move {
|
||||||
|
log::trace!("Dispatcher received an update: {:?}", update);
|
||||||
|
|
||||||
|
let update = match update {
|
||||||
|
Ok(update) => update,
|
||||||
|
Err(error) => {
|
||||||
|
update_listener_error_handler.handle_error(error).await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let update =
|
||||||
|
match self.handle(&self.update_handlers, update).await {
|
||||||
|
Some(update) => update,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match update.kind {
|
||||||
|
UpdateKind::Message(message) => {
|
||||||
|
self.handle(&self.message_handlers, message).await;
|
||||||
|
}
|
||||||
|
UpdateKind::EditedMessage(message) => {
|
||||||
|
self.handle(&self.edited_message_handlers, message)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
UpdateKind::ChannelPost(post) => {
|
||||||
|
self.handle(&self.channel_post_handlers, post).await;
|
||||||
|
}
|
||||||
|
UpdateKind::EditedChannelPost(post) => {
|
||||||
|
self.handle(&self.edited_channel_post_handlers, post)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
UpdateKind::InlineQuery(query) => {
|
||||||
|
self.handle(&self.inline_query_handlers, query).await;
|
||||||
|
}
|
||||||
|
UpdateKind::ChosenInlineResult(result) => {
|
||||||
|
self.handle(
|
||||||
|
&self.chosen_inline_result_handlers,
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
UpdateKind::CallbackQuery(query) => {
|
||||||
|
self.handle(&self.callback_query_handlers, query).await;
|
||||||
|
}
|
||||||
|
UpdateKind::ShippingQuery(query) => {
|
||||||
|
self.handle(&self.shipping_query_handlers, query).await;
|
||||||
|
}
|
||||||
|
UpdateKind::PreCheckoutQuery(query) => {
|
||||||
|
self.handle(&self.pre_checkout_query_handlers, query)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
UpdateKind::Poll(poll) => {
|
||||||
|
self.handle(&self.poll_handlers, poll).await;
|
||||||
|
}
|
||||||
|
UpdateKind::PollAnswer(answer) => {
|
||||||
|
self.handle(&self.poll_answer_handlers, answer).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles a single update.
|
||||||
|
#[allow(clippy::ptr_arg)]
|
||||||
|
async fn handle<Upd>(
|
||||||
|
&self,
|
||||||
|
handlers: &Handlers<'a, Upd, HandlerE>,
|
||||||
|
update: Upd,
|
||||||
|
) -> Option<Upd> {
|
||||||
|
stream::iter(handlers)
|
||||||
|
.fold(Some(update), |acc, handler| {
|
||||||
|
async move {
|
||||||
|
// Option::and_then is not working here, because
|
||||||
|
// Middleware::handle is asynchronous.
|
||||||
|
match acc {
|
||||||
|
Some(update) => {
|
||||||
|
let DispatcherHandlerResult { next, result } =
|
||||||
|
handler
|
||||||
|
.handle_ctx(DispatcherHandlerCtx {
|
||||||
|
bot: Arc::clone(&self.bot),
|
||||||
|
update,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(error) = result {
|
||||||
|
self.handlers_error_handler
|
||||||
|
.handle_error(error)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transforms Future<Output = T> into Future<Output = U> by applying an Into
|
||||||
|
/// conversion.
|
||||||
|
async fn intermediate_fut0<T, U>(fut: impl Future<Output = T>) -> U
|
||||||
|
where
|
||||||
|
T: Into<U>,
|
||||||
|
{
|
||||||
|
fut.await.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transforms CtxHandler with Into<DispatcherHandlerResult<...>> as a return
|
||||||
|
/// value into CtxHandler with DispatcherHandlerResult return value.
|
||||||
|
fn intermediate_fut1<'a, Upd, HandlerE, H, I>(
|
||||||
|
h: &'a H,
|
||||||
|
) -> impl CtxHandler<
|
||||||
|
DispatcherHandlerCtx<Upd>,
|
||||||
|
DispatcherHandlerResult<Upd, HandlerE>,
|
||||||
|
> + 'a
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Upd>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Upd, HandlerE>> + 'a,
|
||||||
|
Upd: 'a,
|
||||||
|
{
|
||||||
|
move |ctx| intermediate_fut0(h.handle_ctx(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a single handler.
|
||||||
|
fn register_handler<'a, Upd, H, I, HandlerE>(
|
||||||
|
mut handlers: Handlers<'a, Upd, HandlerE>,
|
||||||
|
h: &'a H,
|
||||||
|
) -> Handlers<'a, Upd, HandlerE>
|
||||||
|
where
|
||||||
|
H: CtxHandler<DispatcherHandlerCtx<Upd>, I> + 'a,
|
||||||
|
I: Into<DispatcherHandlerResult<Upd, HandlerE>> + 'a,
|
||||||
|
HandlerE: 'a,
|
||||||
|
Upd: 'a,
|
||||||
|
{
|
||||||
|
handlers.push(Box::new(intermediate_fut1(h)));
|
||||||
|
handlers
|
||||||
|
}
|
168
src/dispatching/dispatcher_handler_ctx.rs
Normal file
168
src/dispatching/dispatcher_handler_ctx.rs
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
use crate::{
|
||||||
|
dispatching::dialogue::GetChatId,
|
||||||
|
requests::{
|
||||||
|
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage,
|
||||||
|
PinChatMessage, SendAnimation, SendAudio, SendContact, SendDocument,
|
||||||
|
SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker,
|
||||||
|
SendVenue, SendVideo, SendVideoNote, SendVoice,
|
||||||
|
},
|
||||||
|
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
|
||||||
|
Bot,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// A [`Dispatcher`]'s handler's context of a bot and an update.
|
||||||
|
///
|
||||||
|
/// See [the module-level documentation for the design
|
||||||
|
/// overview](crate::dispatching).
|
||||||
|
///
|
||||||
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
|
pub struct DispatcherHandlerCtx<Upd> {
|
||||||
|
pub bot: Arc<Bot>,
|
||||||
|
pub update: Upd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Upd> GetChatId for DispatcherHandlerCtx<Upd>
|
||||||
|
where
|
||||||
|
Upd: GetChatId,
|
||||||
|
{
|
||||||
|
fn chat_id(&self) -> i64 {
|
||||||
|
self.update.chat_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DispatcherHandlerCtx<Message> {
|
||||||
|
pub fn answer<T>(&self, text: T) -> SendMessage
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.send_message(self.chat_id(), text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reply_to<T>(&self, text: T) -> SendMessage
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.send_message(self.chat_id(), text)
|
||||||
|
.reply_to_message_id(self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
|
||||||
|
self.bot.send_photo(self.update.chat.id, photo)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_audio(&self, audio: InputFile) -> SendAudio {
|
||||||
|
self.bot.send_audio(self.update.chat.id, audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_animation(&self, animation: InputFile) -> SendAnimation {
|
||||||
|
self.bot.send_animation(self.update.chat.id, animation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_document(&self, document: InputFile) -> SendDocument {
|
||||||
|
self.bot.send_document(self.update.chat.id, document)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_video(&self, video: InputFile) -> SendVideo {
|
||||||
|
self.bot.send_video(self.update.chat.id, video)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_voice(&self, voice: InputFile) -> SendVoice {
|
||||||
|
self.bot.send_voice(self.update.chat.id, voice)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_media_group<T>(&self, media_group: T) -> SendMediaGroup
|
||||||
|
where
|
||||||
|
T: Into<Vec<InputMedia>>,
|
||||||
|
{
|
||||||
|
self.bot.send_media_group(self.update.chat.id, media_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_location(
|
||||||
|
&self,
|
||||||
|
latitude: f32,
|
||||||
|
longitude: f32,
|
||||||
|
) -> SendLocation {
|
||||||
|
self.bot
|
||||||
|
.send_location(self.update.chat.id, latitude, longitude)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_venue<T, U>(
|
||||||
|
&self,
|
||||||
|
latitude: f32,
|
||||||
|
longitude: f32,
|
||||||
|
title: T,
|
||||||
|
address: U,
|
||||||
|
) -> SendVenue
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.send_venue(
|
||||||
|
self.update.chat.id,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
title,
|
||||||
|
address,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
|
||||||
|
self.bot.send_video_note(self.update.chat.id, video_note)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_contact<T, U>(
|
||||||
|
&self,
|
||||||
|
phone_number: T,
|
||||||
|
first_name: U,
|
||||||
|
) -> SendContact
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
U: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.send_contact(self.chat_id(), phone_number, first_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn answer_sticker<T>(&self, sticker: InputFile) -> SendSticker {
|
||||||
|
self.bot.send_sticker(self.update.chat.id, sticker)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forward_to<T>(&self, chat_id: T) -> ForwardMessage
|
||||||
|
where
|
||||||
|
T: Into<ChatId>,
|
||||||
|
{
|
||||||
|
self.bot
|
||||||
|
.forward_message(chat_id, self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_message_text<T>(&self, text: T) -> EditMessageText
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
self.bot.edit_message_text(
|
||||||
|
ChatOrInlineMessage::Chat {
|
||||||
|
chat_id: self.update.chat.id.into(),
|
||||||
|
message_id: self.update.id,
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn edit_message_caption(&self) -> EditMessageCaption {
|
||||||
|
self.bot.edit_message_caption(ChatOrInlineMessage::Chat {
|
||||||
|
chat_id: self.update.chat.id.into(),
|
||||||
|
message_id: self.update.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_message(&self) -> DeleteMessage {
|
||||||
|
self.bot.delete_message(self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pin_message(&self) -> PinChatMessage {
|
||||||
|
self.bot
|
||||||
|
.pin_chat_message(self.update.chat.id, self.update.id)
|
||||||
|
}
|
||||||
|
}
|
31
src/dispatching/dispatcher_handler_result.rs
Normal file
31
src/dispatching/dispatcher_handler_result.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/// A result of a handler in [`Dispatcher`].
|
||||||
|
///
|
||||||
|
/// See [the module-level documentation for the design
|
||||||
|
/// overview](crate::dispatching).
|
||||||
|
///
|
||||||
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
|
pub struct DispatcherHandlerResult<Upd, E> {
|
||||||
|
pub next: Option<Upd>,
|
||||||
|
pub result: Result<(), E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Upd, E> DispatcherHandlerResult<Upd, E> {
|
||||||
|
/// Creates new `DispatcherHandlerResult` that continues the pipeline.
|
||||||
|
pub fn next(update: Upd, result: Result<(), E>) -> Self {
|
||||||
|
Self {
|
||||||
|
next: Some(update),
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new `DispatcherHandlerResult` that terminates the pipeline.
|
||||||
|
pub fn exit(result: Result<(), E>) -> Self {
|
||||||
|
Self { next: None, result }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Upd, E> From<Result<(), E>> for DispatcherHandlerResult<Upd, E> {
|
||||||
|
fn from(result: Result<(), E>) -> Self {
|
||||||
|
Self::exit(result)
|
||||||
|
}
|
||||||
|
}
|
151
src/dispatching/error_handlers.rs
Normal file
151
src/dispatching/error_handlers.rs
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
|
||||||
|
|
||||||
|
/// An asynchronous handler of an error.
|
||||||
|
///
|
||||||
|
/// See [the module-level documentation for the design
|
||||||
|
/// overview](crate::dispatching).
|
||||||
|
pub trait ErrorHandler<E> {
|
||||||
|
#[must_use]
|
||||||
|
fn handle_error<'a>(
|
||||||
|
&'a self,
|
||||||
|
error: E,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
|
||||||
|
where
|
||||||
|
E: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, F, Fut> ErrorHandler<E> for F
|
||||||
|
where
|
||||||
|
F: Fn(E) -> Fut,
|
||||||
|
Fut: Future<Output = ()>,
|
||||||
|
{
|
||||||
|
fn handle_error<'a>(
|
||||||
|
&'a self,
|
||||||
|
error: E,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
|
||||||
|
where
|
||||||
|
E: 'a,
|
||||||
|
{
|
||||||
|
Box::pin(async move { self(error).await })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A handler that silently ignores all errors.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main_() {
|
||||||
|
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandler};
|
||||||
|
///
|
||||||
|
/// IgnoringErrorHandler.handle_error(()).await;
|
||||||
|
/// IgnoringErrorHandler.handle_error(404).await;
|
||||||
|
/// IgnoringErrorHandler.handle_error("error").await;
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub struct IgnoringErrorHandler;
|
||||||
|
|
||||||
|
impl<E> ErrorHandler<E> for IgnoringErrorHandler {
|
||||||
|
fn handle_error<'a>(
|
||||||
|
&'a self,
|
||||||
|
_: E,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
|
||||||
|
where
|
||||||
|
E: 'a,
|
||||||
|
{
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A handler that silently ignores all errors that can never happen (e.g.:
|
||||||
|
/// [`!`] or [`Infallible`]).
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main_() {
|
||||||
|
/// use std::convert::{Infallible, TryInto};
|
||||||
|
///
|
||||||
|
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandlerSafe};
|
||||||
|
///
|
||||||
|
/// let result: Result<String, Infallible> = "str".try_into();
|
||||||
|
/// match result {
|
||||||
|
/// Ok(string) => println!("{}", string),
|
||||||
|
/// Err(inf) => IgnoringErrorHandlerSafe.handle_error(inf).await,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// IgnoringErrorHandlerSafe.handle_error(return).await; // return type of `return` is `!` (aka never)
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```compile_fail
|
||||||
|
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandlerSafe};
|
||||||
|
///
|
||||||
|
/// IgnoringErrorHandlerSafe.handle_error(0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
|
||||||
|
/// [`Infallible`]: std::convert::Infallible
|
||||||
|
pub struct IgnoringErrorHandlerSafe;
|
||||||
|
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
|
||||||
|
fn handle_error<'a>(
|
||||||
|
&'a self,
|
||||||
|
_: Infallible,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
|
||||||
|
where
|
||||||
|
Infallible: 'a,
|
||||||
|
{
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A handler that log all errors passed into it.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main_() {
|
||||||
|
/// use teloxide::dispatching::{ErrorHandler, LoggingErrorHandler};
|
||||||
|
///
|
||||||
|
/// LoggingErrorHandler::default().handle_error(()).await;
|
||||||
|
/// LoggingErrorHandler::new("error").handle_error(404).await;
|
||||||
|
/// LoggingErrorHandler::new("error")
|
||||||
|
/// .handle_error("Invalid data type!")
|
||||||
|
/// .await;
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LoggingErrorHandler {
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoggingErrorHandler {
|
||||||
|
/// Creates `LoggingErrorHandler` with a meta text before a log.
|
||||||
|
///
|
||||||
|
/// The logs will be printed in this format: `{text}: {:?}`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new<T>(text: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
Self { text: text.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> ErrorHandler<E> for LoggingErrorHandler
|
||||||
|
where
|
||||||
|
E: Debug,
|
||||||
|
{
|
||||||
|
fn handle_error<'a>(
|
||||||
|
&'a self,
|
||||||
|
error: E,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
|
||||||
|
where
|
||||||
|
E: 'a,
|
||||||
|
{
|
||||||
|
log::error!("{text}: {:?}", error, text = self.text);
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
use std::{future::Future, pin::Pin};
|
|
||||||
|
|
||||||
/// Continue or terminate a user session.
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
|
||||||
pub enum SessionState<Session> {
|
|
||||||
Continue(Session),
|
|
||||||
Terminate,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A handler of a user session and an update.
|
|
||||||
///
|
|
||||||
/// ## Returns
|
|
||||||
/// Returns [`SessionState::Continue(session)`] if it wants to be called again
|
|
||||||
/// after a new update, or [`SessionState::Terminate`] if not.
|
|
||||||
///
|
|
||||||
/// [`SessionState::Continue(session)`]:
|
|
||||||
/// crate::dispatching::SessionState::Continue
|
|
||||||
/// [`SessionState::Terminate`]: crate::dispatching::SessionState::Terminate
|
|
||||||
pub trait Handler<Session, U> {
|
|
||||||
#[must_use]
|
|
||||||
fn handle<'a>(
|
|
||||||
&'a self,
|
|
||||||
session: Session,
|
|
||||||
update: U,
|
|
||||||
) -> Pin<Box<dyn Future<Output = SessionState<Session>> + 'a>>
|
|
||||||
where
|
|
||||||
Session: 'a,
|
|
||||||
U: 'a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The implementation of `Handler` for `Fn(Session, Update) -> Future<Output =
|
|
||||||
/// SessionState<Session>>`.
|
|
||||||
impl<Session, U, F, Fut> Handler<Session, U> for F
|
|
||||||
where
|
|
||||||
F: Fn(Session, U) -> Fut,
|
|
||||||
Fut: Future<Output = SessionState<Session>>,
|
|
||||||
{
|
|
||||||
fn handle<'a>(
|
|
||||||
&'a self,
|
|
||||||
session: Session,
|
|
||||||
update: U,
|
|
||||||
) -> Pin<Box<dyn Future<Output = Fut::Output> + 'a>>
|
|
||||||
where
|
|
||||||
Session: 'a,
|
|
||||||
U: 'a,
|
|
||||||
{
|
|
||||||
Box::pin(async move { self(session, update).await })
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,120 @@
|
||||||
//! Update dispatching.
|
//! Updates dispatching.
|
||||||
|
//!
|
||||||
|
//! The key type here is [`Dispatcher`]. It encapsulates [`Bot`], handlers for
|
||||||
|
//! [11 update kinds] (+ for [`Update`]) and [`ErrorHandler`] for them. When
|
||||||
|
//! [`Update`] is received from Telegram, the following steps are executed:
|
||||||
|
//!
|
||||||
|
//! 1. It is supplied into an appropriate handler (the first ones is those who
|
||||||
|
//! accept [`Update`]).
|
||||||
|
//! 2. If a handler failed, invoke [`ErrorHandler`] with the corresponding
|
||||||
|
//! error.
|
||||||
|
//! 3. If a handler has returned [`DispatcherHandlerResult`] with `None`,
|
||||||
|
//! terminate the pipeline, otherwise supply an update into the next handler
|
||||||
|
//! (back to step 1).
|
||||||
|
//!
|
||||||
|
//! The pipeline is executed until either all the registered handlers were
|
||||||
|
//! executed, or one of handlers has terminated the pipeline. That's simple!
|
||||||
|
//!
|
||||||
|
//! 1. Note that handlers implement [`CtxHandler`], which means that you are
|
||||||
|
//! able to supply [`DialogueDispatcher`] as a handler, since it implements
|
||||||
|
//! [`CtxHandler`] too!
|
||||||
|
//! 2. Note that you don't always need to return [`DispatcherHandlerResult`]
|
||||||
|
//! explicitly, because of automatic conversions. Just return `Result<(), E>` if
|
||||||
|
//! you want to terminate the pipeline (see the example below).
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//! ### The ping-pong bot
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main_() {
|
||||||
|
//! use teloxide::prelude::*;
|
||||||
|
//!
|
||||||
|
//! // Setup logging here...
|
||||||
|
//!
|
||||||
|
//! // Create a dispatcher with a single message handler that answers "pong"
|
||||||
|
//! // to each incoming message.
|
||||||
|
//! Dispatcher::<RequestError>::new(Bot::from_env())
|
||||||
|
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
//! ctx.answer("pong").send().await?;
|
||||||
|
//! Ok(())
|
||||||
|
//! })
|
||||||
|
//! .dispatch()
|
||||||
|
//! .await;
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [Full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)
|
||||||
|
//!
|
||||||
|
//! ### Multiple handlers
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main_() {
|
||||||
|
//! use teloxide::prelude::*;
|
||||||
|
//!
|
||||||
|
//! // Create a dispatcher with multiple handlers of different types. This will
|
||||||
|
//! // print One! and Two! on every incoming UpdateKind::Message.
|
||||||
|
//! Dispatcher::<RequestError>::new(Bot::from_env())
|
||||||
|
//! // This is the first UpdateKind::Message handler, which will be called
|
||||||
|
//! // after the Update handler below.
|
||||||
|
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
//! log::info!("Two!");
|
||||||
|
//! DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
//! })
|
||||||
|
//! // Remember: handler of Update are called first.
|
||||||
|
//! .update_handler(&|ctx: DispatcherHandlerCtx<Update>| async move {
|
||||||
|
//! log::info!("One!");
|
||||||
|
//! DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
//! })
|
||||||
|
//! // This handler will be called right after the first UpdateKind::Message
|
||||||
|
//! // handler, because it is registered after.
|
||||||
|
//! .message_handler(&|_ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
//! // The same as DispatcherHandlerResult::exit(Ok(()))
|
||||||
|
//! Ok(())
|
||||||
|
//! })
|
||||||
|
//! // This handler will never be called, because the UpdateKind::Message
|
||||||
|
//! // handler above terminates the pipeline.
|
||||||
|
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
//! log::info!("This will never be printed!");
|
||||||
|
//! DispatcherHandlerResult::next(ctx.update, Ok(()))
|
||||||
|
//! })
|
||||||
|
//! .dispatch()
|
||||||
|
//! .await;
|
||||||
|
//!
|
||||||
|
//! // Note: if this bot receive, for example, UpdateKind::ChannelPost, it will
|
||||||
|
//! // only print "One!", because the UpdateKind::Message handlers will not be
|
||||||
|
//! // called.
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [Full](https://github.com/teloxide/teloxide/blob/dev/examples/miltiple_handlers_bot/)
|
||||||
|
//!
|
||||||
|
//! For a bit more complicated example, please see [examples/dialogue_bot].
|
||||||
|
//!
|
||||||
|
//! [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
|
//! [11 update kinds]: crate::types::UpdateKind
|
||||||
|
//! [`Update`]: crate::types::Update
|
||||||
|
//! [`ErrorHandler`]: crate::dispatching::ErrorHandler
|
||||||
|
//! [`CtxHandler`]: crate::dispatching::CtxHandler
|
||||||
|
//! [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||||
|
//! [`DispatcherHandlerResult`]: crate::dispatching::DispatcherHandlerResult
|
||||||
|
//! [`Bot`]: crate::Bot
|
||||||
|
//! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/tree/dev/examples/dialogue_bot
|
||||||
|
|
||||||
/// If an update was handled by a dispatcher or not.
|
mod ctx_handlers;
|
||||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
pub mod dialogue;
|
||||||
pub enum DispatchResult {
|
mod dispatcher;
|
||||||
Handled,
|
mod dispatcher_handler_ctx;
|
||||||
Unhandled,
|
mod dispatcher_handler_result;
|
||||||
}
|
mod error_handlers;
|
||||||
|
|
||||||
pub mod chat;
|
|
||||||
mod handler;
|
|
||||||
pub mod update_listeners;
|
pub mod update_listeners;
|
||||||
|
|
||||||
pub use handler::*;
|
pub use ctx_handlers::CtxHandler;
|
||||||
|
pub use dispatcher::Dispatcher;
|
||||||
|
pub use dispatcher_handler_ctx::DispatcherHandlerCtx;
|
||||||
|
pub use dispatcher_handler_result::DispatcherHandlerResult;
|
||||||
|
pub use error_handlers::{
|
||||||
|
ErrorHandler, IgnoringErrorHandler, IgnoringErrorHandlerSafe,
|
||||||
|
LoggingErrorHandler,
|
||||||
|
};
|
||||||
|
|
|
@ -108,7 +108,7 @@ use crate::{
|
||||||
types::{AllowedUpdate, Update},
|
types::{AllowedUpdate, Update},
|
||||||
RequestError,
|
RequestError,
|
||||||
};
|
};
|
||||||
use std::{convert::TryInto, time::Duration};
|
use std::{convert::TryInto, sync::Arc, time::Duration};
|
||||||
|
|
||||||
/// A generic update listener.
|
/// A generic update listener.
|
||||||
pub trait UpdateListener<E>: Stream<Item = Result<Update, E>> {
|
pub trait UpdateListener<E>: Stream<Item = Result<Update, E>> {
|
||||||
|
@ -119,7 +119,7 @@ impl<S, E> UpdateListener<E> for S where S: Stream<Item = Result<Update, E>> {}
|
||||||
/// Returns a long polling update listener with the default configuration.
|
/// Returns a long polling update listener with the default configuration.
|
||||||
///
|
///
|
||||||
/// See also: [`polling`](polling).
|
/// See also: [`polling`](polling).
|
||||||
pub fn polling_default(bot: &Bot) -> impl UpdateListener<RequestError> + '_ {
|
pub fn polling_default(bot: Arc<Bot>) -> impl UpdateListener<RequestError> {
|
||||||
polling(bot, None, None, None)
|
polling(bot, None, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +136,11 @@ pub fn polling_default(bot: &Bot) -> impl UpdateListener<RequestError> + '_ {
|
||||||
///
|
///
|
||||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
/// [`GetUpdates`]: crate::requests::GetUpdates
|
||||||
pub fn polling(
|
pub fn polling(
|
||||||
bot: &Bot,
|
bot: Arc<Bot>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
limit: Option<u8>,
|
limit: Option<u8>,
|
||||||
allowed_updates: Option<Vec<AllowedUpdate>>,
|
allowed_updates: Option<Vec<AllowedUpdate>>,
|
||||||
) -> impl UpdateListener<RequestError> + '_ {
|
) -> impl UpdateListener<RequestError> {
|
||||||
let timeout =
|
let timeout =
|
||||||
timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
|
timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));
|
||||||
|
|
||||||
|
@ -155,9 +155,39 @@ pub fn polling(
|
||||||
let updates = match req.send().await {
|
let updates = match req.send().await {
|
||||||
Err(err) => vec![Err(err)],
|
Err(err) => vec![Err(err)],
|
||||||
Ok(updates) => {
|
Ok(updates) => {
|
||||||
|
// Set offset to the last update's id + 1
|
||||||
if let Some(upd) = updates.last() {
|
if let Some(upd) = updates.last() {
|
||||||
offset = upd.id + 1;
|
let id: i32 = match upd {
|
||||||
|
Ok(ok) => ok.id,
|
||||||
|
Err((value, _)) => value["update_id"]
|
||||||
|
.as_i64()
|
||||||
|
.expect(
|
||||||
|
"The 'update_id' field must always exist in \
|
||||||
|
Update",
|
||||||
|
)
|
||||||
|
.try_into()
|
||||||
|
.expect("update_id must be i32"),
|
||||||
|
};
|
||||||
|
|
||||||
|
offset = id + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let updates = updates
|
||||||
|
.into_iter()
|
||||||
|
.filter(|update| match update {
|
||||||
|
Err((value, error)) => {
|
||||||
|
log::error!("Cannot parse an update.\nError: {:?}\nValue: {}\n\
|
||||||
|
This is a bug in teloxide, please open an issue here: \
|
||||||
|
https://github.com/teloxide/teloxide/issues.", error, value);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Ok(_) => true,
|
||||||
|
})
|
||||||
|
.map(|update| {
|
||||||
|
update.expect("See the previous .filter() call")
|
||||||
|
})
|
||||||
|
.collect::<Vec<Update>>();
|
||||||
|
|
||||||
updates.into_iter().map(Ok).collect::<Vec<_>>()
|
updates.into_iter().map(Ok).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -348,9 +348,9 @@ pub enum ApiErrorKind {
|
||||||
/// chat.
|
/// chat.
|
||||||
///
|
///
|
||||||
/// May happen in methods:
|
/// May happen in methods:
|
||||||
/// 1. [`PinMessage`]
|
/// 1. [`PinChatMessage`]
|
||||||
///
|
///
|
||||||
/// [`PinMessage`]: crate::requests::PinMessage
|
/// [`PinChatMessage`]: crate::requests::PinChatMessage
|
||||||
#[serde(rename = "Bad Request: not enough rights to pin a message")]
|
#[serde(rename = "Bad Request: not enough rights to pin a message")]
|
||||||
NotEnoughRightsToPinMessage,
|
NotEnoughRightsToPinMessage,
|
||||||
|
|
||||||
|
|
280
src/lib.rs
280
src/lib.rs
|
@ -1,3 +1,281 @@
|
||||||
|
//! A full-featured framework that empowers you to easily build [Telegram bots]
|
||||||
|
//! using the [`async`/`.await`] syntax in [Rust]. It handles all the difficult
|
||||||
|
//! stuff so you can focus only on your business logic.
|
||||||
|
//!
|
||||||
|
//! ## Features
|
||||||
|
//! - **Type-safe.** teloxide leverages the Rust's type system with two serious
|
||||||
|
//! implications: resistance to human mistakes and tight integration with
|
||||||
|
//! IDEs. Write fast, avoid debugging as possible.
|
||||||
|
//!
|
||||||
|
//! - **Persistency.** By default, teloxide stores all user dialogues in RAM,
|
||||||
|
//! but you can store them somewhere else (for example, in DB) just by
|
||||||
|
//! implementing 2 functions.
|
||||||
|
//!
|
||||||
|
//! - **Convenient dialogues system.** Define a type-safe [finite automaton]
|
||||||
|
//! and transition functions to drive a user dialogue with ease (see the
|
||||||
|
//! examples below).
|
||||||
|
//!
|
||||||
|
//! - **Convenient API.** Automatic conversions are used to avoid boilerplate.
|
||||||
|
//! For example, functions accept `Into<String>`, rather than `&str` or
|
||||||
|
//! `String`, so you can call them without `.to_string()`/`.as_str()`/etc.
|
||||||
|
//!
|
||||||
|
//! ## Getting started
|
||||||
|
//! 1. Create a new bot using [@Botfather] to get a token in the format
|
||||||
|
//! `123456789:blablabla`. 2. Initialise the `TELOXIDE_TOKEN` environmental
|
||||||
|
//! variable to your token:
|
||||||
|
//! ```bash
|
||||||
|
//! # Unix
|
||||||
|
//! $ export TELOXIDE_TOKEN=MyAwesomeToken
|
||||||
|
//!
|
||||||
|
//! # Windows
|
||||||
|
//! $ set TELOXITE_TOKEN=MyAwesomeToken
|
||||||
|
//! ```
|
||||||
|
//! 3. Be sure that you are up to date:
|
||||||
|
//! ```bash
|
||||||
|
//! $ rustup update stable
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! 4. Execute `cargo new my_bot`, enter the directory and put these lines into
|
||||||
|
//! your `Cargo.toml`:
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies]
|
||||||
|
//! teloxide = "0.1.0"
|
||||||
|
//! log = "0.4.8"
|
||||||
|
//! tokio = "0.2.11"
|
||||||
|
//! pretty_env_logger = "0.4.0"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## The ping-pong bot
|
||||||
|
//! This bot has a single message handler, which answers "pong" to each incoming
|
||||||
|
//! message:
|
||||||
|
//!
|
||||||
|
//! ([Full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/src/main.rs))
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! use teloxide::prelude::*;
|
||||||
|
//!
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main() {
|
||||||
|
//! teloxide::enable_logging!();
|
||||||
|
//! log::info!("Starting the ping-pong bot!");
|
||||||
|
//!
|
||||||
|
//! let bot = Bot::from_env();
|
||||||
|
//!
|
||||||
|
//! Dispatcher::<RequestError>::new(bot)
|
||||||
|
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
|
||||||
|
//! ctx.answer("pong").send().await?;
|
||||||
|
//! Ok(())
|
||||||
|
//! })
|
||||||
|
//! .dispatch()
|
||||||
|
//! .await;
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Commands
|
||||||
|
//! Commands are defined similar to how we define CLI using [structopt]. This
|
||||||
|
//! bot says "I am a cat! Meow!" on `/meow`, generates a random number within
|
||||||
|
//! [0; 1) on `/generate`, and shows the usage guide on `/help`:
|
||||||
|
//!
|
||||||
|
//! ([Full](https://github.com/teloxide/teloxide/blob/dev/examples/simple_commands_bot/src/main.rs))
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! # use teloxide::{prelude::*, utils::command::BotCommand};
|
||||||
|
//! # use rand::{thread_rng, Rng};
|
||||||
|
//! // Imports are omitted...
|
||||||
|
//!
|
||||||
|
//! #[derive(BotCommand)]
|
||||||
|
//! #[command(
|
||||||
|
//! rename = "lowercase",
|
||||||
|
//! description = "These commands are supported:"
|
||||||
|
//! )]
|
||||||
|
//! enum Command {
|
||||||
|
//! #[command(description = "display this text.")]
|
||||||
|
//! Help,
|
||||||
|
//! #[command(description = "be a cat.")]
|
||||||
|
//! Meow,
|
||||||
|
//! #[command(description = "generate a random number within [0; 1).")]
|
||||||
|
//! Generate,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handle_command(
|
||||||
|
//! ctx: DispatcherHandlerCtx<Message>,
|
||||||
|
//! ) -> Result<(), RequestError> {
|
||||||
|
//! let text = match ctx.update.text() {
|
||||||
|
//! Some(text) => text,
|
||||||
|
//! None => {
|
||||||
|
//! log::info!("Received a message, but not text.");
|
||||||
|
//! return Ok(());
|
||||||
|
//! }
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let command = match Command::parse(text) {
|
||||||
|
//! Some((command, _)) => command,
|
||||||
|
//! None => {
|
||||||
|
//! log::info!("Received a text message, but not a command.");
|
||||||
|
//! return Ok(());
|
||||||
|
//! }
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! match command {
|
||||||
|
//! Command::Help => ctx.answer(Command::descriptions()).send().await?,
|
||||||
|
//! Command::Generate => {
|
||||||
|
//! ctx.answer(thread_rng().gen_range(0.0, 1.0).to_string())
|
||||||
|
//! .send()
|
||||||
|
//! .await?
|
||||||
|
//! }
|
||||||
|
//! Command::Meow => ctx.answer("I am a cat! Meow!").send().await?,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! // Setup is omitted...
|
||||||
|
//! # teloxide::enable_logging!();
|
||||||
|
//! # log::info!("Starting simple_commands_bot!");
|
||||||
|
//! #
|
||||||
|
//! # let bot = Bot::from_env();
|
||||||
|
//! #
|
||||||
|
//! # Dispatcher::<RequestError>::new(bot)
|
||||||
|
//! # .message_handler(&handle_command)
|
||||||
|
//! # .dispatch()
|
||||||
|
//! # .await;
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Guess a number
|
||||||
|
//! Wanna see more? This is a bot, which starts a game on each incoming message.
|
||||||
|
//! You must guess a number from 1 to 10 (inclusively):
|
||||||
|
//!
|
||||||
|
//! ([Full](https://github.com/teloxide/teloxide/blob/dev/examples/guess_a_number_bot/src/main.rs))
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! # #[macro_use]
|
||||||
|
//! # extern crate smart_default;
|
||||||
|
//! # use teloxide::prelude::*;
|
||||||
|
//! # use rand::{thread_rng, Rng};
|
||||||
|
//! // Imports are omitted...
|
||||||
|
//!
|
||||||
|
//! #[derive(SmartDefault)]
|
||||||
|
//! enum Dialogue {
|
||||||
|
//! #[default]
|
||||||
|
//! Start,
|
||||||
|
//! ReceiveAttempt(u8),
|
||||||
|
//! }
|
||||||
|
//! async fn handle_message(
|
||||||
|
//! ctx: DialogueHandlerCtx<Message, Dialogue>,
|
||||||
|
//! ) -> Result<DialogueStage<Dialogue>, RequestError> {
|
||||||
|
//! match ctx.dialogue {
|
||||||
|
//! Dialogue::Start => {
|
||||||
|
//! ctx.answer(
|
||||||
|
//! "Let's play a game! Guess a number from 1 to 10
|
||||||
|
//! (inclusively).",
|
||||||
|
//! )
|
||||||
|
//! .send()
|
||||||
|
//! .await?;
|
||||||
|
//! next(Dialogue::ReceiveAttempt(thread_rng().gen_range(1, 11)))
|
||||||
|
//! }
|
||||||
|
//! Dialogue::ReceiveAttempt(secret) => match ctx.update.text() {
|
||||||
|
//! None => {
|
||||||
|
//! ctx.answer("Oh, please, send me a text message!")
|
||||||
|
//! .send()
|
||||||
|
//! .await?;
|
||||||
|
//! next(ctx.dialogue)
|
||||||
|
//! }
|
||||||
|
//! Some(text) => match text.parse::<u8>() {
|
||||||
|
//! Ok(attempt) => match attempt {
|
||||||
|
//! x if !(1..=10).contains(&x) => {
|
||||||
|
//! ctx.answer(
|
||||||
|
//! "Oh, please, send me a number in the range \
|
||||||
|
//! [1; 10]!",
|
||||||
|
//! )
|
||||||
|
//! .send()
|
||||||
|
//! .await?;
|
||||||
|
//! next(ctx.dialogue)
|
||||||
|
//! }
|
||||||
|
//! x if x == secret => {
|
||||||
|
//! ctx.answer("Congratulations! You won!")
|
||||||
|
//! .send()
|
||||||
|
//! .await?;
|
||||||
|
//! exit()
|
||||||
|
//! }
|
||||||
|
//! _ => {
|
||||||
|
//! ctx.answer("No.").send().await?;
|
||||||
|
//! next(ctx.dialogue)
|
||||||
|
//! }
|
||||||
|
//! },
|
||||||
|
//! Err(_) => {
|
||||||
|
//! ctx.answer(
|
||||||
|
//! "Oh, please, send me a number in the range [1; \
|
||||||
|
//! 10]!",
|
||||||
|
//! )
|
||||||
|
//! .send()
|
||||||
|
//! .await?;
|
||||||
|
//! next(ctx.dialogue)
|
||||||
|
//! }
|
||||||
|
//! },
|
||||||
|
//! },
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! # teloxide::enable_logging!();
|
||||||
|
//! # log::info!("Starting guess_a_number_bot!");
|
||||||
|
//! # let bot = Bot::from_env();
|
||||||
|
//! // Setup is omitted...
|
||||||
|
//!
|
||||||
|
//! Dispatcher::new(bot)
|
||||||
|
//! .message_handler(&DialogueDispatcher::new(|ctx| async move {
|
||||||
|
//! handle_message(ctx)
|
||||||
|
//! .await
|
||||||
|
//! .expect("Something wrong with the bot!")
|
||||||
|
//! }))
|
||||||
|
//! .dispatch()
|
||||||
|
//! .await;
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Our [finite automaton], designating a user dialogue, cannot be in an invalid
|
||||||
|
//! state. See [examples/dialogue_bot] to see a bit more complicated bot with
|
||||||
|
//! dialogues.
|
||||||
|
//!
|
||||||
|
//! [See more examples](https://github.com/teloxide/teloxide/tree/dev/examples).
|
||||||
|
//!
|
||||||
|
//! ## Recommendations
|
||||||
|
//!
|
||||||
|
//! - Use this pattern:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! run().await;
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn run() {
|
||||||
|
//! // Your logic here...
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Instead of this:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! #[tokio::main]
|
||||||
|
//! async fn main() {
|
||||||
|
//! // Your logic here...
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The second one produces very strange compiler messages because of the
|
||||||
|
//! `#[tokio::main]` macro. However, the examples above use the second one for
|
||||||
|
//! brevity.
|
||||||
|
//!
|
||||||
|
//! [Telegram bots]: https://telegram.org/blog/bot-revolution
|
||||||
|
//! [`async`/`.await`]: https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html
|
||||||
|
//! [Rust]: https://www.rust-lang.org/
|
||||||
|
//! [finite automaton]: https://en.wikipedia.org/wiki/Finite-state_machine
|
||||||
|
//! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/blob/dev/examples/dialogue_bot/src/main.rs
|
||||||
|
//! [structopt]: https://docs.rs/structopt/0.3.9/structopt/
|
||||||
|
//! [@Botfather]: https://t.me/botfather
|
||||||
|
|
||||||
#![doc(
|
#![doc(
|
||||||
html_logo_url = "https://github.com/teloxide/teloxide/raw/dev/logo.svg",
|
html_logo_url = "https://github.com/teloxide/teloxide/raw/dev/logo.svg",
|
||||||
html_favicon_url = "https://github.com/teloxide/teloxide/raw/dev/ICON.png"
|
html_favicon_url = "https://github.com/teloxide/teloxide/raw/dev/ICON.png"
|
||||||
|
@ -12,6 +290,8 @@ mod net;
|
||||||
|
|
||||||
mod bot;
|
mod bot;
|
||||||
pub mod dispatching;
|
pub mod dispatching;
|
||||||
|
mod logging;
|
||||||
|
pub mod prelude;
|
||||||
pub mod requests;
|
pub mod requests;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
52
src/logging.rs
Normal file
52
src/logging.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/// Enables logging through [pretty-env-logger].
|
||||||
|
///
|
||||||
|
/// A logger will **only** print errors from teloxide and **all** logs from
|
||||||
|
/// your program.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_compile
|
||||||
|
/// teloxide::enable_logging!();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// Calling this macro **is not mandatory**; you can setup if your own logger if
|
||||||
|
/// you want.
|
||||||
|
///
|
||||||
|
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! enable_logging {
|
||||||
|
() => {
|
||||||
|
teloxide::enable_logging_with_filter!(log::LevelFilter::Trace);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables logging through [pretty-env-logger] with a custom filter for your
|
||||||
|
/// program.
|
||||||
|
///
|
||||||
|
/// A logger will **only** print errors from teloxide and restrict logs from
|
||||||
|
/// your program by the specified filter.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Allow printing all logs from your program up to [`LevelFilter::Debug`] (i.e.
|
||||||
|
/// do not print traces):
|
||||||
|
///
|
||||||
|
/// ```no_compile
|
||||||
|
/// teloxide::enable_logging_with_filter!(log::LevelFilter::Debug);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// Calling this macro **is not mandatory**; you can setup if your own logger if
|
||||||
|
/// you want.
|
||||||
|
///
|
||||||
|
/// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger
|
||||||
|
/// [`LevelFilter::Debug`]: https://docs.rs/log/0.4.10/log/enum.LevelFilter.html
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! enable_logging_with_filter {
|
||||||
|
($filter:expr) => {
|
||||||
|
pretty_env_logger::formatted_builder()
|
||||||
|
.write_style(pretty_env_logger::env_logger::WriteStyle::Auto)
|
||||||
|
.filter(Some(env!("CARGO_PKG_NAME")), $filter)
|
||||||
|
.filter(Some("teloxide"), log::LevelFilter::Error)
|
||||||
|
.init();
|
||||||
|
};
|
||||||
|
}
|
14
src/prelude.rs
Normal file
14
src/prelude.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//! Commonly used items.
|
||||||
|
|
||||||
|
pub use crate::{
|
||||||
|
dispatching::{
|
||||||
|
dialogue::{
|
||||||
|
exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage,
|
||||||
|
GetChatId,
|
||||||
|
},
|
||||||
|
Dispatcher, DispatcherHandlerCtx, DispatcherHandlerResult,
|
||||||
|
},
|
||||||
|
requests::{Request, ResponseResult},
|
||||||
|
types::{Message, Update},
|
||||||
|
Bot, RequestError,
|
||||||
|
};
|
|
@ -5,15 +5,15 @@ use crate::{
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::requests::{Request, ResponseResult};
|
use crate::requests::{Request, ResponseResult};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to add a new sticker to a set created by the bot.
|
/// Use this method to add a new sticker to a set created by the bot.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#addstickertoset).
|
/// [The official docs](https://core.telegram.org/bots/api#addstickertoset).
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AddStickerToSet<'a> {
|
pub struct AddStickerToSet {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
name: String,
|
name: String,
|
||||||
png_sticker: InputFile,
|
png_sticker: InputFile,
|
||||||
|
@ -22,7 +22,7 @@ pub struct AddStickerToSet<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for AddStickerToSet<'_> {
|
impl Request for AddStickerToSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -47,9 +47,9 @@ impl Request for AddStickerToSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AddStickerToSet<'a> {
|
impl AddStickerToSet {
|
||||||
pub(crate) fn new<N, E>(
|
pub(crate) fn new<N, E>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
name: N,
|
name: N,
|
||||||
png_sticker: InputFile,
|
png_sticker: InputFile,
|
||||||
|
@ -60,7 +60,7 @@ impl<'a> AddStickerToSet<'a> {
|
||||||
E: Into<String>,
|
E: Into<String>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
user_id,
|
user_id,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
png_sticker,
|
png_sticker,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::True,
|
types::True,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send answers to callback queries sent from [inline
|
/// Use this method to send answers to callback queries sent from [inline
|
||||||
/// keyboards].
|
/// keyboards].
|
||||||
|
@ -18,10 +18,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [inline keyboards]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
/// [inline keyboards]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct AnswerCallbackQuery<'a> {
|
pub struct AnswerCallbackQuery {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
callback_query_id: String,
|
callback_query_id: String,
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
show_alert: Option<bool>,
|
show_alert: Option<bool>,
|
||||||
|
@ -30,7 +30,7 @@ pub struct AnswerCallbackQuery<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for AnswerCallbackQuery<'_> {
|
impl Request for AnswerCallbackQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -44,14 +44,14 @@ impl Request for AnswerCallbackQuery<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AnswerCallbackQuery<'a> {
|
impl AnswerCallbackQuery {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, callback_query_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, callback_query_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<String>,
|
C: Into<String>,
|
||||||
{
|
{
|
||||||
let callback_query_id = callback_query_id.into();
|
let callback_query_id = callback_query_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
callback_query_id,
|
callback_query_id,
|
||||||
text: None,
|
text: None,
|
||||||
show_alert: None,
|
show_alert: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{InlineQueryResult, True},
|
types::{InlineQueryResult, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send answers to an inline query.
|
/// Use this method to send answers to an inline query.
|
||||||
///
|
///
|
||||||
|
@ -14,10 +14,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#answerinlinequery).
|
/// [The official docs](https://core.telegram.org/bots/api#answerinlinequery).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct AnswerInlineQuery<'a> {
|
pub struct AnswerInlineQuery {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
inline_query_id: String,
|
inline_query_id: String,
|
||||||
results: Vec<InlineQueryResult>,
|
results: Vec<InlineQueryResult>,
|
||||||
cache_time: Option<i32>,
|
cache_time: Option<i32>,
|
||||||
|
@ -28,7 +28,7 @@ pub struct AnswerInlineQuery<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for AnswerInlineQuery<'_> {
|
impl Request for AnswerInlineQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -42,9 +42,9 @@ impl Request for AnswerInlineQuery<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AnswerInlineQuery<'a> {
|
impl AnswerInlineQuery {
|
||||||
pub(crate) fn new<I, R>(
|
pub(crate) fn new<I, R>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
inline_query_id: I,
|
inline_query_id: I,
|
||||||
results: R,
|
results: R,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -55,7 +55,7 @@ impl<'a> AnswerInlineQuery<'a> {
|
||||||
let inline_query_id = inline_query_id.into();
|
let inline_query_id = inline_query_id.into();
|
||||||
let results = results.into();
|
let results = results.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
inline_query_id,
|
inline_query_id,
|
||||||
results,
|
results,
|
||||||
cache_time: None,
|
cache_time: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::True,
|
types::True,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Once the user has confirmed their payment and shipping details, the Bot API
|
/// Once the user has confirmed their payment and shipping details, the Bot API
|
||||||
/// sends the final confirmation in the form of an [`Update`] with the field
|
/// sends the final confirmation in the form of an [`Update`] with the field
|
||||||
|
@ -18,17 +18,17 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Update`]: crate::types::Update
|
/// [`Update`]: crate::types::Update
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct AnswerPreCheckoutQuery<'a> {
|
pub struct AnswerPreCheckoutQuery {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
pre_checkout_query_id: String,
|
pre_checkout_query_id: String,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
error_message: Option<String>,
|
error_message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for AnswerPreCheckoutQuery<'_> {
|
impl Request for AnswerPreCheckoutQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -42,9 +42,9 @@ impl Request for AnswerPreCheckoutQuery<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AnswerPreCheckoutQuery<'a> {
|
impl AnswerPreCheckoutQuery {
|
||||||
pub(crate) fn new<P>(
|
pub(crate) fn new<P>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
pre_checkout_query_id: P,
|
pre_checkout_query_id: P,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -53,7 +53,7 @@ impl<'a> AnswerPreCheckoutQuery<'a> {
|
||||||
{
|
{
|
||||||
let pre_checkout_query_id = pre_checkout_query_id.into();
|
let pre_checkout_query_id = pre_checkout_query_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
pre_checkout_query_id,
|
pre_checkout_query_id,
|
||||||
ok,
|
ok,
|
||||||
error_message: None,
|
error_message: None,
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ShippingOption, True},
|
types::{ShippingOption, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// If you sent an invoice requesting a shipping address and the parameter
|
/// If you sent an invoice requesting a shipping address and the parameter
|
||||||
/// `is_flexible` was specified, the Bot API will send an [`Update`] with a
|
/// `is_flexible` was specified, the Bot API will send an [`Update`] with a
|
||||||
/// shipping_query field to the bot. Use this method to reply to shipping
|
/// shipping_query field to the bot. Use this method to reply to shipping
|
||||||
|
@ -16,10 +17,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Update`]: crate::types::Update
|
/// [`Update`]: crate::types::Update
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct AnswerShippingQuery<'a> {
|
pub struct AnswerShippingQuery {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
shipping_query_id: String,
|
shipping_query_id: String,
|
||||||
ok: bool,
|
ok: bool,
|
||||||
shipping_options: Option<Vec<ShippingOption>>,
|
shipping_options: Option<Vec<ShippingOption>>,
|
||||||
|
@ -27,7 +28,7 @@ pub struct AnswerShippingQuery<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for AnswerShippingQuery<'_> {
|
impl Request for AnswerShippingQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -41,14 +42,14 @@ impl Request for AnswerShippingQuery<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AnswerShippingQuery<'a> {
|
impl AnswerShippingQuery {
|
||||||
pub(crate) fn new<S>(bot: &'a Bot, shipping_query_id: S, ok: bool) -> Self
|
pub(crate) fn new<S>(bot: Arc<Bot>, shipping_query_id: S, ok: bool) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
let shipping_query_id = shipping_query_id.into();
|
let shipping_query_id = shipping_query_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
shipping_query_id,
|
shipping_query_id,
|
||||||
ok,
|
ok,
|
||||||
shipping_options: None,
|
shipping_options: None,
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
use crate::Bot;
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
/// A wrapper that implements `Clone`, Copy, `PartialEq`, `Eq`, `Debug`, but
|
|
||||||
/// performs no copying, cloning and comparison.
|
|
||||||
///
|
|
||||||
/// Used in the requests bodies.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BotWrapper<'a>(pub &'a Bot);
|
|
||||||
|
|
||||||
impl PartialEq for BotWrapper<'_> {
|
|
||||||
fn eq(&self, other: &BotWrapper<'_>) -> bool {
|
|
||||||
self.0.token() == other.0.token()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for BotWrapper<'_> {}
|
|
||||||
|
|
||||||
impl<'a> Clone for BotWrapper<'a> {
|
|
||||||
fn clone(&self) -> BotWrapper<'a> {
|
|
||||||
Self(self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for BotWrapper<'_> {}
|
|
||||||
|
|
||||||
impl Deref for BotWrapper<'_> {
|
|
||||||
type Target = Bot;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Bot {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,18 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{InputFile, MaskPosition, True},
|
types::{InputFile, MaskPosition, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to create new sticker set owned by a user. The bot will be
|
/// Use this method to create new sticker set owned by a user. The bot will be
|
||||||
/// able to edit the created sticker set.
|
/// able to edit the created sticker set.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#createnewstickerset).
|
/// [The official docs](https://core.telegram.org/bots/api#createnewstickerset).
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CreateNewStickerSet<'a> {
|
pub struct CreateNewStickerSet {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
name: String,
|
name: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -23,7 +23,7 @@ pub struct CreateNewStickerSet<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for CreateNewStickerSet<'_> {
|
impl Request for CreateNewStickerSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -52,9 +52,9 @@ impl Request for CreateNewStickerSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CreateNewStickerSet<'a> {
|
impl CreateNewStickerSet {
|
||||||
pub(crate) fn new<N, T, E>(
|
pub(crate) fn new<N, T, E>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
name: N,
|
name: N,
|
||||||
title: T,
|
title: T,
|
||||||
|
@ -67,7 +67,7 @@ impl<'a> CreateNewStickerSet<'a> {
|
||||||
E: Into<String>,
|
E: Into<String>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
user_id,
|
user_id,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
title: title.into(),
|
title: title.into(),
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to delete a chat photo. Photos can't be changed for private
|
/// Use this method to delete a chat photo. Photos can't be changed for private
|
||||||
/// chats. The bot must be an administrator in the chat for this to work and
|
/// chats. The bot must be an administrator in the chat for this to work and
|
||||||
|
@ -14,15 +14,15 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletechatphoto).
|
/// [The official docs](https://core.telegram.org/bots/api#deletechatphoto).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct DeleteChatPhoto<'a> {
|
pub struct DeleteChatPhoto {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for DeleteChatPhoto<'_> {
|
impl Request for DeleteChatPhoto {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -36,16 +36,13 @@ impl Request for DeleteChatPhoto<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeleteChatPhoto<'a> {
|
impl DeleteChatPhoto {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
/// Unique identifier for the target chat or username of the target channel
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to delete a group sticker set from a supergroup.
|
/// Use this method to delete a group sticker set from a supergroup.
|
||||||
///
|
///
|
||||||
|
@ -19,15 +19,15 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct DeleteChatStickerSet<'a> {
|
pub struct DeleteChatStickerSet {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for DeleteChatStickerSet<'_> {
|
impl Request for DeleteChatStickerSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -41,16 +41,13 @@ impl Request for DeleteChatStickerSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeleteChatStickerSet<'a> {
|
impl DeleteChatStickerSet {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
/// Unique identifier for the target chat or username of the target
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to delete a message, including service messages.
|
/// Use this method to delete a message, including service messages.
|
||||||
///
|
///
|
||||||
|
@ -24,16 +24,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletemessage).
|
/// [The official docs](https://core.telegram.org/bots/api#deletemessage).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct DeleteMessage<'a> {
|
pub struct DeleteMessage {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
message_id: i32,
|
message_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for DeleteMessage<'_> {
|
impl Request for DeleteMessage {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -47,14 +47,14 @@ impl Request for DeleteMessage<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeleteMessage<'a> {
|
impl DeleteMessage {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, message_id: i32) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, message_id: i32) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
message_id,
|
message_id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::True,
|
types::True,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to delete a sticker from a set created by the bot.
|
/// Use this method to delete a sticker from a set created by the bot.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#deletestickerfromset).
|
/// [The official docs](https://core.telegram.org/bots/api#deletestickerfromset).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct DeleteStickerFromSet<'a> {
|
pub struct DeleteStickerFromSet {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
sticker: String,
|
sticker: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for DeleteStickerFromSet<'_> {
|
impl Request for DeleteStickerFromSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -34,16 +34,13 @@ impl Request for DeleteStickerFromSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeleteStickerFromSet<'a> {
|
impl DeleteStickerFromSet {
|
||||||
pub(crate) fn new<S>(bot: &'a Bot, sticker: S) -> Self
|
pub(crate) fn new<S>(bot: Arc<Bot>, sticker: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
let sticker = sticker.into();
|
let sticker = sticker.into();
|
||||||
Self {
|
Self { bot, sticker }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
sticker,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// File identifier of the sticker.
|
/// File identifier of the sticker.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::True,
|
types::True,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to remove webhook integration if you decide to switch back
|
/// Use this method to remove webhook integration if you decide to switch back
|
||||||
/// to [Bot::get_updates].
|
/// to [Bot::get_updates].
|
||||||
|
@ -15,14 +15,14 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [Bot::get_updates]: crate::Bot::get_updates
|
/// [Bot::get_updates]: crate::Bot::get_updates
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Copy, Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct DeleteWebhook<'a> {
|
pub struct DeleteWebhook {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for DeleteWebhook<'_> {
|
impl Request for DeleteWebhook {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
@ -37,10 +37,8 @@ impl Request for DeleteWebhook<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeleteWebhook<'a> {
|
impl DeleteWebhook {
|
||||||
pub(crate) fn new(bot: &'a Bot) -> Self {
|
pub(crate) fn new(bot: Arc<Bot>) -> Self {
|
||||||
Self {
|
Self { bot }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to edit captions of messages.
|
/// Use this method to edit captions of messages.
|
||||||
///
|
///
|
||||||
|
@ -18,10 +18,10 @@ use crate::{
|
||||||
/// [`Message`]: crate::types::Message
|
/// [`Message`]: crate::types::Message
|
||||||
/// [`True`]: crate::types::True
|
/// [`True`]: crate::types::True
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct EditMessageCaption<'a> {
|
pub struct EditMessageCaption {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
caption: Option<String>,
|
caption: Option<String>,
|
||||||
|
@ -30,7 +30,7 @@ pub struct EditMessageCaption<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for EditMessageCaption<'_> {
|
impl Request for EditMessageCaption {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -44,13 +44,13 @@ impl Request for EditMessageCaption<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EditMessageCaption<'a> {
|
impl EditMessageCaption {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
caption: None,
|
caption: None,
|
||||||
parse_mode: None,
|
parse_mode: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to edit live location messages.
|
/// Use this method to edit live location messages.
|
||||||
///
|
///
|
||||||
|
@ -20,10 +20,10 @@ use crate::{
|
||||||
/// [`Message`]: crate::types::Message
|
/// [`Message`]: crate::types::Message
|
||||||
/// [`True`]: crate::types::True
|
/// [`True`]: crate::types::True
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct EditMessageLiveLocation<'a> {
|
pub struct EditMessageLiveLocation {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
|
@ -32,7 +32,7 @@ pub struct EditMessageLiveLocation<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for EditMessageLiveLocation<'_> {
|
impl Request for EditMessageLiveLocation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -46,15 +46,15 @@ impl Request for EditMessageLiveLocation<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EditMessageLiveLocation<'a> {
|
impl EditMessageLiveLocation {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, InputMedia, Message},
|
types::{ChatOrInlineMessage, InlineKeyboardMarkup, InputMedia, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to edit animation, audio, document, photo, or video
|
/// Use this method to edit animation, audio, document, photo, or video
|
||||||
/// messages.
|
/// messages.
|
||||||
|
@ -20,16 +20,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Message`]: crate::types::Message
|
/// [`Message`]: crate::types::Message
|
||||||
/// [`True`]: crate::types::True
|
/// [`True`]: crate::types::True
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EditMessageMedia<'a> {
|
pub struct EditMessageMedia {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
media: InputMedia,
|
media: InputMedia,
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
reply_markup: Option<InlineKeyboardMarkup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for EditMessageMedia<'_> {
|
impl Request for EditMessageMedia {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -67,14 +67,14 @@ impl Request for EditMessageMedia<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EditMessageMedia<'a> {
|
impl EditMessageMedia {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
media: InputMedia,
|
media: InputMedia,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
media,
|
media,
|
||||||
reply_markup: None,
|
reply_markup: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to edit only the reply markup of messages.
|
/// Use this method to edit only the reply markup of messages.
|
||||||
///
|
///
|
||||||
|
@ -18,17 +18,17 @@ use crate::{
|
||||||
/// [`Message`]: crate::types::Message
|
/// [`Message`]: crate::types::Message
|
||||||
/// [`True`]: crate::types::True
|
/// [`True`]: crate::types::True
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct EditMessageReplyMarkup<'a> {
|
pub struct EditMessageReplyMarkup {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
reply_markup: Option<InlineKeyboardMarkup>,
|
reply_markup: Option<InlineKeyboardMarkup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for EditMessageReplyMarkup<'_> {
|
impl Request for EditMessageReplyMarkup {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -42,13 +42,13 @@ impl Request for EditMessageReplyMarkup<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EditMessageReplyMarkup<'a> {
|
impl EditMessageReplyMarkup {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
reply_markup: None,
|
reply_markup: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to edit text and game messages.
|
/// Use this method to edit text and game messages.
|
||||||
///
|
///
|
||||||
|
@ -18,10 +18,10 @@ use crate::{
|
||||||
/// [`Message`]: crate::types::Message
|
/// [`Message`]: crate::types::Message
|
||||||
/// [`True`]: crate::types::True
|
/// [`True`]: crate::types::True
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct EditMessageText<'a> {
|
pub struct EditMessageText {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -31,7 +31,7 @@ pub struct EditMessageText<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for EditMessageText<'_> {
|
impl Request for EditMessageText {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -45,9 +45,9 @@ impl Request for EditMessageText<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EditMessageText<'a> {
|
impl EditMessageText {
|
||||||
pub(crate) fn new<T>(
|
pub(crate) fn new<T>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
text: T,
|
text: T,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -55,7 +55,7 @@ impl<'a> EditMessageText<'a> {
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
text: text.into(),
|
text: text.into(),
|
||||||
parse_mode: None,
|
parse_mode: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::ChatId,
|
types::ChatId,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to generate a new invite link for a chat; any previously
|
/// Use this method to generate a new invite link for a chat; any previously
|
||||||
/// generated link is revoked.
|
/// generated link is revoked.
|
||||||
|
@ -28,15 +28,15 @@ use crate::{
|
||||||
/// [`Bot::export_chat_invite_link`]: crate::Bot::export_chat_invite_link
|
/// [`Bot::export_chat_invite_link`]: crate::Bot::export_chat_invite_link
|
||||||
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
/// [`Bot::get_chat`]: crate::Bot::get_chat
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct ExportChatInviteLink<'a> {
|
pub struct ExportChatInviteLink {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for ExportChatInviteLink<'_> {
|
impl Request for ExportChatInviteLink {
|
||||||
type Output = String;
|
type Output = String;
|
||||||
|
|
||||||
/// Returns the new invite link as `String` on success.
|
/// Returns the new invite link as `String` on success.
|
||||||
|
@ -51,16 +51,13 @@ impl Request for ExportChatInviteLink<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExportChatInviteLink<'a> {
|
impl ExportChatInviteLink {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
/// Unique identifier for the target chat or username of the target channel
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message},
|
types::{ChatId, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to forward messages of any kind.
|
/// Use this method to forward messages of any kind.
|
||||||
///
|
///
|
||||||
/// [`The official docs`](https://core.telegram.org/bots/api#forwardmessage).
|
/// [`The official docs`](https://core.telegram.org/bots/api#forwardmessage).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct ForwardMessage<'a> {
|
pub struct ForwardMessage {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
from_chat_id: ChatId,
|
from_chat_id: ChatId,
|
||||||
disable_notification: Option<bool>,
|
disable_notification: Option<bool>,
|
||||||
|
@ -23,7 +23,7 @@ pub struct ForwardMessage<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for ForwardMessage<'_> {
|
impl Request for ForwardMessage {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -37,9 +37,9 @@ impl Request for ForwardMessage<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ForwardMessage<'a> {
|
impl ForwardMessage {
|
||||||
pub(crate) fn new<C, F>(
|
pub(crate) fn new<C, F>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
from_chat_id: F,
|
from_chat_id: F,
|
||||||
message_id: i32,
|
message_id: i32,
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> ForwardMessage<'a> {
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
let from_chat_id = from_chat_id.into();
|
let from_chat_id = from_chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
from_chat_id,
|
from_chat_id,
|
||||||
message_id,
|
message_id,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{Chat, ChatId},
|
types::{Chat, ChatId},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get up to date information about the chat (current name
|
/// Use this method to get up to date information about the chat (current name
|
||||||
/// of the user for one-on-one conversations, current username of a user, group
|
/// of the user for one-on-one conversations, current username of a user, group
|
||||||
|
@ -14,15 +14,15 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchat).
|
/// [The official docs](https://core.telegram.org/bots/api#getchat).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetChat<'a> {
|
pub struct GetChat {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetChat<'_> {
|
impl Request for GetChat {
|
||||||
type Output = Chat;
|
type Output = Chat;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Chat> {
|
async fn send(&self) -> ResponseResult<Chat> {
|
||||||
|
@ -31,16 +31,13 @@ impl Request for GetChat<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetChat<'a> {
|
impl GetChat {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
/// Unique identifier for the target chat or username of the target
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, ChatMember},
|
types::{ChatId, ChatMember},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get a list of administrators in a chat.
|
/// Use this method to get a list of administrators in a chat.
|
||||||
///
|
///
|
||||||
|
@ -15,15 +15,15 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatadministrators).
|
/// [The official docs](https://core.telegram.org/bots/api#getchatadministrators).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetChatAdministrators<'a> {
|
pub struct GetChatAdministrators {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetChatAdministrators<'_> {
|
impl Request for GetChatAdministrators {
|
||||||
type Output = Vec<ChatMember>;
|
type Output = Vec<ChatMember>;
|
||||||
|
|
||||||
/// On success, returns an array that contains information about all chat
|
/// On success, returns an array that contains information about all chat
|
||||||
|
@ -39,16 +39,13 @@ impl Request for GetChatAdministrators<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetChatAdministrators<'a> {
|
impl GetChatAdministrators {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
/// Unique identifier for the target chat or username of the target
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, ChatMember},
|
types::{ChatId, ChatMember},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get information about a member of a chat.
|
/// Use this method to get information about a member of a chat.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatmember).
|
/// [The official docs](https://core.telegram.org/bots/api#getchatmember).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetChatMember<'a> {
|
pub struct GetChatMember {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetChatMember<'_> {
|
impl Request for GetChatMember {
|
||||||
type Output = ChatMember;
|
type Output = ChatMember;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<ChatMember> {
|
async fn send(&self) -> ResponseResult<ChatMember> {
|
||||||
|
@ -35,14 +35,14 @@ impl Request for GetChatMember<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetChatMember<'a> {
|
impl GetChatMember {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, user_id: i32) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, user_id: i32) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::ChatId,
|
types::ChatId,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get the number of members in a chat.
|
/// Use this method to get the number of members in a chat.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getchatmemberscount).
|
/// [The official docs](https://core.telegram.org/bots/api#getchatmemberscount).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetChatMembersCount<'a> {
|
pub struct GetChatMembersCount {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetChatMembersCount<'_> {
|
impl Request for GetChatMembersCount {
|
||||||
type Output = i32;
|
type Output = i32;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<i32> {
|
async fn send(&self) -> ResponseResult<i32> {
|
||||||
|
@ -34,16 +34,13 @@ impl Request for GetChatMembersCount<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetChatMembersCount<'a> {
|
impl GetChatMembersCount {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
/// Unique identifier for the target chat or username of the target
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::File,
|
types::File,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get basic info about a file and prepare it for
|
/// Use this method to get basic info about a file and prepare it for
|
||||||
/// downloading.
|
/// downloading.
|
||||||
|
@ -28,15 +28,15 @@ use crate::{
|
||||||
/// [`File`]: crate::types::file
|
/// [`File`]: crate::types::file
|
||||||
/// [`GetFile`]: self::GetFile
|
/// [`GetFile`]: self::GetFile
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetFile<'a> {
|
pub struct GetFile {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
file_id: String,
|
file_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetFile<'_> {
|
impl Request for GetFile {
|
||||||
type Output = File;
|
type Output = File;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<File> {
|
async fn send(&self) -> ResponseResult<File> {
|
||||||
|
@ -45,13 +45,13 @@ impl Request for GetFile<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetFile<'a> {
|
impl GetFile {
|
||||||
pub(crate) fn new<F>(bot: &'a Bot, file_id: F) -> Self
|
pub(crate) fn new<F>(bot: Arc<Bot>, file_id: F) -> Self
|
||||||
where
|
where
|
||||||
F: Into<String>,
|
F: Into<String>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
file_id: file_id.into(),
|
file_id: file_id.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatOrInlineMessage, GameHighScore},
|
types::{ChatOrInlineMessage, GameHighScore},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get data for high score tables.
|
/// Use this method to get data for high score tables.
|
||||||
///
|
///
|
||||||
|
@ -21,17 +21,17 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores).
|
/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetGameHighScores<'a> {
|
pub struct GetGameHighScores {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetGameHighScores<'_> {
|
impl Request for GetGameHighScores {
|
||||||
type Output = Vec<GameHighScore>;
|
type Output = Vec<GameHighScore>;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<GameHighScore>> {
|
async fn send(&self) -> ResponseResult<Vec<GameHighScore>> {
|
||||||
|
@ -45,14 +45,14 @@ impl Request for GetGameHighScores<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetGameHighScores<'a> {
|
impl GetGameHighScores {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_or_inline_message,
|
chat_or_inline_message,
|
||||||
user_id,
|
user_id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
|
@ -6,18 +5,19 @@ use crate::{
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A simple method for testing your bot's auth token. Requires no parameters.
|
/// A simple method for testing your bot's auth token. Requires no parameters.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getme).
|
/// [The official docs](https://core.telegram.org/bots/api#getme).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Copy, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetMe<'a> {
|
pub struct GetMe {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetMe<'_> {
|
impl Request for GetMe {
|
||||||
type Output = Me;
|
type Output = Me;
|
||||||
|
|
||||||
/// Returns basic information about the bot.
|
/// Returns basic information about the bot.
|
||||||
|
@ -28,10 +28,8 @@ impl Request for GetMe<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetMe<'a> {
|
impl GetMe {
|
||||||
pub(crate) fn new(bot: &'a Bot) -> Self {
|
pub(crate) fn new(bot: Arc<Bot>) -> Self {
|
||||||
Self {
|
Self { bot }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::StickerSet,
|
types::StickerSet,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get a sticker set.
|
/// Use this method to get a sticker set.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getstickerset).
|
/// [The official docs](https://core.telegram.org/bots/api#getstickerset).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetStickerSet<'a> {
|
pub struct GetStickerSet {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetStickerSet<'_> {
|
impl Request for GetStickerSet {
|
||||||
type Output = StickerSet;
|
type Output = StickerSet;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<StickerSet> {
|
async fn send(&self) -> ResponseResult<StickerSet> {
|
||||||
|
@ -34,16 +34,13 @@ impl Request for GetStickerSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetStickerSet<'a> {
|
impl GetStickerSet {
|
||||||
pub(crate) fn new<N>(bot: &'a Bot, name: N) -> Self
|
pub(crate) fn new<N>(bot: Arc<Bot>, name: N) -> Self
|
||||||
where
|
where
|
||||||
N: Into<String>,
|
N: Into<String>,
|
||||||
{
|
{
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
Self {
|
Self { bot, name }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Name of the sticker set.
|
/// Name of the sticker set.
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{AllowedUpdate, Update},
|
types::{AllowedUpdate, Update},
|
||||||
Bot,
|
Bot, RequestError,
|
||||||
};
|
};
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to receive incoming updates using long polling ([wiki]).
|
/// Use this method to receive incoming updates using long polling ([wiki]).
|
||||||
///
|
///
|
||||||
|
@ -19,10 +20,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [wiki]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
|
/// [wiki]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetUpdates<'a> {
|
pub struct GetUpdates {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
pub(crate) offset: Option<i32>,
|
pub(crate) offset: Option<i32>,
|
||||||
pub(crate) limit: Option<u8>,
|
pub(crate) limit: Option<u8>,
|
||||||
pub(crate) timeout: Option<u32>,
|
pub(crate) timeout: Option<u32>,
|
||||||
|
@ -30,24 +31,43 @@ pub struct GetUpdates<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetUpdates<'_> {
|
impl Request for GetUpdates {
|
||||||
type Output = Vec<Update>;
|
type Output = Vec<Result<Update, (Value, serde_json::Error)>>;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<Update>> {
|
/// Deserialize to `Vec<serde_json::Result<Update>>` instead of
|
||||||
net::request_json(
|
/// `Vec<Update>`, because we want to parse the rest of updates even if our
|
||||||
|
/// library hasn't parsed one.
|
||||||
|
async fn send(
|
||||||
|
&self,
|
||||||
|
) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
|
||||||
|
let value: Value = net::request_json(
|
||||||
self.bot.client(),
|
self.bot.client(),
|
||||||
self.bot.token(),
|
self.bot.token(),
|
||||||
"getUpdates",
|
"getUpdates",
|
||||||
&self,
|
&self,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Value::Array(array) => Ok(array
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| {
|
||||||
|
serde_json::from_str(&value.to_string())
|
||||||
|
.map_err(|error| (value, error))
|
||||||
|
})
|
||||||
|
.collect()),
|
||||||
|
_ => Err(RequestError::InvalidJson(
|
||||||
|
serde_json::from_value::<Vec<Update>>(value)
|
||||||
|
.expect_err("get_update must return Value::Array"),
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetUpdates<'a> {
|
impl GetUpdates {
|
||||||
pub(crate) fn new(bot: &'a Bot) -> Self {
|
pub(crate) fn new(bot: Arc<Bot>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
offset: None,
|
offset: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::UserProfilePhotos,
|
types::UserProfilePhotos,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get a list of profile pictures for a user.
|
/// Use this method to get a list of profile pictures for a user.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getuserprofilephotos).
|
/// [The official docs](https://core.telegram.org/bots/api#getuserprofilephotos).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Copy, Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetUserProfilePhotos<'a> {
|
pub struct GetUserProfilePhotos {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
offset: Option<i32>,
|
offset: Option<i32>,
|
||||||
limit: Option<i32>,
|
limit: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetUserProfilePhotos<'_> {
|
impl Request for GetUserProfilePhotos {
|
||||||
type Output = UserProfilePhotos;
|
type Output = UserProfilePhotos;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
|
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
|
||||||
|
@ -36,10 +36,10 @@ impl Request for GetUserProfilePhotos<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetUserProfilePhotos<'a> {
|
impl GetUserProfilePhotos {
|
||||||
pub(crate) fn new(bot: &'a Bot, user_id: i32) -> Self {
|
pub(crate) fn new(bot: Arc<Bot>, user_id: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
user_id,
|
user_id,
|
||||||
offset: None,
|
offset: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::WebhookInfo,
|
types::WebhookInfo,
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to get current webhook status.
|
/// Use this method to get current webhook status.
|
||||||
///
|
///
|
||||||
|
@ -16,14 +16,14 @@ use crate::{
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#getwebhookinfo).
|
/// [The official docs](https://core.telegram.org/bots/api#getwebhookinfo).
|
||||||
///
|
///
|
||||||
/// [`Bot::get_updates`]: crate::Bot::get_updates
|
/// [`Bot::get_updates`]: crate::Bot::get_updates
|
||||||
#[derive(Copy, Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetWebhookInfo<'a> {
|
pub struct GetWebhookInfo {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for GetWebhookInfo<'_> {
|
impl Request for GetWebhookInfo {
|
||||||
type Output = WebhookInfo;
|
type Output = WebhookInfo;
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
@ -38,10 +38,8 @@ impl Request for GetWebhookInfo<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GetWebhookInfo<'a> {
|
impl GetWebhookInfo {
|
||||||
pub(crate) fn new(bot: &'a Bot) -> Self {
|
pub(crate) fn new(bot: Arc<Bot>) -> Self {
|
||||||
Self {
|
Self { bot }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to kick a user from a group, a supergroup or a channel.
|
/// Use this method to kick a user from a group, a supergroup or a channel.
|
||||||
///
|
///
|
||||||
|
@ -19,17 +19,17 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [unbanned]: crate::Bot::unban_chat_member
|
/// [unbanned]: crate::Bot::unban_chat_member
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct KickChatMember<'a> {
|
pub struct KickChatMember {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
until_date: Option<i32>,
|
until_date: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for KickChatMember<'_> {
|
impl Request for KickChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -43,14 +43,14 @@ impl Request for KickChatMember<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KickChatMember<'a> {
|
impl KickChatMember {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, user_id: i32) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, user_id: i32) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
until_date: None,
|
until_date: None,
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method for your bot to leave a group, supergroup or channel.
|
/// Use this method for your bot to leave a group, supergroup or channel.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#leavechat).
|
/// [The official docs](https://core.telegram.org/bots/api#leavechat).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct LeaveChat<'a> {
|
pub struct LeaveChat {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for LeaveChat<'_> {
|
impl Request for LeaveChat {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -34,16 +34,13 @@ impl Request for LeaveChat<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LeaveChat<'a> {
|
impl LeaveChat {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self { bot, chat_id }
|
||||||
bot: BotWrapper(bot),
|
|
||||||
chat_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target
|
/// Unique identifier for the target chat or username of the target
|
||||||
|
|
|
@ -130,6 +130,3 @@ pub use stop_poll::*;
|
||||||
pub use unban_chat_member::*;
|
pub use unban_chat_member::*;
|
||||||
pub use unpin_chat_message::*;
|
pub use unpin_chat_message::*;
|
||||||
pub use upload_sticker_file::*;
|
pub use upload_sticker_file::*;
|
||||||
|
|
||||||
mod bot_wrapper;
|
|
||||||
use bot_wrapper::BotWrapper;
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to pin a message in a group, a supergroup, or a channel.
|
/// Use this method to pin a message in a group, a supergroup, or a channel.
|
||||||
///
|
///
|
||||||
|
@ -16,17 +16,17 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#pinchatmessage).
|
/// [The official docs](https://core.telegram.org/bots/api#pinchatmessage).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct PinChatMessage<'a> {
|
pub struct PinChatMessage {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
message_id: i32,
|
message_id: i32,
|
||||||
disable_notification: Option<bool>,
|
disable_notification: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for PinChatMessage<'_> {
|
impl Request for PinChatMessage {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -40,14 +40,14 @@ impl Request for PinChatMessage<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PinChatMessage<'a> {
|
impl PinChatMessage {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, message_id: i32) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, message_id: i32) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
message_id,
|
message_id,
|
||||||
disable_notification: None,
|
disable_notification: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to promote or demote a user in a supergroup or a channel.
|
/// Use this method to promote or demote a user in a supergroup or a channel.
|
||||||
///
|
///
|
||||||
|
@ -16,10 +16,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#promotechatmember).
|
/// [The official docs](https://core.telegram.org/bots/api#promotechatmember).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct PromoteChatMember<'a> {
|
pub struct PromoteChatMember {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
can_change_info: Option<bool>,
|
can_change_info: Option<bool>,
|
||||||
|
@ -33,7 +33,7 @@ pub struct PromoteChatMember<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for PromoteChatMember<'_> {
|
impl Request for PromoteChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -47,14 +47,14 @@ impl Request for PromoteChatMember<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PromoteChatMember<'a> {
|
impl PromoteChatMember {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, user_id: i32) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, user_id: i32) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
can_change_info: None,
|
can_change_info: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, ChatPermissions, True},
|
types::{ChatId, ChatPermissions, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to restrict a user in a supergroup.
|
/// Use this method to restrict a user in a supergroup.
|
||||||
///
|
///
|
||||||
|
@ -16,10 +16,10 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#restrictchatmember).
|
/// [The official docs](https://core.telegram.org/bots/api#restrictchatmember).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct RestrictChatMember<'a> {
|
pub struct RestrictChatMember {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
permissions: ChatPermissions,
|
permissions: ChatPermissions,
|
||||||
|
@ -27,7 +27,7 @@ pub struct RestrictChatMember<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for RestrictChatMember<'_> {
|
impl Request for RestrictChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -41,9 +41,9 @@ impl Request for RestrictChatMember<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RestrictChatMember<'a> {
|
impl RestrictChatMember {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
permissions: ChatPermissions,
|
permissions: ChatPermissions,
|
||||||
|
@ -53,7 +53,7 @@ impl<'a> RestrictChatMember<'a> {
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
permissions,
|
permissions,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video
|
/// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video
|
||||||
/// without sound).
|
/// without sound).
|
||||||
|
@ -13,9 +13,9 @@ use crate::{
|
||||||
/// may be changed in the future.
|
/// may be changed in the future.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendanimation).
|
/// [The official docs](https://core.telegram.org/bots/api#sendanimation).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendAnimation<'a> {
|
pub struct SendAnimation {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
pub chat_id: ChatId,
|
pub chat_id: ChatId,
|
||||||
pub animation: InputFile,
|
pub animation: InputFile,
|
||||||
pub duration: Option<u32>,
|
pub duration: Option<u32>,
|
||||||
|
@ -30,7 +30,7 @@ pub struct SendAnimation<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendAnimation<'_> {
|
impl Request for SendAnimation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -67,13 +67,17 @@ impl Request for SendAnimation<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendAnimation<'a> {
|
impl SendAnimation {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, animation: InputFile) -> Self
|
pub(crate) fn new<C>(
|
||||||
|
bot: Arc<Bot>,
|
||||||
|
chat_id: C,
|
||||||
|
animation: InputFile,
|
||||||
|
) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
animation,
|
animation,
|
||||||
duration: None,
|
duration: None,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send audio files, if you want Telegram clients to display
|
/// Use this method to send audio files, if you want Telegram clients to display
|
||||||
/// them in the music player.
|
/// them in the music player.
|
||||||
|
@ -17,9 +17,9 @@ use crate::{
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendaudio).
|
/// [The official docs](https://core.telegram.org/bots/api#sendaudio).
|
||||||
///
|
///
|
||||||
/// [`Bot::send_voice`]: crate::Bot::send_voice
|
/// [`Bot::send_voice`]: crate::Bot::send_voice
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendAudio<'a> {
|
pub struct SendAudio {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
audio: InputFile,
|
audio: InputFile,
|
||||||
caption: Option<String>,
|
caption: Option<String>,
|
||||||
|
@ -34,7 +34,7 @@ pub struct SendAudio<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendAudio<'_> {
|
impl Request for SendAudio {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -71,13 +71,13 @@ impl Request for SendAudio<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendAudio<'a> {
|
impl SendAudio {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, audio: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, audio: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
audio,
|
audio,
|
||||||
caption: None,
|
caption: None,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method when you need to tell the user that something is happening
|
/// Use this method when you need to tell the user that something is happening
|
||||||
/// on the bot's side.
|
/// on the bot's side.
|
||||||
|
@ -26,10 +26,10 @@ use crate::{
|
||||||
/// [ImageBot]: https://t.me/imagebot
|
/// [ImageBot]: https://t.me/imagebot
|
||||||
/// [`Bot::send_chat_action`]: crate::Bot::send_chat_action
|
/// [`Bot::send_chat_action`]: crate::Bot::send_chat_action
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendChatAction<'a> {
|
pub struct SendChatAction {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
action: SendChatActionKind,
|
action: SendChatActionKind,
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ pub struct SendChatAction<'a> {
|
||||||
/// A type of action used in [`SendChatAction`].
|
/// A type of action used in [`SendChatAction`].
|
||||||
///
|
///
|
||||||
/// [`SendChatAction`]: crate::requests::SendChatAction
|
/// [`SendChatAction`]: crate::requests::SendChatAction
|
||||||
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum SendChatActionKind {
|
pub enum SendChatActionKind {
|
||||||
/// For [text messages](crate::Bot::send_message).
|
/// For [text messages](crate::Bot::send_message).
|
||||||
|
@ -72,7 +72,7 @@ pub enum SendChatActionKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendChatAction<'_> {
|
impl Request for SendChatAction {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -86,9 +86,9 @@ impl Request for SendChatAction<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendChatAction<'a> {
|
impl SendChatAction {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
action: SendChatActionKind,
|
action: SendChatActionKind,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -96,7 +96,7 @@ impl<'a> SendChatAction<'a> {
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
action,
|
action,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
types::{ChatId, Message, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send phone contacts.
|
/// Use this method to send phone contacts.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendcontact).
|
/// [The official docs](https://core.telegram.org/bots/api#sendcontact).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendContact<'a> {
|
pub struct SendContact {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
phone_number: String,
|
phone_number: String,
|
||||||
first_name: String,
|
first_name: String,
|
||||||
|
@ -27,7 +27,7 @@ pub struct SendContact<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendContact<'_> {
|
impl Request for SendContact {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -41,9 +41,9 @@ impl Request for SendContact<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendContact<'a> {
|
impl SendContact {
|
||||||
pub(crate) fn new<C, P, F>(
|
pub(crate) fn new<C, P, F>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
phone_number: P,
|
phone_number: P,
|
||||||
first_name: F,
|
first_name: F,
|
||||||
|
@ -57,7 +57,7 @@ impl<'a> SendContact<'a> {
|
||||||
let phone_number = phone_number.into();
|
let phone_number = phone_number.into();
|
||||||
let first_name = first_name.into();
|
let first_name = first_name.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
phone_number,
|
phone_number,
|
||||||
first_name,
|
first_name,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send general files.
|
/// Use this method to send general files.
|
||||||
///
|
///
|
||||||
|
@ -12,9 +12,9 @@ use crate::{
|
||||||
/// may be changed in the future.
|
/// may be changed in the future.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#senddocument).
|
/// [The official docs](https://core.telegram.org/bots/api#senddocument).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendDocument<'a> {
|
pub struct SendDocument {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
document: InputFile,
|
document: InputFile,
|
||||||
thumb: Option<InputFile>,
|
thumb: Option<InputFile>,
|
||||||
|
@ -26,7 +26,7 @@ pub struct SendDocument<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendDocument<'_> {
|
impl Request for SendDocument {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -57,13 +57,13 @@ impl Request for SendDocument<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendDocument<'a> {
|
impl SendDocument {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, document: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, document: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
document,
|
document,
|
||||||
thumb: None,
|
thumb: None,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{InlineKeyboardMarkup, Message},
|
types::{InlineKeyboardMarkup, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send a game.
|
/// Use this method to send a game.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendgame).
|
/// [The official docs](https://core.telegram.org/bots/api#sendgame).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendGame<'a> {
|
pub struct SendGame {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: i32,
|
chat_id: i32,
|
||||||
game_short_name: String,
|
game_short_name: String,
|
||||||
disable_notification: Option<bool>,
|
disable_notification: Option<bool>,
|
||||||
|
@ -24,7 +24,7 @@ pub struct SendGame<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendGame<'_> {
|
impl Request for SendGame {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -38,14 +38,18 @@ impl Request for SendGame<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendGame<'a> {
|
impl SendGame {
|
||||||
pub(crate) fn new<G>(bot: &'a Bot, chat_id: i32, game_short_name: G) -> Self
|
pub(crate) fn new<G>(
|
||||||
|
bot: Arc<Bot>,
|
||||||
|
chat_id: i32,
|
||||||
|
game_short_name: G,
|
||||||
|
) -> Self
|
||||||
where
|
where
|
||||||
G: Into<String>,
|
G: Into<String>,
|
||||||
{
|
{
|
||||||
let game_short_name = game_short_name.into();
|
let game_short_name = game_short_name.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
game_short_name,
|
game_short_name,
|
||||||
disable_notification: None,
|
disable_notification: None,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{InlineKeyboardMarkup, LabeledPrice, Message},
|
types::{InlineKeyboardMarkup, LabeledPrice, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send invoices.
|
/// Use this method to send invoices.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendinvoice).
|
/// [The official docs](https://core.telegram.org/bots/api#sendinvoice).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendInvoice<'a> {
|
pub struct SendInvoice {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: i32,
|
chat_id: i32,
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
@ -42,7 +42,7 @@ pub struct SendInvoice<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendInvoice<'_> {
|
impl Request for SendInvoice {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -56,10 +56,10 @@ impl Request for SendInvoice<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendInvoice<'a> {
|
impl SendInvoice {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn new<T, D, Pl, Pt, S, C, Pr>(
|
pub(crate) fn new<T, D, Pl, Pt, S, C, Pr>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: i32,
|
chat_id: i32,
|
||||||
title: T,
|
title: T,
|
||||||
description: D,
|
description: D,
|
||||||
|
@ -86,7 +86,7 @@ impl<'a> SendInvoice<'a> {
|
||||||
let currency = currency.into();
|
let currency = currency.into();
|
||||||
let prices = prices.into();
|
let prices = prices.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
types::{ChatId, Message, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send point on the map.
|
/// Use this method to send point on the map.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendlocation).
|
/// [The official docs](https://core.telegram.org/bots/api#sendlocation).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendLocation<'a> {
|
pub struct SendLocation {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
|
@ -26,7 +26,7 @@ pub struct SendLocation<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendLocation<'_> {
|
impl Request for SendLocation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -40,9 +40,9 @@ impl Request for SendLocation<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendLocation<'a> {
|
impl SendLocation {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
|
@ -52,7 +52,7 @@ impl<'a> SendLocation<'a> {
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputMedia, Message},
|
types::{ChatId, InputMedia, Message},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send a group of photos or videos as an album.
|
/// Use this method to send a group of photos or videos as an album.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendmediagroup).
|
/// [The official docs](https://core.telegram.org/bots/api#sendmediagroup).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendMediaGroup<'a> {
|
pub struct SendMediaGroup {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
media: Vec<InputMedia>, // TODO: InputMediaPhoto and InputMediaVideo
|
media: Vec<InputMedia>, // TODO: InputMediaPhoto and InputMediaVideo
|
||||||
disable_notification: Option<bool>,
|
disable_notification: Option<bool>,
|
||||||
|
@ -19,7 +19,7 @@ pub struct SendMediaGroup<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendMediaGroup<'_> {
|
impl Request for SendMediaGroup {
|
||||||
type Output = Vec<Message>;
|
type Output = Vec<Message>;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Vec<Message>> {
|
async fn send(&self) -> ResponseResult<Vec<Message>> {
|
||||||
|
@ -42,8 +42,8 @@ impl Request for SendMediaGroup<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendMediaGroup<'a> {
|
impl SendMediaGroup {
|
||||||
pub(crate) fn new<C, M>(bot: &'a Bot, chat_id: C, media: M) -> Self
|
pub(crate) fn new<C, M>(bot: Arc<Bot>, chat_id: C, media: M) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
M: Into<Vec<InputMedia>>,
|
M: Into<Vec<InputMedia>>,
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> SendMediaGroup<'a> {
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
let media = media.into();
|
let media = media.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
media,
|
media,
|
||||||
disable_notification: None,
|
disable_notification: None,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send text messages.
|
/// Use this method to send text messages.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendmessage).
|
/// [The official docs](https://core.telegram.org/bots/api#sendmessage).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendMessage<'a> {
|
pub struct SendMessage {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
pub chat_id: ChatId,
|
pub chat_id: ChatId,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub parse_mode: Option<ParseMode>,
|
pub parse_mode: Option<ParseMode>,
|
||||||
|
@ -26,7 +26,7 @@ pub struct SendMessage<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendMessage<'_> {
|
impl Request for SendMessage {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -40,14 +40,14 @@ impl Request for SendMessage<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendMessage<'a> {
|
impl SendMessage {
|
||||||
pub(crate) fn new<C, T>(bot: &'a Bot, chat_id: C, text: T) -> Self
|
pub(crate) fn new<C, T>(bot: Arc<Bot>, chat_id: C, text: T) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
text: text.into(),
|
text: text.into(),
|
||||||
parse_mode: None,
|
parse_mode: None,
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send photos.
|
/// Use this method to send photos.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendphoto).
|
/// [The official docs](https://core.telegram.org/bots/api#sendphoto).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendPhoto<'a> {
|
pub struct SendPhoto {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
photo: InputFile,
|
photo: InputFile,
|
||||||
caption: Option<String>,
|
caption: Option<String>,
|
||||||
|
@ -22,7 +22,7 @@ pub struct SendPhoto<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendPhoto<'_> {
|
impl Request for SendPhoto {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -51,13 +51,13 @@ impl Request for SendPhoto<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendPhoto<'a> {
|
impl SendPhoto {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, photo: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, photo: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
photo,
|
photo,
|
||||||
caption: None,
|
caption: None,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message, PollType, ReplyMarkup},
|
types::{ChatId, Message, PollType, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send a native poll.
|
/// Use this method to send a native poll.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendpoll).
|
/// [The official docs](https://core.telegram.org/bots/api#sendpoll).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendPoll<'a> {
|
pub struct SendPoll {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
question: String,
|
question: String,
|
||||||
options: Vec<String>,
|
options: Vec<String>,
|
||||||
|
@ -30,7 +30,7 @@ pub struct SendPoll<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendPoll<'_> {
|
impl Request for SendPoll {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -44,9 +44,9 @@ impl Request for SendPoll<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendPoll<'a> {
|
impl SendPoll {
|
||||||
pub(crate) fn new<C, Q, O>(
|
pub(crate) fn new<C, Q, O>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
question: Q,
|
question: Q,
|
||||||
options: O,
|
options: O,
|
||||||
|
@ -60,7 +60,7 @@ impl<'a> SendPoll<'a> {
|
||||||
let question = question.into();
|
let question = question.into();
|
||||||
let options = options.into();
|
let options = options.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
question,
|
question,
|
||||||
options,
|
options,
|
||||||
|
@ -106,6 +106,7 @@ impl<'a> SendPoll<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `true`, if the poll needs to be anonymous, defaults to `true`.
|
/// `true`, if the poll needs to be anonymous, defaults to `true`.
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub fn is_anonymous<T>(mut self, val: T) -> Self
|
pub fn is_anonymous<T>(mut self, val: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<bool>,
|
T: Into<bool>,
|
||||||
|
@ -145,6 +146,7 @@ impl<'a> SendPoll<'a> {
|
||||||
/// Pass `true`, if the poll needs to be immediately closed.
|
/// Pass `true`, if the poll needs to be immediately closed.
|
||||||
///
|
///
|
||||||
/// This can be useful for poll preview.
|
/// This can be useful for poll preview.
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub fn is_closed<T>(mut self, val: T) -> Self
|
pub fn is_closed<T>(mut self, val: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<bool>,
|
T: Into<bool>,
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send static .WEBP or [animated] .TGS stickers.
|
/// Use this method to send static .WEBP or [animated] .TGS stickers.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendsticker).
|
/// [The official docs](https://core.telegram.org/bots/api#sendsticker).
|
||||||
///
|
///
|
||||||
/// [animated]: https://telegram.org/blog/animated-stickers
|
/// [animated]: https://telegram.org/blog/animated-stickers
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendSticker<'a> {
|
pub struct SendSticker {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
sticker: InputFile,
|
sticker: InputFile,
|
||||||
disable_notification: Option<bool>,
|
disable_notification: Option<bool>,
|
||||||
|
@ -22,7 +22,7 @@ pub struct SendSticker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendSticker<'_> {
|
impl Request for SendSticker {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -47,13 +47,13 @@ impl Request for SendSticker<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendSticker<'a> {
|
impl SendSticker {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, sticker: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, sticker: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
sticker,
|
sticker,
|
||||||
disable_notification: None,
|
disable_notification: None,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, Message, ReplyMarkup},
|
types::{ChatId, Message, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send information about a venue.
|
/// Use this method to send information about a venue.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvenue).
|
/// [The official docs](https://core.telegram.org/bots/api#sendvenue).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SendVenue<'a> {
|
pub struct SendVenue {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
|
@ -29,7 +29,7 @@ pub struct SendVenue<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendVenue<'_> {
|
impl Request for SendVenue {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -43,9 +43,9 @@ impl Request for SendVenue<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendVenue<'a> {
|
impl SendVenue {
|
||||||
pub(crate) fn new<C, T, A>(
|
pub(crate) fn new<C, T, A>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
|
@ -61,7 +61,7 @@ impl<'a> SendVenue<'a> {
|
||||||
let title = title.into();
|
let title = title.into();
|
||||||
let address = address.into();
|
let address = address.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send video files, Telegram clients support mp4 videos
|
/// Use this method to send video files, Telegram clients support mp4 videos
|
||||||
/// (other formats may be sent as Document).
|
/// (other formats may be sent as Document).
|
||||||
|
@ -13,9 +13,9 @@ use crate::{
|
||||||
/// limit may be changed in the future.
|
/// limit may be changed in the future.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvideo).
|
/// [The official docs](https://core.telegram.org/bots/api#sendvideo).
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendVideo<'a> {
|
pub struct SendVideo {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
video: InputFile,
|
video: InputFile,
|
||||||
duration: Option<i32>,
|
duration: Option<i32>,
|
||||||
|
@ -31,7 +31,7 @@ pub struct SendVideo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendVideo<'_> {
|
impl Request for SendVideo {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -70,13 +70,13 @@ impl Request for SendVideo<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendVideo<'a> {
|
impl SendVideo {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, video: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, video: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
video,
|
video,
|
||||||
duration: None,
|
duration: None,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// As of [v.4.0], Telegram clients support rounded square mp4 videos of up to 1
|
/// As of [v.4.0], Telegram clients support rounded square mp4 videos of up to 1
|
||||||
/// minute long. Use this method to send video messages.
|
/// minute long. Use this method to send video messages.
|
||||||
|
@ -12,9 +12,9 @@ use crate::{
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#sendvideonote).
|
/// [The official docs](https://core.telegram.org/bots/api#sendvideonote).
|
||||||
///
|
///
|
||||||
/// [v.4.0]: https://telegram.org/blog/video-messages-and-telescope
|
/// [v.4.0]: https://telegram.org/blog/video-messages-and-telescope
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendVideoNote<'a> {
|
pub struct SendVideoNote {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
video_note: InputFile,
|
video_note: InputFile,
|
||||||
duration: Option<i32>,
|
duration: Option<i32>,
|
||||||
|
@ -26,7 +26,7 @@ pub struct SendVideoNote<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendVideoNote<'_> {
|
impl Request for SendVideoNote {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -57,9 +57,9 @@ impl Request for SendVideoNote<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendVideoNote<'a> {
|
impl SendVideoNote {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
video_note: InputFile,
|
video_note: InputFile,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -67,7 +67,7 @@ impl<'a> SendVideoNote<'a> {
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
video_note,
|
video_note,
|
||||||
duration: None,
|
duration: None,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
requests::{form_builder::FormBuilder, Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to send audio files, if you want Telegram clients to display
|
/// Use this method to send audio files, if you want Telegram clients to display
|
||||||
/// the file as a playable voice message.
|
/// the file as a playable voice message.
|
||||||
|
@ -18,9 +18,9 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [`Audio`]: crate::types::Audio
|
/// [`Audio`]: crate::types::Audio
|
||||||
/// [`Document`]: crate::types::Document
|
/// [`Document`]: crate::types::Document
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SendVoice<'a> {
|
pub struct SendVoice {
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
voice: InputFile,
|
voice: InputFile,
|
||||||
caption: Option<String>,
|
caption: Option<String>,
|
||||||
|
@ -32,7 +32,7 @@ pub struct SendVoice<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SendVoice<'_> {
|
impl Request for SendVoice {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
|
@ -63,13 +63,13 @@ impl Request for SendVoice<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SendVoice<'a> {
|
impl SendVoice {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, voice: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, voice: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
voice,
|
voice,
|
||||||
caption: None,
|
caption: None,
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to set a custom title for an administrator in a supergroup
|
/// Use this method to set a custom title for an administrator in a supergroup
|
||||||
/// promoted by the bot.
|
/// promoted by the bot.
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatadministratorcustomtitle).
|
/// [The official docs](https://core.telegram.org/bots/api#setchatadministratorcustomtitle).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetChatAdministratorCustomTitle<'a> {
|
pub struct SetChatAdministratorCustomTitle {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
custom_title: String,
|
custom_title: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SetChatAdministratorCustomTitle<'_> {
|
impl Request for SetChatAdministratorCustomTitle {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -37,9 +37,9 @@ impl Request for SetChatAdministratorCustomTitle<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetChatAdministratorCustomTitle<'a> {
|
impl SetChatAdministratorCustomTitle {
|
||||||
pub(crate) fn new<C, CT>(
|
pub(crate) fn new<C, CT>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
custom_title: CT,
|
custom_title: CT,
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> SetChatAdministratorCustomTitle<'a> {
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
let custom_title = custom_title.into();
|
let custom_title = custom_title.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
custom_title,
|
custom_title,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to change the description of a group, a supergroup or a
|
/// Use this method to change the description of a group, a supergroup or a
|
||||||
/// channel.
|
/// channel.
|
||||||
|
@ -16,16 +16,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatdescription).
|
/// [The official docs](https://core.telegram.org/bots/api#setchatdescription).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetChatDescription<'a> {
|
pub struct SetChatDescription {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SetChatDescription<'_> {
|
impl Request for SetChatDescription {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -39,14 +39,14 @@ impl Request for SetChatDescription<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetChatDescription<'a> {
|
impl SetChatDescription {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
description: None,
|
description: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, ChatPermissions, True},
|
types::{ChatId, ChatPermissions, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to set default chat permissions for all members.
|
/// Use this method to set default chat permissions for all members.
|
||||||
///
|
///
|
||||||
|
@ -15,16 +15,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatpermissions).
|
/// [The official docs](https://core.telegram.org/bots/api#setchatpermissions).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetChatPermissions<'a> {
|
pub struct SetChatPermissions {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
permissions: ChatPermissions,
|
permissions: ChatPermissions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SetChatPermissions<'_> {
|
impl Request for SetChatPermissions {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -38,9 +38,9 @@ impl Request for SetChatPermissions<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetChatPermissions<'a> {
|
impl SetChatPermissions {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
permissions: ChatPermissions,
|
permissions: ChatPermissions,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -49,7 +49,7 @@ impl<'a> SetChatPermissions<'a> {
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
permissions,
|
permissions,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, InputFile, True},
|
types::{ChatId, InputFile, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to set a new profile photo for the chat.
|
/// Use this method to set a new profile photo for the chat.
|
||||||
///
|
///
|
||||||
|
@ -15,16 +15,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatphoto).
|
/// [The official docs](https://core.telegram.org/bots/api#setchatphoto).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetChatPhoto<'a> {
|
pub struct SetChatPhoto {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
photo: InputFile,
|
photo: InputFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SetChatPhoto<'_> {
|
impl Request for SetChatPhoto {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -38,14 +38,14 @@ impl Request for SetChatPhoto<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetChatPhoto<'a> {
|
impl SetChatPhoto {
|
||||||
pub(crate) fn new<C>(bot: &'a Bot, chat_id: C, photo: InputFile) -> Self
|
pub(crate) fn new<C>(bot: Arc<Bot>, chat_id: C, photo: InputFile) -> Self
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
photo,
|
photo,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::BotWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
net,
|
net,
|
||||||
requests::{Request, ResponseResult},
|
requests::{Request, ResponseResult},
|
||||||
types::{ChatId, True},
|
types::{ChatId, True},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Use this method to set a new group sticker set for a supergroup.
|
/// Use this method to set a new group sticker set for a supergroup.
|
||||||
///
|
///
|
||||||
|
@ -16,16 +16,16 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [The official docs](https://core.telegram.org/bots/api#setchatstickerset).
|
/// [The official docs](https://core.telegram.org/bots/api#setchatstickerset).
|
||||||
#[serde_with_macros::skip_serializing_none]
|
#[serde_with_macros::skip_serializing_none]
|
||||||
#[derive(Eq, PartialEq, Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetChatStickerSet<'a> {
|
pub struct SetChatStickerSet {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
bot: BotWrapper<'a>,
|
bot: Arc<Bot>,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
sticker_set_name: String,
|
sticker_set_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Request for SetChatStickerSet<'_> {
|
impl Request for SetChatStickerSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
|
@ -39,9 +39,9 @@ impl Request for SetChatStickerSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SetChatStickerSet<'a> {
|
impl SetChatStickerSet {
|
||||||
pub(crate) fn new<C, S>(
|
pub(crate) fn new<C, S>(
|
||||||
bot: &'a Bot,
|
bot: Arc<Bot>,
|
||||||
chat_id: C,
|
chat_id: C,
|
||||||
sticker_set_name: S,
|
sticker_set_name: S,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -52,7 +52,7 @@ impl<'a> SetChatStickerSet<'a> {
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
let sticker_set_name = sticker_set_name.into();
|
let sticker_set_name = sticker_set_name.into();
|
||||||
Self {
|
Self {
|
||||||
bot: BotWrapper(bot),
|
bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
sticker_set_name,
|
sticker_set_name,
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue