mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-22 06:45:37 +01:00
Use the default characters per line limit
This commit is contained in:
parent
f9c192aad0
commit
38a1f470ad
121 changed files with 521 additions and 1580 deletions
45
README.md
45
README.md
|
@ -100,7 +100,7 @@ async fn main() {
|
||||||
Dispatcher::new(bot)
|
Dispatcher::new(bot)
|
||||||
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
|
.messages_handler(|rx: DispatcherHandlerRx<Message>| {
|
||||||
rx.for_each(|message| async move {
|
rx.for_each(|message| async move {
|
||||||
message.answer("pong").send().await.log_on_error().await;
|
message.answer_str("pong").await.log_on_error().await;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.dispatch()
|
.dispatch()
|
||||||
|
@ -136,28 +136,18 @@ enum Command {
|
||||||
Help,
|
Help,
|
||||||
#[command(description = "handle a username.")]
|
#[command(description = "handle a username.")]
|
||||||
Username(String),
|
Username(String),
|
||||||
#[command(
|
#[command(description = "handle a username and an age.", parse_with = "split")]
|
||||||
description = "handle a username and an age.",
|
|
||||||
parse_with = "split"
|
|
||||||
)]
|
|
||||||
UsernameAndAge { username: String, age: u8 },
|
UsernameAndAge { username: String, age: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn answer(
|
async fn answer(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
command: Command,
|
|
||||||
) -> ResponseResult<()> {
|
|
||||||
match command {
|
match command {
|
||||||
Command::Help => cx.answer(Command::descriptions()).send().await?,
|
Command::Help => cx.answer(Command::descriptions()).send().await?,
|
||||||
Command::Username(username) => {
|
Command::Username(username) => {
|
||||||
cx.answer_str(format!("Your username is @{}.", username)).await?
|
cx.answer_str(format!("Your username is @{}.", username)).await?
|
||||||
}
|
}
|
||||||
Command::UsernameAndAge { username, age } => {
|
Command::UsernameAndAge { username, age } => {
|
||||||
cx.answer_str(format!(
|
cx.answer_str(format!("Your username is @{} and age is {}.", username, age)).await?
|
||||||
"Your username is @{} and age is {}.",
|
|
||||||
username, age
|
|
||||||
))
|
|
||||||
.await?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,6 +166,7 @@ async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// Setup is omitted...
|
// Setup is omitted...
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
@ -195,9 +186,8 @@ Below is a bot, which asks you three questions and then sends the answers back t
|
||||||
```rust
|
```rust
|
||||||
// Imports are omitted...
|
// Imports are omitted...
|
||||||
|
|
||||||
#[derive(Transition, SmartDefault, From)]
|
#[derive(Transition, From)]
|
||||||
pub enum Dialogue {
|
pub enum Dialogue {
|
||||||
#[default]
|
|
||||||
Start(StartState),
|
Start(StartState),
|
||||||
ReceiveFullName(ReceiveFullNameState),
|
ReceiveFullName(ReceiveFullNameState),
|
||||||
ReceiveAge(ReceiveAgeState),
|
ReceiveAge(ReceiveAgeState),
|
||||||
|
@ -219,11 +209,7 @@ impl Default for Dialogue {
|
||||||
pub struct StartState;
|
pub struct StartState;
|
||||||
|
|
||||||
#[teloxide(transition)]
|
#[teloxide(transition)]
|
||||||
async fn start(
|
async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> TransitionOut<Dialogue> {
|
||||||
_state: StartState,
|
|
||||||
cx: TransitionIn,
|
|
||||||
_ans: String,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
cx.answer_str("Let's start! What's your full name?").await?;
|
cx.answer_str("Let's start! What's your full name?").await?;
|
||||||
next(ReceiveFullNameState)
|
next(ReceiveFullNameState)
|
||||||
}
|
}
|
||||||
|
@ -291,11 +277,8 @@ async fn receive_location(
|
||||||
cx: TransitionIn,
|
cx: TransitionIn,
|
||||||
ans: String,
|
ans: String,
|
||||||
) -> TransitionOut<Dialogue> {
|
) -> TransitionOut<Dialogue> {
|
||||||
cx.answer_str(format!(
|
cx.answer_str(format!("Full name: {}\nAge: {}\nLocation: {}", state.full_name, state.age, ans))
|
||||||
"Full name: {}\nAge: {}\nLocation: {}",
|
.await?;
|
||||||
state.full_name, state.age, ans
|
|
||||||
))
|
|
||||||
.await?;
|
|
||||||
exit()
|
exit()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -320,19 +303,14 @@ async fn main() {
|
||||||
|DialogueWithCx { cx, dialogue }: In| async move {
|
|DialogueWithCx { cx, dialogue }: In| async move {
|
||||||
// No panic because of std::convert::Infallible.
|
// No panic because of std::convert::Infallible.
|
||||||
let dialogue = dialogue.unwrap();
|
let dialogue = dialogue.unwrap();
|
||||||
handle_message(cx, dialogue)
|
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
|
||||||
.await
|
|
||||||
.expect("Something wrong with the bot!")
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.dispatch()
|
.dispatch()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_message(
|
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
dialogue: Dialogue,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
match cx.update.text_owned() {
|
match cx.update.text_owned() {
|
||||||
None => {
|
None => {
|
||||||
cx.answer_str("Send me a text message.").await?;
|
cx.answer_str("Send me a text message.").await?;
|
||||||
|
@ -341,6 +319,7 @@ async fn handle_message(
|
||||||
Some(ans) => dialogue.react(cx, ans).await,
|
Some(ans) => dialogue.react(cx, ans).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use teloxide::{
|
use teloxide::{prelude::*, types::ChatPermissions, utils::command::BotCommand};
|
||||||
prelude::*, types::ChatPermissions, utils::command::BotCommand
|
|
||||||
};
|
|
||||||
|
|
||||||
use futures::future;
|
use futures::future;
|
||||||
|
|
||||||
|
@ -81,9 +79,7 @@ async fn mute_user(cx: &Cx, time: u32) -> ResponseResult<()> {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
cx.reply_to("Use this command in reply to another message")
|
cx.reply_to("Use this command in reply to another message").send().await?;
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -94,15 +90,10 @@ async fn kick_user(cx: &Cx) -> ResponseResult<()> {
|
||||||
match cx.update.reply_to_message() {
|
match cx.update.reply_to_message() {
|
||||||
Some(mes) => {
|
Some(mes) => {
|
||||||
// bot.unban_chat_member can also kicks a user from a group chat.
|
// bot.unban_chat_member can also kicks a user from a group chat.
|
||||||
cx.bot
|
cx.bot.unban_chat_member(cx.update.chat_id(), mes.from().unwrap().id).send().await?;
|
||||||
.unban_chat_member(cx.update.chat_id(), mes.from().unwrap().id)
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
cx.reply_to("Use this command in reply to another message")
|
cx.reply_to("Use this command in reply to another message").send().await?;
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -122,29 +113,18 @@ async fn ban_user(cx: &Cx, time: u32) -> ResponseResult<()> {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
cx.reply_to("Use this command in a reply to another message!")
|
cx.reply_to("Use this command in a reply to another message!").send().await?;
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn action(
|
async fn action(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
command: Command,
|
|
||||||
) -> ResponseResult<()> {
|
|
||||||
match command {
|
match command {
|
||||||
Command::Help => {
|
Command::Help => cx.answer(Command::descriptions()).send().await.map(|_| ())?,
|
||||||
cx.answer(Command::descriptions()).send().await.map(|_| ())?
|
|
||||||
}
|
|
||||||
Command::Kick => kick_user(&cx).await?,
|
Command::Kick => kick_user(&cx).await?,
|
||||||
Command::Ban { time, unit } => {
|
Command::Ban { time, unit } => ban_user(&cx, calc_restrict_time(time, unit)).await?,
|
||||||
ban_user(&cx, calc_restrict_time(time, unit)).await?
|
Command::Mute { time, unit } => mute_user(&cx, calc_restrict_time(time, unit)).await?,
|
||||||
}
|
|
||||||
Command::Mute { time, unit } => {
|
|
||||||
mute_user(&cx, calc_restrict_time(time, unit)).await?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::dialogue::{
|
use crate::dialogue::{states::receive_location::ReceiveLocationState, Dialogue};
|
||||||
states::receive_location::ReceiveLocationState, Dialogue,
|
|
||||||
};
|
|
||||||
use teloxide::prelude::*;
|
use teloxide::prelude::*;
|
||||||
use teloxide_macros::teloxide;
|
use teloxide_macros::teloxide;
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,7 @@ async fn receive_location(
|
||||||
cx: TransitionIn,
|
cx: TransitionIn,
|
||||||
ans: String,
|
ans: String,
|
||||||
) -> TransitionOut<Dialogue> {
|
) -> TransitionOut<Dialogue> {
|
||||||
cx.answer_str(format!(
|
cx.answer_str(format!("Full name: {}\nAge: {}\nLocation: {}", state.full_name, state.age, ans))
|
||||||
"Full name: {}\nAge: {}\nLocation: {}",
|
.await?;
|
||||||
state.full_name, state.age, ans
|
|
||||||
))
|
|
||||||
.await?;
|
|
||||||
exit()
|
exit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,7 @@ use teloxide_macros::teloxide;
|
||||||
pub struct StartState;
|
pub struct StartState;
|
||||||
|
|
||||||
#[teloxide(transition)]
|
#[teloxide(transition)]
|
||||||
async fn start(
|
async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> TransitionOut<Dialogue> {
|
||||||
_state: StartState,
|
|
||||||
cx: TransitionIn,
|
|
||||||
_ans: String,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
cx.answer_str("Let's start! What's your full name?").await?;
|
cx.answer_str("Let's start! What's your full name?").await?;
|
||||||
next(ReceiveFullNameState)
|
next(ReceiveFullNameState)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,19 +44,14 @@ async fn run() {
|
||||||
|DialogueWithCx { cx, dialogue }: In| async move {
|
|DialogueWithCx { cx, dialogue }: In| async move {
|
||||||
// No panic because of std::convert::Infallible.
|
// No panic because of std::convert::Infallible.
|
||||||
let dialogue = dialogue.unwrap();
|
let dialogue = dialogue.unwrap();
|
||||||
handle_message(cx, dialogue)
|
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
|
||||||
.await
|
|
||||||
.expect("Something wrong with the bot!")
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.dispatch()
|
.dispatch()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_message(
|
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
dialogue: Dialogue,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
match cx.update.text_owned() {
|
match cx.update.text_owned() {
|
||||||
None => {
|
None => {
|
||||||
cx.answer_str("Send me a text message.").await?;
|
cx.answer_str("Send me a text message.").await?;
|
||||||
|
|
|
@ -14,19 +14,14 @@ async fn main() {
|
||||||
run().await;
|
run().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_rejection(
|
async fn handle_rejection(error: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
||||||
error: warp::Rejection,
|
|
||||||
) -> Result<impl warp::Reply, Infallible> {
|
|
||||||
log::error!("Cannot process the request due to: {:?}", error);
|
log::error!("Cannot process the request due to: {:?}", error);
|
||||||
Ok(StatusCode::INTERNAL_SERVER_ERROR)
|
Ok(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn webhook<'a>(
|
pub async fn webhook<'a>(bot: Bot) -> impl update_listeners::UpdateListener<Infallible> {
|
||||||
bot: Bot,
|
|
||||||
) -> impl update_listeners::UpdateListener<Infallible> {
|
|
||||||
// Heroku defines auto defines a port value
|
// Heroku defines auto defines a port value
|
||||||
let teloxide_token = env::var("TELOXIDE_TOKEN")
|
let teloxide_token = env::var("TELOXIDE_TOKEN").expect("TELOXIDE_TOKEN env variable missing");
|
||||||
.expect("TELOXIDE_TOKEN env variable missing");
|
|
||||||
let port: u16 = env::var("PORT")
|
let port: u16 = env::var("PORT")
|
||||||
.expect("PORT env variable missing")
|
.expect("PORT env variable missing")
|
||||||
.parse()
|
.parse()
|
||||||
|
@ -58,8 +53,7 @@ pub async fn webhook<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Ok(update) = try_parse {
|
if let Ok(update) = try_parse {
|
||||||
tx.send(Ok(update))
|
tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook")
|
||||||
.expect("Cannot send an incoming update from the webhook")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusCode::OK
|
StatusCode::OK
|
||||||
|
@ -87,9 +81,7 @@ async fn run() {
|
||||||
})
|
})
|
||||||
.dispatch_with_listener(
|
.dispatch_with_listener(
|
||||||
webhook(bot).await,
|
webhook(bot).await,
|
||||||
LoggingErrorHandler::with_custom_text(
|
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
||||||
"An error from the update listener",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// The version of ngrok ping-pong-bot, which uses a webhook to receive updates from
|
// The version of ngrok ping-pong-bot, which uses a webhook to receive updates
|
||||||
// Telegram, instead of long polling.
|
// from Telegram, instead of long polling.
|
||||||
|
|
||||||
use teloxide::{dispatching::update_listeners, prelude::*};
|
use teloxide::{dispatching::update_listeners, prelude::*};
|
||||||
|
|
||||||
|
@ -14,16 +14,12 @@ async fn main() {
|
||||||
run().await;
|
run().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_rejection(
|
async fn handle_rejection(error: warp::Rejection) -> Result<impl warp::Reply, Infallible> {
|
||||||
error: warp::Rejection,
|
|
||||||
) -> Result<impl warp::Reply, Infallible> {
|
|
||||||
log::error!("Cannot process the request due to: {:?}", error);
|
log::error!("Cannot process the request due to: {:?}", error);
|
||||||
Ok(StatusCode::INTERNAL_SERVER_ERROR)
|
Ok(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn webhook<'a>(
|
pub async fn webhook<'a>(bot: Bot) -> impl update_listeners::UpdateListener<Infallible> {
|
||||||
bot: Bot,
|
|
||||||
) -> impl update_listeners::UpdateListener<Infallible> {
|
|
||||||
// You might want to specify a self-signed certificate via .certificate
|
// You might want to specify a self-signed certificate via .certificate
|
||||||
// method on SetWebhook.
|
// method on SetWebhook.
|
||||||
bot.set_webhook("Your HTTPS ngrok URL here. Get it by 'ngrok http 80'")
|
bot.set_webhook("Your HTTPS ngrok URL here. Get it by 'ngrok http 80'")
|
||||||
|
@ -37,8 +33,7 @@ pub async fn webhook<'a>(
|
||||||
.and(warp::body::json())
|
.and(warp::body::json())
|
||||||
.map(move |json: serde_json::Value| {
|
.map(move |json: serde_json::Value| {
|
||||||
if let Ok(update) = Update::try_parse(&json) {
|
if let Ok(update) = Update::try_parse(&json) {
|
||||||
tx.send(Ok(update))
|
tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook")
|
||||||
.expect("Cannot send an incoming update from the webhook")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusCode::OK
|
StatusCode::OK
|
||||||
|
@ -68,9 +63,7 @@ async fn run() {
|
||||||
})
|
})
|
||||||
.dispatch_with_listener(
|
.dispatch_with_listener(
|
||||||
webhook(bot).await,
|
webhook(bot).await,
|
||||||
LoggingErrorHandler::with_custom_text(
|
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
||||||
"An error from the update listener",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,26 +38,19 @@ async fn run() {
|
||||||
|DialogueWithCx { cx, dialogue }: In| async move {
|
|DialogueWithCx { cx, dialogue }: In| async move {
|
||||||
// No panic because of std::convert::Infallible.
|
// No panic because of std::convert::Infallible.
|
||||||
let dialogue = dialogue.unwrap();
|
let dialogue = dialogue.unwrap();
|
||||||
handle_message(cx, dialogue)
|
handle_message(cx, dialogue).await.expect("Something wrong with the bot!")
|
||||||
.await
|
|
||||||
.expect("Something wrong with the bot!")
|
|
||||||
},
|
},
|
||||||
// You can also choose serializer::JSON or serializer::CBOR
|
// You can also choose serializer::JSON or serializer::CBOR
|
||||||
// All serializers but JSON require enabling feature
|
// All serializers but JSON require enabling feature
|
||||||
// "serializer-<name>", e. g. "serializer-cbor"
|
// "serializer-<name>", e. g. "serializer-cbor"
|
||||||
// or "serializer-bincode"
|
// or "serializer-bincode"
|
||||||
RedisStorage::open("redis://127.0.0.1:6379", Bincode)
|
RedisStorage::open("redis://127.0.0.1:6379", Bincode).await.unwrap(),
|
||||||
.await
|
|
||||||
.unwrap(),
|
|
||||||
))
|
))
|
||||||
.dispatch()
|
.dispatch()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_message(
|
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
dialogue: Dialogue,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
match cx.update.text_owned() {
|
match cx.update.text_owned() {
|
||||||
None => {
|
None => {
|
||||||
cx.answer_str("Send me a text message.").await?;
|
cx.answer_str("Send me a text message.").await?;
|
||||||
|
|
|
@ -4,17 +4,9 @@ use teloxide_macros::teloxide;
|
||||||
use super::states::*;
|
use super::states::*;
|
||||||
|
|
||||||
#[teloxide(transition)]
|
#[teloxide(transition)]
|
||||||
async fn start(
|
async fn start(state: StartState, cx: TransitionIn, ans: String) -> TransitionOut<Dialogue> {
|
||||||
state: StartState,
|
|
||||||
cx: TransitionIn,
|
|
||||||
ans: String,
|
|
||||||
) -> TransitionOut<Dialogue> {
|
|
||||||
if let Ok(number) = ans.parse() {
|
if let Ok(number) = ans.parse() {
|
||||||
cx.answer_str(format!(
|
cx.answer_str(format!("Remembered number {}. Now use /get or /reset", number)).await?;
|
||||||
"Remembered number {}. Now use /get or /reset",
|
|
||||||
number
|
|
||||||
))
|
|
||||||
.await?;
|
|
||||||
next(HaveNumberState { number })
|
next(HaveNumberState { number })
|
||||||
} else {
|
} else {
|
||||||
cx.answer_str("Please, send me a number").await?;
|
cx.answer_str("Please, send me a number").await?;
|
||||||
|
|
|
@ -26,10 +26,7 @@ async fn run() {
|
||||||
let previous = MESSAGES_TOTAL.fetch_add(1, Ordering::Relaxed);
|
let previous = MESSAGES_TOTAL.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
message
|
message
|
||||||
.answer_str(format!(
|
.answer_str(format!("I received {} messages in total.", previous))
|
||||||
"I received {} messages in total.",
|
|
||||||
previous
|
|
||||||
))
|
|
||||||
.await
|
.await
|
||||||
.log_on_error()
|
.log_on_error()
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -7,28 +7,18 @@ enum Command {
|
||||||
Help,
|
Help,
|
||||||
#[command(description = "handle a username.")]
|
#[command(description = "handle a username.")]
|
||||||
Username(String),
|
Username(String),
|
||||||
#[command(
|
#[command(description = "handle a username and an age.", parse_with = "split")]
|
||||||
description = "handle a username and an age.",
|
|
||||||
parse_with = "split"
|
|
||||||
)]
|
|
||||||
UsernameAndAge { username: String, age: u8 },
|
UsernameAndAge { username: String, age: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn answer(
|
async fn answer(cx: UpdateWithCx<Message>, command: Command) -> ResponseResult<()> {
|
||||||
cx: UpdateWithCx<Message>,
|
|
||||||
command: Command,
|
|
||||||
) -> ResponseResult<()> {
|
|
||||||
match command {
|
match command {
|
||||||
Command::Help => cx.answer(Command::descriptions()).send().await?,
|
Command::Help => cx.answer(Command::descriptions()).send().await?,
|
||||||
Command::Username(username) => {
|
Command::Username(username) => {
|
||||||
cx.answer_str(format!("Your username is @{}.", username)).await?
|
cx.answer_str(format!("Your username is @{}.", username)).await?
|
||||||
}
|
}
|
||||||
Command::UsernameAndAge { username, age } => {
|
Command::UsernameAndAge { username, age } => {
|
||||||
cx.answer_str(format!(
|
cx.answer_str(format!("Your username is @{} and age is {}.", username, age)).await?
|
||||||
"Your username is @{} and age is {}.",
|
|
||||||
username, age
|
|
||||||
))
|
|
||||||
.await?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
format_code_in_doc_comments = true
|
format_code_in_doc_comments = true
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
format_strings = true
|
format_strings = true
|
||||||
max_width = 80
|
|
||||||
merge_imports = true
|
merge_imports = true
|
||||||
use_small_heuristics = "Max"
|
use_small_heuristics = "Max"
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
|
|
237
src/bot/api.rs
237
src/bot/api.rs
|
@ -1,27 +1,23 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
requests::{
|
requests::{
|
||||||
AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery,
|
AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery, AnswerPreCheckoutQuery,
|
||||||
AnswerPreCheckoutQuery, AnswerShippingQuery, CreateNewStickerSet,
|
AnswerShippingQuery, CreateNewStickerSet, DeleteChatPhoto, DeleteChatStickerSet,
|
||||||
DeleteChatPhoto, DeleteChatStickerSet, DeleteMessage,
|
DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditMessageCaption,
|
||||||
DeleteStickerFromSet, DeleteWebhook, EditMessageCaption,
|
EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup, EditMessageText,
|
||||||
EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup,
|
ExportChatInviteLink, ForwardMessage, GetChat, GetChatAdministrators, GetChatMember,
|
||||||
EditMessageText, ExportChatInviteLink, ForwardMessage, GetChat,
|
GetChatMembersCount, GetFile, GetGameHighScores, GetMe, GetStickerSet, GetUpdates,
|
||||||
GetChatAdministrators, GetChatMember, GetChatMembersCount, GetFile,
|
GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat, PinChatMessage,
|
||||||
GetGameHighScores, GetMe, GetStickerSet, GetUpdates,
|
PromoteChatMember, RestrictChatMember, SendAnimation, SendAudio, SendChatAction,
|
||||||
GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat,
|
SendChatActionKind, SendContact, SendDocument, SendGame, SendInvoice, SendLocation,
|
||||||
PinChatMessage, PromoteChatMember, RestrictChatMember, SendAnimation,
|
SendMediaGroup, SendMessage, SendPhoto, SendPoll, SendSticker, SendVenue, SendVideo,
|
||||||
SendAudio, SendChatAction, SendChatActionKind, SendContact,
|
SendVideoNote, SendVoice, SetChatAdministratorCustomTitle, SetChatDescription,
|
||||||
SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup,
|
SetChatPermissions, SetChatPhoto, SetChatStickerSet, SetChatTitle, SetGameScore,
|
||||||
SendMessage, SendPhoto, SendPoll, SendSticker, SendVenue, SendVideo,
|
SetStickerPositionInSet, SetWebhook, StopMessageLiveLocation, StopPoll, UnbanChatMember,
|
||||||
SendVideoNote, SendVoice, SetChatAdministratorCustomTitle,
|
|
||||||
SetChatDescription, SetChatPermissions, SetChatPhoto,
|
|
||||||
SetChatStickerSet, SetChatTitle, SetGameScore, SetStickerPositionInSet,
|
|
||||||
SetWebhook, StopMessageLiveLocation, StopPoll, UnbanChatMember,
|
|
||||||
UnpinChatMessage, UploadStickerFile,
|
UnpinChatMessage, UploadStickerFile,
|
||||||
},
|
},
|
||||||
types::{
|
types::{
|
||||||
ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult,
|
ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||||
InputFile, InputMedia, LabeledPrice,
|
LabeledPrice,
|
||||||
},
|
},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
@ -121,8 +117,9 @@ impl Bot {
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendMessage::new(self.clone(), chat_id, text),
|
None => SendMessage::new(self.clone(), chat_id, text),
|
||||||
Some(parse_mode) => SendMessage::new(self.clone(), chat_id, text)
|
Some(parse_mode) => {
|
||||||
.parse_mode(*parse_mode.deref()),
|
SendMessage::new(self.clone(), chat_id, text).parse_mode(*parse_mode.deref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +181,9 @@ impl Bot {
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendPhoto::new(self.clone(), chat_id, photo),
|
None => SendPhoto::new(self.clone(), chat_id, photo),
|
||||||
Some(parse_mode) => SendPhoto::new(self.clone(), chat_id, photo)
|
Some(parse_mode) => {
|
||||||
.parse_mode(*parse_mode.deref()),
|
SendPhoto::new(self.clone(), chat_id, photo).parse_mode(*parse_mode.deref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,8 +204,9 @@ impl Bot {
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendAudio::new(self.clone(), chat_id, audio),
|
None => SendAudio::new(self.clone(), chat_id, audio),
|
||||||
Some(parse_mode) => SendAudio::new(self.clone(), chat_id, audio)
|
Some(parse_mode) => {
|
||||||
.parse_mode(*parse_mode.deref()),
|
SendAudio::new(self.clone(), chat_id, audio).parse_mode(*parse_mode.deref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,19 +234,14 @@ impl Bot {
|
||||||
///
|
///
|
||||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||||
/// [`BotBuilder`]: crate::BotBuilder
|
/// [`BotBuilder`]: crate::BotBuilder
|
||||||
pub fn send_document<C>(
|
pub fn send_document<C>(&self, chat_id: C, document: InputFile) -> SendDocument
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
document: InputFile,
|
|
||||||
) -> SendDocument
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendDocument::new(self.clone(), chat_id, document),
|
None => SendDocument::new(self.clone(), chat_id, document),
|
||||||
Some(parse_mode) => {
|
Some(parse_mode) => {
|
||||||
SendDocument::new(self.clone(), chat_id, document)
|
SendDocument::new(self.clone(), chat_id, document).parse_mode(*parse_mode.deref())
|
||||||
.parse_mode(*parse_mode.deref())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,8 +279,9 @@ impl Bot {
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendVideo::new(self.clone(), chat_id, video),
|
None => SendVideo::new(self.clone(), chat_id, video),
|
||||||
Some(parse_mode) => SendVideo::new(self.clone(), chat_id, video)
|
Some(parse_mode) => {
|
||||||
.parse_mode(*parse_mode.deref()),
|
SendVideo::new(self.clone(), chat_id, video).parse_mode(*parse_mode.deref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,19 +303,14 @@ impl Bot {
|
||||||
///
|
///
|
||||||
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
/// [a default parse mode]: crate::BotBuilder::parse_mode
|
||||||
/// [`BotBuilder`]: crate::BotBuilder
|
/// [`BotBuilder`]: crate::BotBuilder
|
||||||
pub fn send_animation<C>(
|
pub fn send_animation<C>(&self, chat_id: C, animation: InputFile) -> SendAnimation
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
animation: InputFile,
|
|
||||||
) -> SendAnimation
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendAnimation::new(self.clone(), chat_id, animation),
|
None => SendAnimation::new(self.clone(), chat_id, animation),
|
||||||
Some(parse_mode) => {
|
Some(parse_mode) => {
|
||||||
SendAnimation::new(self.clone(), chat_id, animation)
|
SendAnimation::new(self.clone(), chat_id, animation).parse_mode(*parse_mode.deref())
|
||||||
.parse_mode(*parse_mode.deref())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,8 +354,9 @@ impl Bot {
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => SendVoice::new(self.clone(), chat_id, voice),
|
None => SendVoice::new(self.clone(), chat_id, voice),
|
||||||
Some(parse_mode) => SendVoice::new(self.clone(), chat_id, voice)
|
Some(parse_mode) => {
|
||||||
.parse_mode(*parse_mode.deref()),
|
SendVoice::new(self.clone(), chat_id, voice).parse_mode(*parse_mode.deref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,11 +381,7 @@ impl Bot {
|
||||||
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
/// [`InputFile::FileId`]: crate::types::InputFile::FileId
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
||||||
|
|
||||||
pub fn send_video_note<C>(
|
pub fn send_video_note<C>(&self, chat_id: C, video_note: InputFile) -> SendVideoNote
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
video_note: InputFile,
|
|
||||||
) -> SendVideoNote
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -427,12 +414,7 @@ impl Bot {
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `latitude`: Latitude of the location.
|
/// - `latitude`: Latitude of the location.
|
||||||
/// - `longitude`: Latitude of the location.
|
/// - `longitude`: Latitude of the location.
|
||||||
pub fn send_location<C>(
|
pub fn send_location<C>(&self, chat_id: C, latitude: f32, longitude: f32) -> SendLocation
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
) -> SendLocation
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -460,12 +442,7 @@ impl Bot {
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
) -> EditMessageLiveLocation {
|
) -> EditMessageLiveLocation {
|
||||||
EditMessageLiveLocation::new(
|
EditMessageLiveLocation::new(self.clone(), chat_or_inline_message, latitude, longitude)
|
||||||
self.clone(),
|
|
||||||
chat_or_inline_message,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use this method to stop updating a live location message before
|
/// Use this method to stop updating a live location message before
|
||||||
|
@ -509,14 +486,7 @@ impl Bot {
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
A: Into<String>,
|
A: Into<String>,
|
||||||
{
|
{
|
||||||
SendVenue::new(
|
SendVenue::new(self.clone(), chat_id, latitude, longitude, title, address)
|
||||||
self.clone(),
|
|
||||||
chat_id,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
title,
|
|
||||||
address,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use this method to send phone contacts.
|
/// Use this method to send phone contacts.
|
||||||
|
@ -529,12 +499,7 @@ impl Bot {
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `phone_number`: Contact's phone number.
|
/// - `phone_number`: Contact's phone number.
|
||||||
/// - `first_name`: Contact's first name.
|
/// - `first_name`: Contact's first name.
|
||||||
pub fn send_contact<C, P, F>(
|
pub fn send_contact<C, P, F>(&self, chat_id: C, phone_number: P, first_name: F) -> SendContact
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
phone_number: P,
|
|
||||||
first_name: F,
|
|
||||||
) -> SendContact
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
P: Into<String>,
|
P: Into<String>,
|
||||||
|
@ -555,12 +520,7 @@ impl Bot {
|
||||||
/// - `question`: Poll question, 1-255 characters.
|
/// - `question`: Poll question, 1-255 characters.
|
||||||
/// - `options`: List of answer options, 2-10 strings 1-100 characters
|
/// - `options`: List of answer options, 2-10 strings 1-100 characters
|
||||||
/// each.
|
/// each.
|
||||||
pub fn send_poll<C, Q, O>(
|
pub fn send_poll<C, Q, O>(&self, chat_id: C, question: Q, options: O) -> SendPoll
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
question: Q,
|
|
||||||
options: O,
|
|
||||||
) -> SendPoll
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
Q: Into<String>,
|
Q: Into<String>,
|
||||||
|
@ -592,11 +552,7 @@ impl Bot {
|
||||||
///
|
///
|
||||||
/// [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
|
||||||
pub fn send_chat_action<C>(
|
pub fn send_chat_action<C>(&self, chat_id: C, action: SendChatActionKind) -> SendChatAction
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
action: SendChatActionKind,
|
|
||||||
) -> SendChatAction
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -609,10 +565,7 @@ impl Bot {
|
||||||
///
|
///
|
||||||
/// # Params
|
/// # Params
|
||||||
/// - `user_id`: Unique identifier of the target user.
|
/// - `user_id`: Unique identifier of the target user.
|
||||||
pub fn get_user_profile_photos(
|
pub fn get_user_profile_photos(&self, user_id: i32) -> GetUserProfilePhotos {
|
||||||
&self,
|
|
||||||
user_id: i32,
|
|
||||||
) -> GetUserProfilePhotos {
|
|
||||||
GetUserProfilePhotos::new(self.clone(), user_id)
|
GetUserProfilePhotos::new(self.clone(), user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,11 +613,7 @@ impl Bot {
|
||||||
/// - `user_id`: Unique identifier of the target user.
|
/// - `user_id`: Unique identifier of the target user.
|
||||||
///
|
///
|
||||||
/// [unbanned]: crate::Bot::unban_chat_member
|
/// [unbanned]: crate::Bot::unban_chat_member
|
||||||
pub fn kick_chat_member<C>(
|
pub fn kick_chat_member<C>(&self, chat_id: C, user_id: i32) -> KickChatMember
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
user_id: i32,
|
|
||||||
) -> KickChatMember
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -682,11 +631,7 @@ impl Bot {
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `user_id`: Unique identifier of the target user.
|
/// - `user_id`: Unique identifier of the target user.
|
||||||
pub fn unban_chat_member<C>(
|
pub fn unban_chat_member<C>(&self, chat_id: C, user_id: i32) -> UnbanChatMember
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
user_id: i32,
|
|
||||||
) -> UnbanChatMember
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -731,11 +676,7 @@ impl Bot {
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `user_id`: Unique identifier of the target user.
|
/// - `user_id`: Unique identifier of the target user.
|
||||||
pub fn promote_chat_member<C>(
|
pub fn promote_chat_member<C>(&self, chat_id: C, user_id: i32) -> PromoteChatMember
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
user_id: i32,
|
|
||||||
) -> PromoteChatMember
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -806,11 +747,7 @@ impl Bot {
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `photo`: New chat photo, uploaded using `multipart/form-data`.
|
/// - `photo`: New chat photo, uploaded using `multipart/form-data`.
|
||||||
pub fn set_chat_photo<C>(
|
pub fn set_chat_photo<C>(&self, chat_id: C, photo: InputFile) -> SetChatPhoto
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
photo: InputFile,
|
|
||||||
) -> SetChatPhoto
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -883,11 +820,7 @@ impl Bot {
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
/// - `message_id`: Identifier of a message to pin.
|
/// - `message_id`: Identifier of a message to pin.
|
||||||
pub fn pin_chat_message<C>(
|
pub fn pin_chat_message<C>(&self, chat_id: C, message_id: i32) -> PinChatMessage
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
message_id: i32,
|
|
||||||
) -> PinChatMessage
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -953,10 +886,7 @@ impl Bot {
|
||||||
/// # Params
|
/// # Params
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target supergroup or channel (in the format `@channelusername`).
|
/// target supergroup or channel (in the format `@channelusername`).
|
||||||
pub fn get_chat_administrators<C>(
|
pub fn get_chat_administrators<C>(&self, chat_id: C) -> GetChatAdministrators
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
) -> GetChatAdministrators
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -1006,11 +936,7 @@ impl Bot {
|
||||||
/// target supergroup (in the format `@supergroupusername`).
|
/// target supergroup (in the format `@supergroupusername`).
|
||||||
/// - `sticker_set_name`: Name of the sticker set to be set as the group
|
/// - `sticker_set_name`: Name of the sticker set to be set as the group
|
||||||
/// sticker set.
|
/// sticker set.
|
||||||
pub fn set_chat_sticker_set<C, S>(
|
pub fn set_chat_sticker_set<C, S>(&self, chat_id: C, sticker_set_name: S) -> SetChatStickerSet
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
sticker_set_name: S,
|
|
||||||
) -> SetChatStickerSet
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
|
@ -1051,10 +977,7 @@ impl Bot {
|
||||||
/// - `callback_query_id`: Unique identifier for the query to be answered.
|
/// - `callback_query_id`: Unique identifier for the query to be answered.
|
||||||
///
|
///
|
||||||
/// [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
|
||||||
pub fn answer_callback_query<C>(
|
pub fn answer_callback_query<C>(&self, callback_query_id: C) -> AnswerCallbackQuery
|
||||||
&self,
|
|
||||||
callback_query_id: C,
|
|
||||||
) -> AnswerCallbackQuery
|
|
||||||
where
|
where
|
||||||
C: Into<String>,
|
C: Into<String>,
|
||||||
{
|
{
|
||||||
|
@ -1088,13 +1011,9 @@ impl Bot {
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => {
|
None => EditMessageText::new(self.clone(), chat_or_inline_message, text),
|
||||||
EditMessageText::new(self.clone(), chat_or_inline_message, text)
|
Some(parse_mode) => EditMessageText::new(self.clone(), chat_or_inline_message, text)
|
||||||
}
|
.parse_mode(*parse_mode.deref()),
|
||||||
Some(parse_mode) => {
|
|
||||||
EditMessageText::new(self.clone(), chat_or_inline_message, text)
|
|
||||||
.parse_mode(*parse_mode.deref())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1118,13 +1037,9 @@ impl Bot {
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
chat_or_inline_message: ChatOrInlineMessage,
|
||||||
) -> EditMessageCaption {
|
) -> EditMessageCaption {
|
||||||
match self.parse_mode.deref() {
|
match self.parse_mode.deref() {
|
||||||
None => {
|
None => EditMessageCaption::new(self.clone(), chat_or_inline_message),
|
||||||
EditMessageCaption::new(self.clone(), chat_or_inline_message)
|
Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_or_inline_message)
|
||||||
}
|
.parse_mode(*parse_mode.deref()),
|
||||||
Some(parse_mode) => {
|
|
||||||
EditMessageCaption::new(self.clone(), chat_or_inline_message)
|
|
||||||
.parse_mode(*parse_mode.deref())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,11 +1117,7 @@ impl Bot {
|
||||||
/// - `chat_id`: Unique identifier for the target chat or username of the
|
/// - `chat_id`: Unique identifier for the target chat or username of the
|
||||||
/// target channel (in the format `@channelusername`).
|
/// target channel (in the format `@channelusername`).
|
||||||
/// - `message_id`: Identifier of the message to delete.
|
/// - `message_id`: Identifier of the message to delete.
|
||||||
pub fn delete_message<C>(
|
pub fn delete_message<C>(&self, chat_id: C, message_id: i32) -> DeleteMessage
|
||||||
&self,
|
|
||||||
chat_id: C,
|
|
||||||
message_id: i32,
|
|
||||||
) -> DeleteMessage
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
@ -1268,11 +1179,7 @@ impl Bot {
|
||||||
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
/// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files
|
||||||
/// [`Bot::create_new_sticker_set`]: crate::Bot::create_new_sticker_set
|
/// [`Bot::create_new_sticker_set`]: crate::Bot::create_new_sticker_set
|
||||||
/// [`Bot::add_sticker_to_set`]: crate::Bot::add_sticker_to_set
|
/// [`Bot::add_sticker_to_set`]: crate::Bot::add_sticker_to_set
|
||||||
pub fn upload_sticker_file(
|
pub fn upload_sticker_file(&self, user_id: i32, png_sticker: InputFile) -> UploadStickerFile {
|
||||||
&self,
|
|
||||||
user_id: i32,
|
|
||||||
png_sticker: InputFile,
|
|
||||||
) -> UploadStickerFile {
|
|
||||||
UploadStickerFile::new(self.clone(), user_id, png_sticker)
|
UploadStickerFile::new(self.clone(), user_id, png_sticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1317,14 +1224,7 @@ impl Bot {
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
E: Into<String>,
|
E: Into<String>,
|
||||||
{
|
{
|
||||||
CreateNewStickerSet::new(
|
CreateNewStickerSet::new(self.clone(), user_id, name, title, png_sticker, emojis)
|
||||||
self.clone(),
|
|
||||||
user_id,
|
|
||||||
name,
|
|
||||||
title,
|
|
||||||
png_sticker,
|
|
||||||
emojis,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -1402,11 +1302,7 @@ impl Bot {
|
||||||
/// # Params
|
/// # Params
|
||||||
/// - `inline_query_id`: Unique identifier for the answered query.
|
/// - `inline_query_id`: Unique identifier for the answered query.
|
||||||
/// - `results`: A JSON-serialized array of results for the inline query.
|
/// - `results`: A JSON-serialized array of results for the inline query.
|
||||||
pub fn answer_inline_query<I, R>(
|
pub fn answer_inline_query<I, R>(&self, inline_query_id: I, results: R) -> AnswerInlineQuery
|
||||||
&self,
|
|
||||||
inline_query_id: I,
|
|
||||||
results: R,
|
|
||||||
) -> AnswerInlineQuery
|
|
||||||
where
|
where
|
||||||
I: Into<String>,
|
I: Into<String>,
|
||||||
R: Into<Vec<InlineQueryResult>>,
|
R: Into<Vec<InlineQueryResult>>,
|
||||||
|
@ -1484,11 +1380,7 @@ impl Bot {
|
||||||
/// delivery to the specified address is not possible).
|
/// delivery to the specified address is not possible).
|
||||||
///
|
///
|
||||||
/// [`Update`]: crate::types::Update
|
/// [`Update`]: crate::types::Update
|
||||||
pub fn answer_shipping_query<S>(
|
pub fn answer_shipping_query<S>(&self, shipping_query_id: S, ok: bool) -> AnswerShippingQuery
|
||||||
&self,
|
|
||||||
shipping_query_id: S,
|
|
||||||
ok: bool,
|
|
||||||
) -> AnswerShippingQuery
|
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
|
@ -1607,11 +1499,6 @@ impl Bot {
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
CT: Into<String>,
|
CT: Into<String>,
|
||||||
{
|
{
|
||||||
SetChatAdministratorCustomTitle::new(
|
SetChatAdministratorCustomTitle::new(self.clone(), chat_id, user_id, custom_title)
|
||||||
self.clone(),
|
|
||||||
chat_id,
|
|
||||||
user_id,
|
|
||||||
custom_title,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,7 @@ impl Bot {
|
||||||
pub async fn download_file_stream(
|
pub async fn download_file_stream(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<impl Stream<Item = Result<Bytes, reqwest::Error>>, reqwest::Error>
|
) -> Result<impl Stream<Item = Result<Bytes, reqwest::Error>>, reqwest::Error> {
|
||||||
{
|
|
||||||
download_file_stream(&self.client, &self.token, path).await
|
download_file_stream(&self.client, &self.token, path).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,7 @@ pub(crate) fn build_sound_bot() -> Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_token_from_env() -> String {
|
fn get_token_from_env() -> String {
|
||||||
std::env::var("TELOXIDE_TOKEN")
|
std::env::var("TELOXIDE_TOKEN").expect("Cannot get the TELOXIDE_TOKEN env variable")
|
||||||
.expect("Cannot get the TELOXIDE_TOKEN env variable")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bot {
|
impl Bot {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::dispatching::{
|
use crate::dispatching::{
|
||||||
dialogue::{
|
dialogue::{
|
||||||
DialogueDispatcherHandler, DialogueStage, DialogueWithCx, GetChatId,
|
DialogueDispatcherHandler, DialogueStage, DialogueWithCx, GetChatId, InMemStorage, Storage,
|
||||||
InMemStorage, Storage,
|
|
||||||
},
|
},
|
||||||
DispatcherHandler, UpdateWithCx,
|
DispatcherHandler, UpdateWithCx,
|
||||||
};
|
};
|
||||||
|
@ -100,13 +99,10 @@ where
|
||||||
|
|
||||||
match handler.handle(DialogueWithCx { cx, dialogue }).await {
|
match handler.handle(DialogueWithCx { cx, dialogue }).await {
|
||||||
DialogueStage::Next(new_dialogue) => {
|
DialogueStage::Next(new_dialogue) => {
|
||||||
if let Ok(Some(_)) =
|
if let Ok(Some(_)) = storage.update_dialogue(chat_id, new_dialogue).await {
|
||||||
storage.update_dialogue(chat_id, new_dialogue).await
|
|
||||||
{
|
|
||||||
panic!(
|
panic!(
|
||||||
"Oops, you have an bug in your Storage: \
|
"Oops, you have an bug in your Storage: update_dialogue returns \
|
||||||
update_dialogue returns Some after \
|
Some after remove_dialogue"
|
||||||
remove_dialogue"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,10 +131,7 @@ where
|
||||||
S: Storage<D> + Send + Sync + 'static,
|
S: Storage<D> + Send + Sync + 'static,
|
||||||
S::Error: Send + 'static,
|
S::Error: Send + 'static,
|
||||||
{
|
{
|
||||||
fn handle(
|
fn handle(self, updates: mpsc::UnboundedReceiver<UpdateWithCx<Upd>>) -> BoxFuture<'static, ()>
|
||||||
self,
|
|
||||||
updates: mpsc::UnboundedReceiver<UpdateWithCx<Upd>>,
|
|
||||||
) -> BoxFuture<'static, ()>
|
|
||||||
where
|
where
|
||||||
UpdateWithCx<Upd>: 'static,
|
UpdateWithCx<Upd>: 'static,
|
||||||
{
|
{
|
||||||
|
@ -152,19 +145,13 @@ where
|
||||||
// An old dialogue
|
// An old dialogue
|
||||||
Some(tx) => {
|
Some(tx) => {
|
||||||
if tx.1.send(cx).is_err() {
|
if tx.1.send(cx).is_err() {
|
||||||
panic!(
|
panic!("We are not dropping a receiver or call .close() on it",);
|
||||||
"We are not dropping a receiver or call .close() \
|
|
||||||
on it",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let tx = this.new_tx();
|
let tx = this.new_tx();
|
||||||
if tx.send(cx).is_err() {
|
if tx.send(cx).is_err() {
|
||||||
panic!(
|
panic!("We are not dropping a receiver or call .close() on it",);
|
||||||
"We are not dropping a receiver or call .close() \
|
|
||||||
on it",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.senders.insert(chat_id, tx);
|
this.senders.insert(chat_id, tx);
|
||||||
}
|
}
|
||||||
|
@ -214,8 +201,8 @@ mod tests {
|
||||||
static ref SEQ3: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
static ref SEQ3: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatcher = DialogueDispatcher::new(
|
let dispatcher =
|
||||||
|cx: DialogueWithCx<MyUpdate, (), Infallible>| async move {
|
DialogueDispatcher::new(|cx: DialogueWithCx<MyUpdate, (), Infallible>| async move {
|
||||||
delay_for(Duration::from_millis(300)).await;
|
delay_for(Duration::from_millis(300)).await;
|
||||||
|
|
||||||
match cx.cx.update {
|
match cx.cx.update {
|
||||||
|
@ -232,8 +219,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogueStage::Next(())
|
DialogueStage::Next(())
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
let updates = stream::iter(
|
let updates = stream::iter(
|
||||||
vec![
|
vec![
|
||||||
|
@ -260,10 +246,7 @@ mod tests {
|
||||||
MyUpdate::new(3, 1611),
|
MyUpdate::new(3, 1611),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|update| UpdateWithCx {
|
.map(|update| UpdateWithCx { update, bot: Bot::new("Doesn't matter here") })
|
||||||
update,
|
|
||||||
bot: Bot::new("Doesn't matter here"),
|
|
||||||
})
|
|
||||||
.collect::<Vec<UpdateWithCx<MyUpdate>>>(),
|
.collect::<Vec<UpdateWithCx<MyUpdate>>>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -287,13 +270,7 @@ mod tests {
|
||||||
delay_for(Duration::from_millis(3000)).await;
|
delay_for(Duration::from_millis(3000)).await;
|
||||||
|
|
||||||
assert_eq!(*SEQ1.lock().await, vec![174, 125, 2, 193, 104, 7, 7778]);
|
assert_eq!(*SEQ1.lock().await, vec![174, 125, 2, 193, 104, 7, 7778]);
|
||||||
assert_eq!(
|
assert_eq!(*SEQ2.lock().await, vec![411, 515, 623, 2222, 737, 10, 55456]);
|
||||||
*SEQ2.lock().await,
|
assert_eq!(*SEQ3.lock().await, vec![72782, 2737, 5475, 1096, 872, 5665, 1611]);
|
||||||
vec![411, 515, 623, 2222, 737, 10, 55456]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
*SEQ3.lock().await,
|
|
||||||
vec![72782, 2737, 5475, 1096, 872, 5665, 1611]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,7 @@ where
|
||||||
F: Fn(DialogueWithCx<Upd, D, E>) -> Fut + Send + Sync + 'static,
|
F: Fn(DialogueWithCx<Upd, D, E>) -> Fut + Send + Sync + 'static,
|
||||||
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
Fut: Future<Output = DialogueStage<D>> + Send + 'static,
|
||||||
{
|
{
|
||||||
fn handle(
|
fn handle(self: Arc<Self>, cx: DialogueWithCx<Upd, D, E>) -> BoxFuture<'static, Fut::Output>
|
||||||
self: Arc<Self>,
|
|
||||||
cx: DialogueWithCx<Upd, D, E>,
|
|
||||||
) -> BoxFuture<'static, Fut::Output>
|
|
||||||
where
|
where
|
||||||
DialogueWithCx<Upd, D, E>: Send + 'static,
|
DialogueWithCx<Upd, D, E>: Send + 'static,
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,8 +153,7 @@ pub use dialogue_stage::{exit, next, DialogueStage};
|
||||||
pub use dialogue_with_cx::DialogueWithCx;
|
pub use dialogue_with_cx::DialogueWithCx;
|
||||||
pub use get_chat_id::GetChatId;
|
pub use get_chat_id::GetChatId;
|
||||||
pub use transition::{
|
pub use transition::{
|
||||||
SubTransition, SubTransitionOutputType, Transition, TransitionIn,
|
SubTransition, SubTransitionOutputType, Transition, TransitionIn, TransitionOut,
|
||||||
TransitionOut,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "redis-storage")]
|
#[cfg(feature = "redis-storage")]
|
||||||
|
|
|
@ -43,8 +43,6 @@ impl<D> Storage<D> for InMemStorage<D> {
|
||||||
where
|
where
|
||||||
D: Send + 'static,
|
D: Send + 'static,
|
||||||
{
|
{
|
||||||
Box::pin(
|
Box::pin(async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) })
|
||||||
async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,7 @@ impl<S> RedisStorage<S> {
|
||||||
serializer: S,
|
serializer: S,
|
||||||
) -> Result<Arc<Self>, RedisStorageError<Infallible>> {
|
) -> Result<Arc<Self>, RedisStorageError<Infallible>> {
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
conn: Mutex::new(
|
conn: Mutex::new(redis::Client::open(url)?.get_async_connection().await?),
|
||||||
redis::Client::open(url)?.get_async_connection().await?,
|
|
||||||
),
|
|
||||||
serializer,
|
serializer,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -91,21 +89,15 @@ where
|
||||||
dialogue: D,
|
dialogue: D,
|
||||||
) -> BoxFuture<'static, Result<Option<D>, Self::Error>> {
|
) -> BoxFuture<'static, Result<Option<D>, Self::Error>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let dialogue = self
|
let dialogue =
|
||||||
.serializer
|
self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?;
|
||||||
.serialize(&dialogue)
|
|
||||||
.map_err(RedisStorageError::SerdeError)?;
|
|
||||||
Ok(self
|
Ok(self
|
||||||
.conn
|
.conn
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.getset::<_, Vec<u8>, Option<Vec<u8>>>(chat_id, dialogue)
|
.getset::<_, Vec<u8>, Option<Vec<u8>>>(chat_id, dialogue)
|
||||||
.await?
|
.await?
|
||||||
.map(|d| {
|
.map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError))
|
||||||
self.serializer
|
|
||||||
.deserialize(&d)
|
|
||||||
.map_err(RedisStorageError::SerdeError)
|
|
||||||
})
|
|
||||||
.transpose()?)
|
.transpose()?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,7 @@ pub trait Transition<T>: Sized {
|
||||||
/// Turns itself into another state, depending on the input message.
|
/// Turns itself into another state, depending on the input message.
|
||||||
///
|
///
|
||||||
/// `aux` will be passed to each subtransition function.
|
/// `aux` will be passed to each subtransition function.
|
||||||
fn react(
|
fn react(self, cx: TransitionIn, aux: T) -> BoxFuture<'static, TransitionOut<Self>>;
|
||||||
self,
|
|
||||||
cx: TransitionIn,
|
|
||||||
aux: T,
|
|
||||||
) -> BoxFuture<'static, TransitionOut<Self>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like [`Transition`], but from `StateN` -> `Dialogue`.
|
/// Like [`Transition`], but from `StateN` -> `Dialogue`.
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
dispatching::{
|
dispatching::{
|
||||||
update_listeners, update_listeners::UpdateListener, DispatcherHandler,
|
update_listeners, update_listeners::UpdateListener, DispatcherHandler, UpdateWithCx,
|
||||||
UpdateWithCx,
|
|
||||||
},
|
},
|
||||||
error_handlers::{ErrorHandler, LoggingErrorHandler},
|
error_handlers::{ErrorHandler, LoggingErrorHandler},
|
||||||
types::{
|
types::{
|
||||||
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
|
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, PollAnswer,
|
||||||
PollAnswer, PreCheckoutQuery, ShippingQuery, UpdateKind,
|
PreCheckoutQuery, ShippingQuery, UpdateKind,
|
||||||
},
|
},
|
||||||
Bot,
|
Bot,
|
||||||
};
|
};
|
||||||
|
@ -26,19 +25,14 @@ mod macros {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<'a, Upd>(
|
fn send<'a, Upd>(bot: &'a Bot, tx: &'a Tx<Upd>, update: Upd, variant: &'static str)
|
||||||
bot: &'a Bot,
|
where
|
||||||
tx: &'a Tx<Upd>,
|
|
||||||
update: Upd,
|
|
||||||
variant: &'static str,
|
|
||||||
) where
|
|
||||||
Upd: Debug,
|
Upd: Debug,
|
||||||
{
|
{
|
||||||
if let Some(tx) = tx {
|
if let Some(tx) = tx {
|
||||||
if let Err(error) = tx.send(UpdateWithCx { bot: bot.clone(), update }) {
|
if let Err(error) = tx.send(UpdateWithCx { bot: bot.clone(), update }) {
|
||||||
log::error!(
|
log::error!(
|
||||||
"The RX part of the {} channel is closed, but an update is \
|
"The RX part of the {} channel is closed, but an update is received.\nError:{}\n",
|
||||||
received.\nError:{}\n",
|
|
||||||
variant,
|
variant,
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
|
@ -206,9 +200,7 @@ impl Dispatcher {
|
||||||
pub async fn dispatch(&self) {
|
pub async fn dispatch(&self) {
|
||||||
self.dispatch_with_listener(
|
self.dispatch_with_listener(
|
||||||
update_listeners::polling_default(self.bot.clone()),
|
update_listeners::polling_default(self.bot.clone()),
|
||||||
LoggingErrorHandler::with_custom_text(
|
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
||||||
"An error from the update listener",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -228,8 +220,7 @@ impl Dispatcher {
|
||||||
|
|
||||||
update_listener
|
update_listener
|
||||||
.for_each(move |update| {
|
.for_each(move |update| {
|
||||||
let update_listener_error_handler =
|
let update_listener_error_handler = Arc::clone(&update_listener_error_handler);
|
||||||
Arc::clone(&update_listener_error_handler);
|
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
log::trace!("Dispatcher received an update: {:?}", update);
|
log::trace!("Dispatcher received an update: {:?}", update);
|
||||||
|
@ -237,21 +228,14 @@ impl Dispatcher {
|
||||||
let update = match update {
|
let update = match update {
|
||||||
Ok(update) => update,
|
Ok(update) => update,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
Arc::clone(&update_listener_error_handler)
|
Arc::clone(&update_listener_error_handler).handle_error(error).await;
|
||||||
.handle_error(error)
|
|
||||||
.await;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match update.kind {
|
match update.kind {
|
||||||
UpdateKind::Message(message) => {
|
UpdateKind::Message(message) => {
|
||||||
send!(
|
send!(&self.bot, &self.messages_queue, message, UpdateKind::Message);
|
||||||
&self.bot,
|
|
||||||
&self.messages_queue,
|
|
||||||
message,
|
|
||||||
UpdateKind::Message
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
UpdateKind::EditedMessage(message) => {
|
UpdateKind::EditedMessage(message) => {
|
||||||
send!(
|
send!(
|
||||||
|
@ -318,12 +302,7 @@ impl Dispatcher {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
UpdateKind::Poll(poll) => {
|
UpdateKind::Poll(poll) => {
|
||||||
send!(
|
send!(&self.bot, &self.polls_queue, poll, UpdateKind::Poll);
|
||||||
&self.bot,
|
|
||||||
&self.polls_queue,
|
|
||||||
poll,
|
|
||||||
UpdateKind::Poll
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
UpdateKind::PollAnswer(answer) => {
|
UpdateKind::PollAnswer(answer) => {
|
||||||
send!(
|
send!(
|
||||||
|
|
|
@ -11,10 +11,7 @@ use futures::future::BoxFuture;
|
||||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||||
pub trait DispatcherHandler<Upd> {
|
pub trait DispatcherHandler<Upd> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn handle(
|
fn handle(self, updates: DispatcherHandlerRx<Upd>) -> BoxFuture<'static, ()>
|
||||||
self,
|
|
||||||
updates: DispatcherHandlerRx<Upd>,
|
|
||||||
) -> BoxFuture<'static, ()>
|
|
||||||
where
|
where
|
||||||
UpdateWithCx<Upd>: Send + 'static;
|
UpdateWithCx<Upd>: Send + 'static;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::{
|
use crate::{prelude::UpdateWithCx, types::Message, utils::command::BotCommand};
|
||||||
prelude::UpdateWithCx, types::Message, utils::command::BotCommand,
|
|
||||||
};
|
|
||||||
use futures::{stream::BoxStream, Stream, StreamExt};
|
use futures::{stream::BoxStream, Stream, StreamExt};
|
||||||
|
|
||||||
/// An extension trait to be used with [`DispatcherHandlerRx`].
|
/// An extension trait to be used with [`DispatcherHandlerRx`].
|
||||||
|
@ -11,18 +9,13 @@ use futures::{stream::BoxStream, Stream, StreamExt};
|
||||||
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
|
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
|
||||||
pub trait DispatcherHandlerRxExt {
|
pub trait DispatcherHandlerRxExt {
|
||||||
/// Extracts only text messages from this stream of arbitrary messages.
|
/// Extracts only text messages from this stream of arbitrary messages.
|
||||||
fn text_messages(
|
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
||||||
self,
|
|
||||||
) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>;
|
Self: Stream<Item = UpdateWithCx<Message>>;
|
||||||
|
|
||||||
/// Extracts only commands with their arguments from this stream of
|
/// Extracts only commands with their arguments from this stream of
|
||||||
/// arbitrary messages.
|
/// arbitrary messages.
|
||||||
fn commands<C, N>(
|
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
||||||
self,
|
|
||||||
bot_name: N,
|
|
||||||
) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<Message>>,
|
||||||
C: BotCommand,
|
C: BotCommand,
|
||||||
|
@ -33,21 +26,14 @@ impl<T> DispatcherHandlerRxExt for T
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
{
|
{
|
||||||
fn text_messages(
|
fn text_messages(self) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
||||||
self,
|
|
||||||
) -> BoxStream<'static, (UpdateWithCx<Message>, String)>
|
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<Message>>,
|
||||||
{
|
{
|
||||||
Box::pin(self.filter_map(|cx| async move {
|
Box::pin(self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) }))
|
||||||
cx.update.text_owned().map(|text| (cx, text))
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commands<C, N>(
|
fn commands<C, N>(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
||||||
self,
|
|
||||||
bot_name: N,
|
|
||||||
) -> BoxStream<'static, (UpdateWithCx<Message>, C)>
|
|
||||||
where
|
where
|
||||||
Self: Stream<Item = UpdateWithCx<Message>>,
|
Self: Stream<Item = UpdateWithCx<Message>>,
|
||||||
C: BotCommand,
|
C: BotCommand,
|
||||||
|
@ -58,9 +44,7 @@ where
|
||||||
Box::pin(self.text_messages().filter_map(move |(cx, text)| {
|
Box::pin(self.text_messages().filter_map(move |(cx, text)| {
|
||||||
let bot_name = bot_name.clone();
|
let bot_name = bot_name.clone();
|
||||||
|
|
||||||
async move {
|
async move { C::parse(&text, &bot_name).map(|command| (cx, command)).ok() }
|
||||||
C::parse(&text, &bot_name).map(|command| (cx, command)).ok()
|
|
||||||
}
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,8 +145,7 @@ pub fn polling(
|
||||||
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"));
|
|
||||||
|
|
||||||
stream::unfold(
|
stream::unfold(
|
||||||
(allowed_updates, bot, 0),
|
(allowed_updates, bot, 0),
|
||||||
|
@ -165,10 +164,7 @@ pub fn polling(
|
||||||
Ok(ok) => ok.id,
|
Ok(ok) => ok.id,
|
||||||
Err((value, _)) => value["update_id"]
|
Err((value, _)) => value["update_id"]
|
||||||
.as_i64()
|
.as_i64()
|
||||||
.expect(
|
.expect("The 'update_id' field must always exist in Update")
|
||||||
"The 'update_id' field must always exist \
|
|
||||||
in Update",
|
|
||||||
)
|
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("update_id must be i32"),
|
.expect("update_id must be i32"),
|
||||||
};
|
};
|
||||||
|
@ -176,10 +172,8 @@ pub fn polling(
|
||||||
offset = id + 1;
|
offset = id + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let updates = updates
|
let updates =
|
||||||
.into_iter()
|
updates.into_iter().filter_map(Result::ok).collect::<Vec<Update>>();
|
||||||
.filter_map(Result::ok)
|
|
||||||
.collect::<Vec<Update>>();
|
|
||||||
|
|
||||||
updates.into_iter().map(Ok).collect::<Vec<_>>()
|
updates.into_iter().map(Ok).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
dispatching::dialogue::GetChatId,
|
dispatching::dialogue::GetChatId,
|
||||||
requests::{
|
requests::{
|
||||||
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage,
|
DeleteMessage, EditMessageCaption, EditMessageText, ForwardMessage, PinChatMessage,
|
||||||
PinChatMessage, Request, ResponseResult, SendAnimation, SendAudio,
|
Request, ResponseResult, SendAnimation, SendAudio, SendContact, SendDocument, SendLocation,
|
||||||
SendContact, SendDocument, SendLocation, SendMediaGroup, SendMessage,
|
SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo, SendVideoNote,
|
||||||
SendPhoto, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice,
|
SendVoice,
|
||||||
},
|
},
|
||||||
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
|
types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message},
|
||||||
Bot,
|
Bot,
|
||||||
|
@ -51,9 +51,7 @@ impl UpdateWithCx<Message> {
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot
|
self.bot.send_message(self.chat_id(), text).reply_to_message_id(self.update.id)
|
||||||
.send_message(self.chat_id(), text)
|
|
||||||
.reply_to_message_id(self.update.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
|
pub fn answer_photo(&self, photo: InputFile) -> SendPhoto {
|
||||||
|
@ -87,11 +85,7 @@ impl UpdateWithCx<Message> {
|
||||||
self.bot.send_media_group(self.update.chat.id, media_group)
|
self.bot.send_media_group(self.update.chat.id, media_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_location(
|
pub fn answer_location(&self, latitude: f32, longitude: f32) -> SendLocation {
|
||||||
&self,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
) -> SendLocation {
|
|
||||||
self.bot.send_location(self.update.chat.id, latitude, longitude)
|
self.bot.send_location(self.update.chat.id, latitude, longitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,24 +100,14 @@ impl UpdateWithCx<Message> {
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
self.bot.send_venue(
|
self.bot.send_venue(self.update.chat.id, latitude, longitude, title, address)
|
||||||
self.update.chat.id,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
title,
|
|
||||||
address,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
|
pub fn answer_video_note(&self, video_note: InputFile) -> SendVideoNote {
|
||||||
self.bot.send_video_note(self.update.chat.id, video_note)
|
self.bot.send_video_note(self.update.chat.id, video_note)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn answer_contact<T, U>(
|
pub fn answer_contact<T, U>(&self, phone_number: T, first_name: U) -> SendContact
|
||||||
&self,
|
|
||||||
phone_number: T,
|
|
||||||
first_name: U,
|
|
||||||
) -> SendContact
|
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
|
|
|
@ -174,9 +174,7 @@ impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
|
||||||
///
|
///
|
||||||
/// LoggingErrorHandler::new().handle_error(()).await;
|
/// LoggingErrorHandler::new().handle_error(()).await;
|
||||||
/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404).await;
|
/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404).await;
|
||||||
/// LoggingErrorHandler::with_custom_text("Omg2")
|
/// LoggingErrorHandler::with_custom_text("Omg2").handle_error("Invalid data type!").await;
|
||||||
/// .handle_error("Invalid data type!")
|
|
||||||
/// .await;
|
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct LoggingErrorHandler {
|
pub struct LoggingErrorHandler {
|
||||||
|
|
|
@ -63,9 +63,9 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`EditMessageText`]
|
/// 1. [`EditMessageText`]
|
||||||
///
|
///
|
||||||
/// [`EditMessageText`]: crate::requests::EditMessageText
|
/// [`EditMessageText`]: crate::requests::EditMessageText
|
||||||
#[serde(rename = "Bad Request: message is not modified: specified new \
|
#[serde(rename = "Bad Request: message is not modified: specified new message content and \
|
||||||
message content and reply markup are exactly the same \
|
reply markup are exactly the same as a current content and reply markup \
|
||||||
as a current content and reply markup of the message")]
|
of the message")]
|
||||||
MessageNotModified,
|
MessageNotModified,
|
||||||
|
|
||||||
/// Occurs when bot tries to forward or delete a message which was deleted.
|
/// Occurs when bot tries to forward or delete a message which was deleted.
|
||||||
|
@ -285,8 +285,8 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`AnswerCallbackQuery`]
|
/// 1. [`AnswerCallbackQuery`]
|
||||||
///
|
///
|
||||||
/// [`AnswerCallbackQuery`]: crate::requests::AnswerCallbackQuery
|
/// [`AnswerCallbackQuery`]: crate::requests::AnswerCallbackQuery
|
||||||
#[serde(rename = "Bad Request: query is too old and response timeout \
|
#[serde(rename = "Bad Request: query is too old and response timeout expired or query id is \
|
||||||
expired or query id is invalid")]
|
invalid")]
|
||||||
InvalidQueryID,
|
InvalidQueryID,
|
||||||
|
|
||||||
/// Occurs when bot tries to send InlineKeyboardMarkup with invalid button
|
/// Occurs when bot tries to send InlineKeyboardMarkup with invalid button
|
||||||
|
@ -314,8 +314,8 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`SendMessage`]
|
/// 1. [`SendMessage`]
|
||||||
///
|
///
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
/// [`SendMessage`]: crate::requests::SendMessage
|
||||||
#[serde(rename = "Bad Request: can't parse inline keyboard button: Text \
|
#[serde(rename = "Bad Request: can't parse inline keyboard button: Text buttons are \
|
||||||
buttons are unallowed in the inline keyboard")]
|
unallowed in the inline keyboard")]
|
||||||
TextButtonsAreUnallowed,
|
TextButtonsAreUnallowed,
|
||||||
|
|
||||||
/// Occurs when bot tries to get file by wrong file id.
|
/// Occurs when bot tries to get file by wrong file id.
|
||||||
|
@ -361,8 +361,7 @@ pub enum KnownApiErrorKind {
|
||||||
|
|
||||||
/// Occurs when bot tries to use method in group which is allowed only in a
|
/// Occurs when bot tries to use method in group which is allowed only in a
|
||||||
/// supergroup or channel.
|
/// supergroup or channel.
|
||||||
#[serde(rename = "Bad Request: method is available only for supergroups \
|
#[serde(rename = "Bad Request: method is available only for supergroups and channel")]
|
||||||
and channel")]
|
|
||||||
MethodNotAvailableInPrivateChats,
|
MethodNotAvailableInPrivateChats,
|
||||||
|
|
||||||
/// Occurs when bot tries to demote chat creator.
|
/// Occurs when bot tries to demote chat creator.
|
||||||
|
@ -390,8 +389,7 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`RestrictChatMember`]
|
/// 1. [`RestrictChatMember`]
|
||||||
///
|
///
|
||||||
/// [`RestrictChatMember`]: crate::requests::RestrictChatMember
|
/// [`RestrictChatMember`]: crate::requests::RestrictChatMember
|
||||||
#[serde(rename = "Bad Request: not enough rights to restrict/unrestrict \
|
#[serde(rename = "Bad Request: not enough rights to restrict/unrestrict chat member")]
|
||||||
chat member")]
|
|
||||||
NotEnoughRightsToRestrict,
|
NotEnoughRightsToRestrict,
|
||||||
|
|
||||||
/// Occurs when bot tries set webhook to protocol other than HTTPS.
|
/// Occurs when bot tries set webhook to protocol other than HTTPS.
|
||||||
|
@ -400,8 +398,7 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`SetWebhook`]
|
/// 1. [`SetWebhook`]
|
||||||
///
|
///
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
/// [`SetWebhook`]: crate::requests::SetWebhook
|
||||||
#[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided \
|
#[serde(rename = "Bad Request: bad webhook: HTTPS url must be provided for webhook")]
|
||||||
for webhook")]
|
|
||||||
WebhookRequireHTTPS,
|
WebhookRequireHTTPS,
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to port other than 80, 88, 443 or
|
/// Occurs when bot tries to set webhook to port other than 80, 88, 443 or
|
||||||
|
@ -411,8 +408,8 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`SetWebhook`]
|
/// 1. [`SetWebhook`]
|
||||||
///
|
///
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
/// [`SetWebhook`]: crate::requests::SetWebhook
|
||||||
#[serde(rename = "Bad Request: bad webhook: Webhook can be set up only \
|
#[serde(rename = "Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 \
|
||||||
on ports 80, 88, 443 or 8443")]
|
or 8443")]
|
||||||
BadWebhookPort,
|
BadWebhookPort,
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to unknown host.
|
/// Occurs when bot tries to set webhook to unknown host.
|
||||||
|
@ -421,8 +418,7 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`SetWebhook`]
|
/// 1. [`SetWebhook`]
|
||||||
///
|
///
|
||||||
/// [`SetWebhook`]: crate::requests::SetWebhook
|
/// [`SetWebhook`]: crate::requests::SetWebhook
|
||||||
#[serde(rename = "Bad Request: bad webhook: Failed to resolve host: \
|
#[serde(rename = "Bad Request: bad webhook: Failed to resolve host: Name or service not known")]
|
||||||
Name or service not known")]
|
|
||||||
UnknownHost,
|
UnknownHost,
|
||||||
|
|
||||||
/// Occurs when bot tries to set webhook to invalid URL.
|
/// Occurs when bot tries to set webhook to invalid URL.
|
||||||
|
@ -476,9 +472,7 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`SendMessage`]
|
/// 1. [`SendMessage`]
|
||||||
///
|
///
|
||||||
/// [`SendMessage`]: crate::requests::SendMessage
|
/// [`SendMessage`]: crate::requests::SendMessage
|
||||||
#[serde(
|
#[serde(rename = "Unauthorized: bot can't initiate conversation with a user")]
|
||||||
rename = "Unauthorized: bot can't initiate conversation with a user"
|
|
||||||
)]
|
|
||||||
CantInitiateConversation,
|
CantInitiateConversation,
|
||||||
|
|
||||||
/// Occurs when you tries to send message to bot.
|
/// Occurs when you tries to send message to bot.
|
||||||
|
@ -506,8 +500,8 @@ pub enum KnownApiErrorKind {
|
||||||
/// 1. [`GetUpdates`]
|
/// 1. [`GetUpdates`]
|
||||||
///
|
///
|
||||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
/// [`GetUpdates`]: crate::requests::GetUpdates
|
||||||
#[serde(rename = "Conflict: terminated by other getUpdates request; \
|
#[serde(rename = "Conflict: terminated by other getUpdates request; make sure that only one \
|
||||||
make sure that only one bot instance is running")]
|
bot instance is running")]
|
||||||
TerminatedByOtherGetUpdates,
|
TerminatedByOtherGetUpdates,
|
||||||
|
|
||||||
/// Occurs when bot tries to get file by invalid file id.
|
/// Occurs when bot tries to get file by invalid file id.
|
||||||
|
|
|
@ -17,9 +17,7 @@
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
pub use bot::{Bot, BotBuilder};
|
pub use bot::{Bot, BotBuilder};
|
||||||
pub use errors::{
|
pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError};
|
||||||
ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
mod net;
|
mod net;
|
||||||
|
|
|
@ -17,24 +17,14 @@ const TELEGRAM_API_URL: &str = "https://api.telegram.org";
|
||||||
///
|
///
|
||||||
/// [Telegram documentation]: https://core.telegram.org/bots/api#making-requests
|
/// [Telegram documentation]: https://core.telegram.org/bots/api#making-requests
|
||||||
fn method_url(base: &str, token: &str, method_name: &str) -> String {
|
fn method_url(base: &str, token: &str, method_name: &str) -> String {
|
||||||
format!(
|
format!("{url}/bot{token}/{method}", url = base, token = token, method = method_name,)
|
||||||
"{url}/bot{token}/{method}",
|
|
||||||
url = base,
|
|
||||||
token = token,
|
|
||||||
method = method_name,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates URL for downloading a file. See the [Telegram documentation].
|
/// Creates URL for downloading a file. See the [Telegram documentation].
|
||||||
///
|
///
|
||||||
/// [Telegram documentation]: https://core.telegram.org/bots/api#file
|
/// [Telegram documentation]: https://core.telegram.org/bots/api#file
|
||||||
fn file_url(base: &str, token: &str, file_path: &str) -> String {
|
fn file_url(base: &str, token: &str, file_path: &str) -> String {
|
||||||
format!(
|
format!("{url}/file/bot{token}/{file}", url = base, token = token, file = file_path,)
|
||||||
"{url}/file/bot{token}/{file}",
|
|
||||||
url = base,
|
|
||||||
token = token,
|
|
||||||
file = file_path,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -33,17 +33,10 @@ impl<R> Into<ResponseResult<R>> for TelegramResponse<R> {
|
||||||
fn into(self) -> Result<R, RequestError> {
|
fn into(self) -> Result<R, RequestError> {
|
||||||
match self {
|
match self {
|
||||||
TelegramResponse::Ok { result, .. } => Ok(result),
|
TelegramResponse::Ok { result, .. } => Ok(result),
|
||||||
TelegramResponse::Err {
|
TelegramResponse::Err { kind, error_code, response_parameters, .. } => {
|
||||||
kind,
|
|
||||||
error_code,
|
|
||||||
response_parameters,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if let Some(params) = response_parameters {
|
if let Some(params) = response_parameters {
|
||||||
match params {
|
match params {
|
||||||
ResponseParameters::RetryAfter(i) => {
|
ResponseParameters::RetryAfter(i) => Err(RequestError::RetryAfter(i)),
|
||||||
Err(RequestError::RetryAfter(i))
|
|
||||||
}
|
|
||||||
ResponseParameters::MigrateToChatId(to) => {
|
ResponseParameters::MigrateToChatId(to) => {
|
||||||
Err(RequestError::MigrateToChatId(to))
|
Err(RequestError::MigrateToChatId(to))
|
||||||
}
|
}
|
||||||
|
@ -66,8 +59,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn terminated_by_other_get_updates() {
|
fn terminated_by_other_get_updates() {
|
||||||
let expected =
|
let expected = ApiErrorKind::Known(KnownApiErrorKind::TerminatedByOtherGetUpdates);
|
||||||
ApiErrorKind::Known(KnownApiErrorKind::TerminatedByOtherGetUpdates);
|
|
||||||
if let TelegramResponse::Err{ kind, .. } = serde_json::from_str::<TelegramResponse<Update>>(r#"{"ok":false,"error_code":409,"description":"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"}"#).unwrap() {
|
if let TelegramResponse::Err{ kind, .. } = serde_json::from_str::<TelegramResponse<Update>>(r#"{"ok":false,"error_code":409,"description":"Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"}"#).unwrap() {
|
||||||
assert_eq!(expected, kind);
|
assert_eq!(expected, kind);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
dispatching::{
|
dispatching::{
|
||||||
dialogue::{
|
dialogue::{
|
||||||
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx,
|
exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId, Transition,
|
||||||
GetChatId, Transition, TransitionIn, TransitionOut,
|
TransitionIn, TransitionOut,
|
||||||
},
|
},
|
||||||
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx,
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,13 +33,7 @@ impl Request for AnswerCallbackQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "answerCallbackQuery", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"answerCallbackQuery",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,14 +43,7 @@ impl AnswerCallbackQuery {
|
||||||
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, callback_query_id, text: None, show_alert: None, url: None, cache_time: None }
|
||||||
bot,
|
|
||||||
callback_query_id,
|
|
||||||
text: None,
|
|
||||||
show_alert: None,
|
|
||||||
url: None,
|
|
||||||
cache_time: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the query to be answered.
|
/// Unique identifier for the query to be answered.
|
||||||
|
|
|
@ -31,13 +31,7 @@ impl Request for AnswerInlineQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "answerInlineQuery", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"answerInlineQuery",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,8 @@ impl Request for AnswerPreCheckoutQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "answerPreCheckoutQuery", &self)
|
||||||
self.bot.client(),
|
.await
|
||||||
self.bot.token(),
|
|
||||||
"answerPreCheckoutQuery",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,7 @@ impl Request for AnswerShippingQuery {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "answerShippingQuery", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"answerShippingQuery",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,13 +41,7 @@ impl AnswerShippingQuery {
|
||||||
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, shipping_query_id, ok, shipping_options: None, error_message: None }
|
||||||
bot,
|
|
||||||
shipping_query_id,
|
|
||||||
ok,
|
|
||||||
shipping_options: None,
|
|
||||||
error_message: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the query to be answered.
|
/// Unique identifier for the query to be answered.
|
||||||
|
|
|
@ -25,13 +25,7 @@ impl Request for DeleteChatPhoto {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "deleteChatPhoto", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"deleteChatPhoto",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,13 +30,7 @@ impl Request for DeleteChatStickerSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "deleteChatStickerSet", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"deleteChatStickerSet",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,7 @@ impl Request for DeleteMessage {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "deleteMessage", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"deleteMessage",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,7 @@ impl Request for DeleteStickerFromSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "deleteStickerFromSet", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"deleteStickerFromSet",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,7 @@ impl Request for DeleteWebhook {
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "deleteWebhook", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"deleteWebhook",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,28 +33,13 @@ impl Request for EditMessageCaption {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "editMessageCaption", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"editMessageCaption",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditMessageCaption {
|
impl EditMessageCaption {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||||
bot: Bot,
|
Self { bot, chat_or_inline_message, caption: None, parse_mode: None, reply_markup: None }
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
bot,
|
|
||||||
chat_or_inline_message,
|
|
||||||
caption: None,
|
|
||||||
parse_mode: None,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||||
|
|
|
@ -35,13 +35,8 @@ impl Request for EditMessageLiveLocation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "editMessageLiveLocation", &self)
|
||||||
self.bot.client(),
|
.await
|
||||||
self.bot.token(),
|
|
||||||
"editMessageLiveLocation",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +47,7 @@ impl EditMessageLiveLocation {
|
||||||
latitude: f32,
|
latitude: f32,
|
||||||
longitude: f32,
|
longitude: f32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { bot, chat_or_inline_message, latitude, longitude, reply_markup: None }
|
||||||
bot,
|
|
||||||
chat_or_inline_message,
|
|
||||||
latitude,
|
|
||||||
longitude,
|
|
||||||
reply_markup: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self {
|
||||||
|
|
|
@ -36,13 +36,10 @@ impl Request for EditMessageMedia {
|
||||||
|
|
||||||
match &self.chat_or_inline_message {
|
match &self.chat_or_inline_message {
|
||||||
ChatOrInlineMessage::Chat { chat_id, message_id } => {
|
ChatOrInlineMessage::Chat { chat_id, message_id } => {
|
||||||
params = params
|
params = params.add_text("chat_id", chat_id).add_text("message_id", message_id);
|
||||||
.add_text("chat_id", chat_id)
|
|
||||||
.add_text("message_id", message_id);
|
|
||||||
}
|
}
|
||||||
ChatOrInlineMessage::Inline { inline_message_id } => {
|
ChatOrInlineMessage::Inline { inline_message_id } => {
|
||||||
params =
|
params = params.add_text("inline_message_id", inline_message_id);
|
||||||
params.add_text("inline_message_id", inline_message_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,21 +31,13 @@ impl Request for EditMessageReplyMarkup {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "editMessageReplyMarkup", &self)
|
||||||
self.bot.client(),
|
.await
|
||||||
self.bot.token(),
|
|
||||||
"editMessageReplyMarkup",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditMessageReplyMarkup {
|
impl EditMessageReplyMarkup {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||||
bot: Bot,
|
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
|
||||||
) -> Self {
|
|
||||||
Self { bot, chat_or_inline_message, reply_markup: None }
|
Self { bot, chat_or_inline_message, reply_markup: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,22 +34,12 @@ impl Request for EditMessageText {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "editMessageText", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"editMessageText",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditMessageText {
|
impl EditMessageText {
|
||||||
pub(crate) fn new<T>(
|
pub(crate) fn new<T>(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, text: T) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
|
||||||
text: T,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,13 +40,7 @@ impl Request for ExportChatInviteLink {
|
||||||
|
|
||||||
/// Returns the new invite link as `String` on success.
|
/// Returns the new invite link as `String` on success.
|
||||||
async fn send(&self) -> ResponseResult<String> {
|
async fn send(&self) -> ResponseResult<String> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "exportChatInviteLink", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"exportChatInviteLink",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,36 +26,19 @@ impl Request for ForwardMessage {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "forwardMessage", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"forwardMessage",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ForwardMessage {
|
impl ForwardMessage {
|
||||||
pub(crate) fn new<C, F>(
|
pub(crate) fn new<C, F>(bot: Bot, chat_id: C, from_chat_id: F, message_id: i32) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
from_chat_id: F,
|
|
||||||
message_id: i32,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
F: Into<ChatId>,
|
F: Into<ChatId>,
|
||||||
{
|
{
|
||||||
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, chat_id, from_chat_id, message_id, disable_notification: None }
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
from_chat_id,
|
|
||||||
message_id,
|
|
||||||
disable_notification: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
/// Unique identifier for the target chat or username of the target channel
|
||||||
|
|
|
@ -25,8 +25,7 @@ impl Request for GetChat {
|
||||||
type Output = Chat;
|
type Output = Chat;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Chat> {
|
async fn send(&self) -> ResponseResult<Chat> {
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getChat", &self)
|
net::request_json(self.bot.client(), self.bot.token(), "getChat", &self).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,7 @@ impl Request for GetChatAdministrators {
|
||||||
/// On success, returns an array that contains information about all chat
|
/// On success, returns an array that contains information about all chat
|
||||||
/// administrators except other bots.
|
/// administrators except other bots.
|
||||||
async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
|
async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getChatAdministrators", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getChatAdministrators",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,7 @@ impl Request for GetChatMember {
|
||||||
type Output = ChatMember;
|
type Output = ChatMember;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<ChatMember> {
|
async fn send(&self) -> ResponseResult<ChatMember> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getChatMember", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getChatMember",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,7 @@ impl Request for GetChatMembersCount {
|
||||||
type Output = i32;
|
type Output = i32;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<i32> {
|
async fn send(&self) -> ResponseResult<i32> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getChatMembersCount", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getChatMembersCount",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,7 @@ impl Request for GetFile {
|
||||||
type Output = File;
|
type Output = File;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<File> {
|
async fn send(&self) -> ResponseResult<File> {
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getFile", &self)
|
net::request_json(self.bot.client(), self.bot.token(), "getFile", &self).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,22 +34,12 @@ 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>> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getGameHighScores", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getGameHighScores",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetGameHighScores {
|
impl GetGameHighScores {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, user_id: i32) -> Self {
|
||||||
bot: Bot,
|
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
|
||||||
user_id: i32,
|
|
||||||
) -> Self {
|
|
||||||
Self { bot, chat_or_inline_message, user_id }
|
Self { bot, chat_or_inline_message, user_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ impl Request for GetMe {
|
||||||
/// Returns basic information about the bot.
|
/// Returns basic information about the bot.
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
async fn send(&self) -> ResponseResult<Me> {
|
async fn send(&self) -> ResponseResult<Me> {
|
||||||
net::request_json(self.bot.client(), self.bot.token(), "getMe", &self)
|
net::request_json(self.bot.client(), self.bot.token(), "getMe", &self).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,7 @@ impl Request for GetStickerSet {
|
||||||
type Output = StickerSet;
|
type Output = StickerSet;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<StickerSet> {
|
async fn send(&self) -> ResponseResult<StickerSet> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getStickerSet", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getStickerSet",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,23 +36,14 @@ impl Request for GetUpdates {
|
||||||
/// Deserialize to `Vec<serde_json::Result<Update>>` instead of
|
/// Deserialize to `Vec<serde_json::Result<Update>>` instead of
|
||||||
/// `Vec<Update>`, because we want to parse the rest of updates even if our
|
/// `Vec<Update>`, because we want to parse the rest of updates even if our
|
||||||
/// library hasn't parsed one.
|
/// library hasn't parsed one.
|
||||||
async fn send(
|
async fn send(&self) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
|
||||||
&self,
|
let value: Value =
|
||||||
) -> ResponseResult<Vec<Result<Update, (Value, serde_json::Error)>>> {
|
net::request_json(self.bot.client(), self.bot.token(), "getUpdates", &self).await?;
|
||||||
let value: Value = net::request_json(
|
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getUpdates",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Value::Array(array) => Ok(array
|
Value::Array(array) => Ok(array
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|value| {
|
.map(|value| Update::try_parse(&value).map_err(|error| (value, error)))
|
||||||
Update::try_parse(&value).map_err(|error| (value, error))
|
|
||||||
})
|
|
||||||
.collect()),
|
.collect()),
|
||||||
_ => Err(RequestError::InvalidJson(
|
_ => Err(RequestError::InvalidJson(
|
||||||
serde_json::from_value::<Vec<Update>>(value)
|
serde_json::from_value::<Vec<Update>>(value)
|
||||||
|
@ -64,13 +55,7 @@ impl Request for GetUpdates {
|
||||||
|
|
||||||
impl GetUpdates {
|
impl GetUpdates {
|
||||||
pub(crate) fn new(bot: Bot) -> Self {
|
pub(crate) fn new(bot: Bot) -> Self {
|
||||||
Self {
|
Self { bot, offset: None, limit: None, timeout: None, allowed_updates: None }
|
||||||
bot,
|
|
||||||
offset: None,
|
|
||||||
limit: None,
|
|
||||||
timeout: None,
|
|
||||||
allowed_updates: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifier of the first update to be returned.
|
/// Identifier of the first update to be returned.
|
||||||
|
|
|
@ -25,13 +25,7 @@ impl Request for GetUserProfilePhotos {
|
||||||
type Output = UserProfilePhotos;
|
type Output = UserProfilePhotos;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
|
async fn send(&self) -> ResponseResult<UserProfilePhotos> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getUserProfilePhotos", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getUserProfilePhotos",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for GetWebhookInfo {
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
async fn send(&self) -> ResponseResult<WebhookInfo> {
|
async fn send(&self) -> ResponseResult<WebhookInfo> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "getWebhookInfo", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"getWebhookInfo",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,7 @@ impl Request for KickChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "kickChatMember", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"kickChatMember",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,7 @@ impl Request for LeaveChat {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "leaveChat", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"leaveChat",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,7 @@ impl Request for PinChatMessage {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "pinChatMessage", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"pinChatMessage",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,7 @@ impl Request for PromoteChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "promoteChatMember", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"promoteChatMember",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,23 +30,12 @@ impl Request for RestrictChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "restrictChatMember", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"restrictChatMember",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestrictChatMember {
|
impl RestrictChatMember {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(bot: Bot, chat_id: C, user_id: i32, permissions: ChatPermissions) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
user_id: i32,
|
|
||||||
permissions: ChatPermissions,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,22 +75,12 @@ impl Request for SendChatAction {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendChatAction", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendChatAction",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendChatAction {
|
impl SendChatAction {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(bot: Bot, chat_id: C, action: SendChatActionKind) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
action: SendChatActionKind,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,23 +30,12 @@ impl Request for SendContact {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendContact", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendContact",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendContact {
|
impl SendContact {
|
||||||
pub(crate) fn new<C, P, F>(
|
pub(crate) fn new<C, P, F>(bot: Bot, chat_id: C, phone_number: P, first_name: F) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
phone_number: P,
|
|
||||||
first_name: F,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
P: Into<String>,
|
P: Into<String>,
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for SendGame {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendGame", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendGame",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,7 @@ impl Request for SendInvoice {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendInvoice", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendInvoice",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,23 +29,12 @@ impl Request for SendLocation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendLocation", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendLocation",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendLocation {
|
impl SendLocation {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(bot: Bot, chat_id: C, latitude: f32, longitude: f32) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
latitude: f32,
|
|
||||||
longitude: f32,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,13 +45,7 @@ impl SendMediaGroup {
|
||||||
{
|
{
|
||||||
let chat_id = chat_id.into();
|
let chat_id = chat_id.into();
|
||||||
let media = media.into();
|
let media = media.into();
|
||||||
Self {
|
Self { bot, chat_id, media, disable_notification: None, reply_to_message_id: None }
|
||||||
bot,
|
|
||||||
chat_id,
|
|
||||||
media,
|
|
||||||
disable_notification: None,
|
|
||||||
reply_to_message_id: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier for the target chat or username of the target channel
|
/// Unique identifier for the target chat or username of the target channel
|
||||||
|
|
|
@ -29,13 +29,7 @@ impl Request for SendMessage {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendMessage", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendMessage",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,23 +33,12 @@ impl Request for SendPoll {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendPoll", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendPoll",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendPoll {
|
impl SendPoll {
|
||||||
pub(crate) fn new<C, Q, O>(
|
pub(crate) fn new<C, Q, O>(bot: Bot, chat_id: C, question: Q, options: O) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
question: Q,
|
|
||||||
options: O,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
Q: Into<String>,
|
Q: Into<String>,
|
||||||
|
|
|
@ -32,13 +32,7 @@ impl Request for SendVenue {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendVenue", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendVenue",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,7 @@ impl Request for SetChatAdministratorCustomTitle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SetChatAdministratorCustomTitle {
|
impl SetChatAdministratorCustomTitle {
|
||||||
pub(crate) fn new<C, CT>(
|
pub(crate) fn new<C, CT>(bot: Bot, chat_id: C, user_id: i32, custom_title: CT) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
user_id: i32,
|
|
||||||
custom_title: CT,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
CT: Into<String>,
|
CT: Into<String>,
|
||||||
|
|
|
@ -28,13 +28,7 @@ impl Request for SetChatDescription {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setChatDescription", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setChatDescription",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,22 +27,12 @@ impl Request for SetChatPermissions {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "sendChatPermissions", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"sendChatPermissions",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SetChatPermissions {
|
impl SetChatPermissions {
|
||||||
pub(crate) fn new<C>(
|
pub(crate) fn new<C>(bot: Bot, chat_id: C, permissions: ChatPermissions) -> Self
|
||||||
bot: Bot,
|
|
||||||
chat_id: C,
|
|
||||||
permissions: ChatPermissions,
|
|
||||||
) -> Self
|
|
||||||
where
|
where
|
||||||
C: Into<ChatId>,
|
C: Into<ChatId>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for SetChatPhoto {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setChatPhoto", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setChatPhoto",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,7 @@ impl Request for SetChatStickerSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setChatStickerSet", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setChatStickerSet",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for SetChatTitle {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setChatTitle", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setChatTitle",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,7 @@ impl Request for SetGameScore {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setGameScore", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setGameScore",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,8 @@ impl Request for SetStickerPositionInSet {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setStickerPositionInSet", &self)
|
||||||
self.bot.client(),
|
.await
|
||||||
self.bot.token(),
|
|
||||||
"setStickerPositionInSet",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,7 @@ impl Request for SetWebhook {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "setWebhook", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"setWebhook",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,13 +49,7 @@ impl SetWebhook {
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
let url = url.into();
|
let url = url.into();
|
||||||
Self {
|
Self { bot, url, certificate: None, max_connections: None, allowed_updates: None }
|
||||||
bot,
|
|
||||||
url,
|
|
||||||
certificate: None,
|
|
||||||
max_connections: None,
|
|
||||||
allowed_updates: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HTTPS url to send updates to.
|
/// HTTPS url to send updates to.
|
||||||
|
|
|
@ -32,21 +32,13 @@ impl Request for StopMessageLiveLocation {
|
||||||
type Output = Message;
|
type Output = Message;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<Message> {
|
async fn send(&self) -> ResponseResult<Message> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "stopMessageLiveLocation", &self)
|
||||||
self.bot.client(),
|
.await
|
||||||
self.bot.token(),
|
|
||||||
"stopMessageLiveLocation",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StopMessageLiveLocation {
|
impl StopMessageLiveLocation {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self {
|
||||||
bot: Bot,
|
|
||||||
chat_or_inline_message: ChatOrInlineMessage,
|
|
||||||
) -> Self {
|
|
||||||
Self { bot, chat_or_inline_message, reply_markup: None }
|
Self { bot, chat_or_inline_message, reply_markup: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,7 @@ impl Request for StopPoll {
|
||||||
///
|
///
|
||||||
/// [`Poll`]: crate::types::Poll
|
/// [`Poll`]: crate::types::Poll
|
||||||
async fn send(&self) -> ResponseResult<Poll> {
|
async fn send(&self) -> ResponseResult<Poll> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "stopPoll", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"stopPoll",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StopPoll {
|
impl StopPoll {
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for UnbanChatMember {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "unbanChatMember", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"unbanChatMember",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,7 @@ impl Request for UnpinChatMessage {
|
||||||
type Output = True;
|
type Output = True;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<True> {
|
async fn send(&self) -> ResponseResult<True> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "unpinChatMessage", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"unpinChatMessage",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,7 @@ impl Request for UploadStickerFile {
|
||||||
type Output = File;
|
type Output = File;
|
||||||
|
|
||||||
async fn send(&self) -> ResponseResult<File> {
|
async fn send(&self) -> ResponseResult<File> {
|
||||||
net::request_json(
|
net::request_json(self.bot.client(), self.bot.token(), "uploadStickerFile", &self).await
|
||||||
self.bot.client(),
|
|
||||||
self.bot.token(),
|
|
||||||
"uploadStickerFile",
|
|
||||||
&self,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ use reqwest::multipart::Form;
|
||||||
use crate::{
|
use crate::{
|
||||||
requests::utils::{file_from_memory_to_part, file_to_part},
|
requests::utils::{file_from_memory_to_part, file_to_part},
|
||||||
types::{
|
types::{
|
||||||
ChatId, InlineKeyboardMarkup, InputFile, InputMedia, MaskPosition,
|
ChatId, InlineKeyboardMarkup, InputFile, InputMedia, MaskPosition, ParseMode, ReplyMarkup,
|
||||||
ParseMode, ReplyMarkup,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,18 +26,12 @@ impl FormBuilder {
|
||||||
T: IntoFormText,
|
T: IntoFormText,
|
||||||
{
|
{
|
||||||
match value.into_form_text() {
|
match value.into_form_text() {
|
||||||
Some(val) => {
|
Some(val) => Self { form: self.form.text(name.into().into_owned(), val) },
|
||||||
Self { form: self.form.text(name.into().into_owned(), val) }
|
|
||||||
}
|
|
||||||
None => self,
|
None => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_input_file<'a, N>(
|
pub async fn add_input_file<'a, N>(self, name: N, value: &InputFile) -> tokio::io::Result<Self>
|
||||||
self,
|
|
||||||
name: N,
|
|
||||||
value: &InputFile,
|
|
||||||
) -> tokio::io::Result<Self>
|
|
||||||
where
|
where
|
||||||
N: Into<Cow<'a, str>>,
|
N: Into<Cow<'a, str>>,
|
||||||
{
|
{
|
||||||
|
@ -53,19 +46,12 @@ impl FormBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// used in SendMediaGroup
|
// used in SendMediaGroup
|
||||||
pub async fn add_file<'a, N>(
|
pub async fn add_file<'a, N>(self, name: N, path_to_file: PathBuf) -> tokio::io::Result<Self>
|
||||||
self,
|
|
||||||
name: N,
|
|
||||||
path_to_file: PathBuf,
|
|
||||||
) -> tokio::io::Result<Self>
|
|
||||||
where
|
where
|
||||||
N: Into<Cow<'a, str>>,
|
N: Into<Cow<'a, str>>,
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
form: self.form.part(
|
form: self.form.part(name.into().into_owned(), file_to_part(path_to_file).await?),
|
||||||
name.into().into_owned(),
|
|
||||||
file_to_part(path_to_file).await?,
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +65,9 @@ impl FormBuilder {
|
||||||
N: Into<Cow<'a, str>>,
|
N: Into<Cow<'a, str>>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
form: self.form.part(
|
form: self
|
||||||
name.into().into_owned(),
|
.form
|
||||||
file_from_memory_to_part(data, file_name),
|
.part(name.into().into_owned(), file_from_memory_to_part(data, file_name)),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,15 +94,7 @@ macro_rules! impl_for_struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_for_struct!(
|
impl_for_struct!(bool, i32, i64, u32, ReplyMarkup, InlineKeyboardMarkup, MaskPosition);
|
||||||
bool,
|
|
||||||
i32,
|
|
||||||
i64,
|
|
||||||
u32,
|
|
||||||
ReplyMarkup,
|
|
||||||
InlineKeyboardMarkup,
|
|
||||||
MaskPosition
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T> IntoFormText for Option<T>
|
impl<T> IntoFormText for Option<T>
|
||||||
where
|
where
|
||||||
|
@ -132,16 +109,14 @@ where
|
||||||
// encode files :|)
|
// encode files :|)
|
||||||
impl IntoFormText for Vec<InputMedia> {
|
impl IntoFormText for Vec<InputMedia> {
|
||||||
fn into_form_text(&self) -> Option<String> {
|
fn into_form_text(&self) -> Option<String> {
|
||||||
let json =
|
let json = serde_json::to_string(self).expect("serde_json::to_string failed");
|
||||||
serde_json::to_string(self).expect("serde_json::to_string failed");
|
|
||||||
Some(json)
|
Some(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoFormText for InputMedia {
|
impl IntoFormText for InputMedia {
|
||||||
fn into_form_text(&self) -> Option<String> {
|
fn into_form_text(&self) -> Option<String> {
|
||||||
let json =
|
let json = serde_json::to_string(self).expect("serde_json::to_string failed");
|
||||||
serde_json::to_string(self).expect("serde_json::to_string failed");
|
|
||||||
Some(json)
|
Some(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,7 @@ impl Decoder for FileDecoder {
|
||||||
type Item = Bytes;
|
type Item = Bytes;
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
|
||||||
fn decode(
|
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
&mut self,
|
|
||||||
src: &mut BytesMut,
|
|
||||||
) -> Result<Option<Self::Item>, Self::Error> {
|
|
||||||
if src.is_empty() {
|
if src.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
@ -22,20 +19,13 @@ impl Decoder for FileDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn file_to_part(path_to_file: PathBuf) -> std::io::Result<Part> {
|
pub async fn file_to_part(path_to_file: PathBuf) -> std::io::Result<Part> {
|
||||||
let file_name =
|
let file_name = path_to_file.file_name().unwrap().to_string_lossy().into_owned();
|
||||||
path_to_file.file_name().unwrap().to_string_lossy().into_owned();
|
|
||||||
|
|
||||||
let file = FramedRead::new(
|
let file = FramedRead::new(tokio::fs::File::open(path_to_file).await?, FileDecoder);
|
||||||
tokio::fs::File::open(path_to_file).await?,
|
|
||||||
FileDecoder,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Part::stream(Body::wrap_stream(file)).file_name(file_name))
|
Ok(Part::stream(Body::wrap_stream(file)).file_name(file_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_from_memory_to_part(
|
pub fn file_from_memory_to_part(data: Cow<'static, [u8]>, name: String) -> Part {
|
||||||
data: Cow<'static, [u8]>,
|
|
||||||
name: String,
|
|
||||||
) -> Part {
|
|
||||||
Part::bytes(data).file_name(name)
|
Part::bytes(data).file_name(name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,7 @@ mod tests {
|
||||||
duration: 60,
|
duration: 60,
|
||||||
performer: Some("Performer".to_string()),
|
performer: Some("Performer".to_string()),
|
||||||
title: Some("Title".to_string()),
|
title: Some("Title".to_string()),
|
||||||
mime_type: Some(
|
mime_type: Some(serde_json::from_str("\"application/zip\"").unwrap()),
|
||||||
serde_json::from_str("\"application/zip\"").unwrap(),
|
|
||||||
),
|
|
||||||
file_size: Some(123_456),
|
file_size: Some(123_456),
|
||||||
thumb: Some(PhotoSize {
|
thumb: Some(PhotoSize {
|
||||||
file_id: "id".to_string(),
|
file_id: "id".to_string(),
|
||||||
|
|
|
@ -154,16 +154,10 @@ impl<'de> serde::de::Visitor<'de> for PrivateChatKindVisitor {
|
||||||
write!(f, r#"field equal to "private""#)
|
write!(f, r#"field equal to "private""#)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_borrowed_str<E: serde::de::Error>(
|
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
|
||||||
self,
|
|
||||||
v: &'de str,
|
|
||||||
) -> Result<Self::Value, E> {
|
|
||||||
match v {
|
match v {
|
||||||
"private" => Ok(()),
|
"private" => Ok(()),
|
||||||
_ => Err(E::invalid_value(
|
_ => Err(E::invalid_value(serde::de::Unexpected::Str(v), &r#""private""#)),
|
||||||
serde::de::Unexpected::Str(v),
|
|
||||||
&r#""private""#,
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,30 +174,16 @@ impl Chat {
|
||||||
matches!(self.kind, ChatKind::Private(_))
|
matches!(self.kind, ChatKind::Private(_))
|
||||||
}
|
}
|
||||||
pub fn is_group(&self) -> bool {
|
pub fn is_group(&self) -> bool {
|
||||||
matches!(
|
matches!(self.kind, ChatKind::Public(ChatPublic { kind: PublicChatKind::Group(_), .. }))
|
||||||
self.kind,
|
|
||||||
ChatKind::Public(ChatPublic {
|
|
||||||
kind: PublicChatKind::Group(_), ..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
pub fn is_supergroup(&self) -> bool {
|
pub fn is_supergroup(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.kind,
|
self.kind,
|
||||||
ChatKind::Public(ChatPublic {
|
ChatKind::Public(ChatPublic { kind: PublicChatKind::Supergroup(_), .. })
|
||||||
kind: PublicChatKind::Supergroup(_),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn is_channel(&self) -> bool {
|
pub fn is_channel(&self) -> bool {
|
||||||
matches!(
|
matches!(self.kind, ChatKind::Public(ChatPublic { kind: PublicChatKind::Channel(_), .. }))
|
||||||
self.kind,
|
|
||||||
ChatKind::Public(ChatPublic {
|
|
||||||
kind: PublicChatKind::Channel(_),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_chat(&self) -> bool {
|
pub fn is_chat(&self) -> bool {
|
||||||
|
@ -232,9 +212,7 @@ mod tests {
|
||||||
}),
|
}),
|
||||||
photo: None,
|
photo: None,
|
||||||
};
|
};
|
||||||
let actual =
|
let actual = from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#).unwrap();
|
||||||
from_str(r#"{"id":-1,"type":"channel","username":"channelname"}"#)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,9 +229,9 @@ mod tests {
|
||||||
}),
|
}),
|
||||||
photo: None,
|
photo: None,
|
||||||
},
|
},
|
||||||
from_str(
|
from_str(r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#)
|
||||||
r#"{"id":0,"type":"private","username":"username","first_name":"Anon"}"#
|
.unwrap()
|
||||||
).unwrap());
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -3,9 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A unique identifier for the target chat or username of the target channel
|
/// A unique identifier for the target chat or username of the target channel
|
||||||
/// (in the format `@channelusername`).
|
/// (in the format `@channelusername`).
|
||||||
#[derive(
|
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From)]
|
||||||
Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Display, From,
|
|
||||||
)]
|
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum ChatId {
|
pub enum ChatId {
|
||||||
/// A chat identifier.
|
/// A chat identifier.
|
||||||
|
@ -32,10 +30,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn chat_id_channel_username_serialization() {
|
fn chat_id_channel_username_serialization() {
|
||||||
let expected_json = String::from(r#""@username""#);
|
let expected_json = String::from(r#""@username""#);
|
||||||
let actual_json = serde_json::to_string(&ChatId::ChannelUsername(
|
let actual_json =
|
||||||
String::from("@username"),
|
serde_json::to_string(&ChatId::ChannelUsername(String::from("@username"))).unwrap();
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(expected_json, actual_json)
|
assert_eq!(expected_json, actual_json)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,7 @@ mod tests {
|
||||||
secret: "secret".to_string(),
|
secret: "secret".to_string(),
|
||||||
};
|
};
|
||||||
// when
|
// when
|
||||||
let actual_json =
|
let actual_json = serde_json::to_string(&encrypted_credentials).unwrap();
|
||||||
serde_json::to_string(&encrypted_credentials).unwrap();
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(actual_json, expected_json)
|
assert_eq!(actual_json, expected_json)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,35 +79,21 @@ pub enum InlineKeyboardButtonKind {
|
||||||
/// ```
|
/// ```
|
||||||
/// use teloxide::types::InlineKeyboardButton;
|
/// use teloxide::types::InlineKeyboardButton;
|
||||||
///
|
///
|
||||||
/// let url_button = InlineKeyboardButton::url(
|
/// let url_button = InlineKeyboardButton::url("Text".to_string(), "http://url.com".to_string());
|
||||||
/// "Text".to_string(),
|
|
||||||
/// "http://url.com".to_string(),
|
|
||||||
/// );
|
|
||||||
/// ```
|
/// ```
|
||||||
impl InlineKeyboardButton {
|
impl InlineKeyboardButton {
|
||||||
pub fn url(text: String, url: String) -> InlineKeyboardButton {
|
pub fn url(text: String, url: String) -> InlineKeyboardButton {
|
||||||
InlineKeyboardButton { text, kind: InlineKeyboardButtonKind::Url(url) }
|
InlineKeyboardButton { text, kind: InlineKeyboardButtonKind::Url(url) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn callback(
|
pub fn callback(text: String, callback_data: String) -> InlineKeyboardButton {
|
||||||
text: String,
|
InlineKeyboardButton { text, kind: InlineKeyboardButtonKind::CallbackData(callback_data) }
|
||||||
callback_data: String,
|
|
||||||
) -> InlineKeyboardButton {
|
|
||||||
InlineKeyboardButton {
|
|
||||||
text,
|
|
||||||
kind: InlineKeyboardButtonKind::CallbackData(callback_data),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn switch_inline_query(
|
pub fn switch_inline_query(text: String, switch_inline_query: String) -> InlineKeyboardButton {
|
||||||
text: String,
|
|
||||||
switch_inline_query: String,
|
|
||||||
) -> InlineKeyboardButton {
|
|
||||||
InlineKeyboardButton {
|
InlineKeyboardButton {
|
||||||
text,
|
text,
|
||||||
kind: InlineKeyboardButtonKind::SwitchInlineQuery(
|
kind: InlineKeyboardButtonKind::SwitchInlineQuery(switch_inline_query),
|
||||||
switch_inline_query,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,7 @@ pub struct InlineKeyboardMarkup {
|
||||||
/// ```
|
/// ```
|
||||||
/// use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
|
/// use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
|
||||||
///
|
///
|
||||||
/// let url_button = InlineKeyboardButton::url(
|
/// let url_button = InlineKeyboardButton::url("text".to_string(), "http://url.com".to_string());
|
||||||
/// "text".to_string(),
|
|
||||||
/// "http://url.com".to_string(),
|
|
||||||
/// );
|
|
||||||
/// let keyboard = InlineKeyboardMarkup::default().append_row(vec![url_button]);
|
/// let keyboard = InlineKeyboardMarkup::default().append_row(vec![url_button]);
|
||||||
/// ```
|
/// ```
|
||||||
impl InlineKeyboardMarkup {
|
impl InlineKeyboardMarkup {
|
||||||
|
@ -38,11 +35,7 @@ impl InlineKeyboardMarkup {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_to_row(
|
pub fn append_to_row(mut self, button: InlineKeyboardButton, index: usize) -> Self {
|
||||||
mut self,
|
|
||||||
button: InlineKeyboardButton,
|
|
||||||
index: usize,
|
|
||||||
) -> Self {
|
|
||||||
match self.inline_keyboard.get_mut(index) {
|
match self.inline_keyboard.get_mut(index) {
|
||||||
Some(buttons) => buttons.push(button),
|
Some(buttons) => buttons.push(button),
|
||||||
None => self.inline_keyboard.push(vec![button]),
|
None => self.inline_keyboard.push(vec![button]),
|
||||||
|
@ -57,65 +50,41 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn append_row() {
|
fn append_row() {
|
||||||
let button1 = InlineKeyboardButton::url(
|
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
|
||||||
"text 1".to_string(),
|
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
|
||||||
"url 1".to_string(),
|
|
||||||
);
|
|
||||||
let button2 = InlineKeyboardButton::url(
|
|
||||||
"text 2".to_string(),
|
|
||||||
"url 2".to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let markup = InlineKeyboardMarkup::default()
|
let markup =
|
||||||
.append_row(vec![button1.clone(), button2.clone()]);
|
InlineKeyboardMarkup::default().append_row(vec![button1.clone(), button2.clone()]);
|
||||||
|
|
||||||
let expected = InlineKeyboardMarkup {
|
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1, button2]] };
|
||||||
inline_keyboard: vec![vec![button1, button2]],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(markup, expected);
|
assert_eq!(markup, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn append_to_row_existent_row() {
|
fn append_to_row_existent_row() {
|
||||||
let button1 = InlineKeyboardButton::url(
|
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
|
||||||
"text 1".to_string(),
|
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
|
||||||
"url 1".to_string(),
|
|
||||||
);
|
|
||||||
let button2 = InlineKeyboardButton::url(
|
|
||||||
"text 2".to_string(),
|
|
||||||
"url 2".to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let markup = InlineKeyboardMarkup::default()
|
let markup = InlineKeyboardMarkup::default()
|
||||||
.append_row(vec![button1.clone()])
|
.append_row(vec![button1.clone()])
|
||||||
.append_to_row(button2.clone(), 0);
|
.append_to_row(button2.clone(), 0);
|
||||||
|
|
||||||
let expected = InlineKeyboardMarkup {
|
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1, button2]] };
|
||||||
inline_keyboard: vec![vec![button1, button2]],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(markup, expected);
|
assert_eq!(markup, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn append_to_row_nonexistent_row() {
|
fn append_to_row_nonexistent_row() {
|
||||||
let button1 = InlineKeyboardButton::url(
|
let button1 = InlineKeyboardButton::url("text 1".to_string(), "url 1".to_string());
|
||||||
"text 1".to_string(),
|
let button2 = InlineKeyboardButton::url("text 2".to_string(), "url 2".to_string());
|
||||||
"url 1".to_string(),
|
|
||||||
);
|
|
||||||
let button2 = InlineKeyboardButton::url(
|
|
||||||
"text 2".to_string(),
|
|
||||||
"url 2".to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let markup = InlineKeyboardMarkup::default()
|
let markup = InlineKeyboardMarkup::default()
|
||||||
.append_row(vec![button1.clone()])
|
.append_row(vec![button1.clone()])
|
||||||
.append_to_row(button2.clone(), 1);
|
.append_to_row(button2.clone(), 1);
|
||||||
|
|
||||||
let expected = InlineKeyboardMarkup {
|
let expected = InlineKeyboardMarkup { inline_keyboard: vec![vec![button1], vec![button2]] };
|
||||||
inline_keyboard: vec![vec![button1], vec![button2]],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(markup, expected);
|
assert_eq!(markup, expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,13 @@ use derive_more::From;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
InlineQueryResultArticle, InlineQueryResultAudio,
|
InlineQueryResultArticle, InlineQueryResultAudio, InlineQueryResultCachedAudio,
|
||||||
InlineQueryResultCachedAudio, InlineQueryResultCachedDocument,
|
InlineQueryResultCachedDocument, InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif,
|
||||||
InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif,
|
InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker, InlineQueryResultCachedVideo,
|
||||||
InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker,
|
InlineQueryResultCachedVoice, InlineQueryResultContact, InlineQueryResultDocument,
|
||||||
InlineQueryResultCachedVideo, InlineQueryResultCachedVoice,
|
InlineQueryResultGame, InlineQueryResultGif, InlineQueryResultLocation,
|
||||||
InlineQueryResultContact, InlineQueryResultDocument, InlineQueryResultGame,
|
InlineQueryResultMpeg4Gif, InlineQueryResultPhoto, InlineQueryResultVenue,
|
||||||
InlineQueryResultGif, InlineQueryResultLocation, InlineQueryResultMpeg4Gif,
|
InlineQueryResultVideo, InlineQueryResultVoice,
|
||||||
InlineQueryResultPhoto, InlineQueryResultVenue, InlineQueryResultVideo,
|
|
||||||
InlineQueryResultVoice,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This object represents one result of an inline query.
|
/// This object represents one result of an inline query.
|
||||||
|
@ -57,25 +55,22 @@ pub enum InlineQueryResult {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode,
|
inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode, InlineQueryResult,
|
||||||
InlineQueryResult, InlineQueryResultCachedAudio, InputMessageContent,
|
InlineQueryResultCachedAudio, InputMessageContent, InputMessageContentText,
|
||||||
InputMessageContentText,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cached_audio_min_serialize() {
|
fn cached_audio_min_serialize() {
|
||||||
let structure =
|
let structure = InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
|
||||||
InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
|
id: String::from("id"),
|
||||||
id: String::from("id"),
|
audio_file_id: String::from("audio_file_id"),
|
||||||
audio_file_id: String::from("audio_file_id"),
|
caption: None,
|
||||||
caption: None,
|
parse_mode: None,
|
||||||
parse_mode: None,
|
reply_markup: None,
|
||||||
reply_markup: None,
|
input_message_content: None,
|
||||||
input_message_content: None,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let expected_json =
|
let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id"}"#;
|
||||||
r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id"}"#;
|
|
||||||
let actual_json = serde_json::to_string(&structure).unwrap();
|
let actual_json = serde_json::to_string(&structure).unwrap();
|
||||||
|
|
||||||
assert_eq!(expected_json, actual_json);
|
assert_eq!(expected_json, actual_json);
|
||||||
|
@ -83,21 +78,18 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cached_audio_full_serialize() {
|
fn cached_audio_full_serialize() {
|
||||||
let structure =
|
let structure = InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
|
||||||
InlineQueryResult::CachedAudio(InlineQueryResultCachedAudio {
|
id: String::from("id"),
|
||||||
id: String::from("id"),
|
audio_file_id: String::from("audio_file_id"),
|
||||||
audio_file_id: String::from("audio_file_id"),
|
caption: Some(String::from("caption")),
|
||||||
caption: Some(String::from("caption")),
|
parse_mode: Some(ParseMode::HTML),
|
||||||
parse_mode: Some(ParseMode::HTML),
|
reply_markup: Some(InlineKeyboardMarkup::default()),
|
||||||
reply_markup: Some(InlineKeyboardMarkup::default()),
|
input_message_content: Some(InputMessageContent::Text(InputMessageContentText {
|
||||||
input_message_content: Some(InputMessageContent::Text(
|
message_text: String::from("message_text"),
|
||||||
InputMessageContentText {
|
parse_mode: Some(ParseMode::MarkdownV2),
|
||||||
message_text: String::from("message_text"),
|
disable_web_page_preview: Some(true),
|
||||||
parse_mode: Some(ParseMode::MarkdownV2),
|
})),
|
||||||
disable_web_page_preview: Some(true),
|
});
|
||||||
},
|
|
||||||
)),
|
|
||||||
});
|
|
||||||
|
|
||||||
let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id","caption":"caption","parse_mode":"HTML","reply_markup":{"inline_keyboard":[]},"input_message_content":{"message_text":"message_text","parse_mode":"MarkdownV2","disable_web_page_preview":true}}"#;
|
let expected_json = r#"{"type":"audio","id":"id","audio_file_id":"audio_file_id","caption":"caption","parse_mode":"HTML","reply_markup":{"inline_keyboard":[]},"input_message_content":{"message_text":"message_text","parse_mode":"MarkdownV2","disable_web_page_preview":true}}"#;
|
||||||
let actual_json = serde_json::to_string(&structure).unwrap();
|
let actual_json = serde_json::to_string(&structure).unwrap();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode};
|
||||||
InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents a link to a file.
|
/// Represents a link to a file.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode};
|
||||||
InlineKeyboardMarkup, InputMessageContent, MimeWrapper, ParseMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents a link to a page containing an embedded video player or a video
|
/// Represents a link to a page containing an embedded video player or a video
|
||||||
/// file.
|
/// file.
|
||||||
|
|
|
@ -85,19 +85,13 @@ impl Serialize for InputFile {
|
||||||
// multipart/form-data
|
// multipart/form-data
|
||||||
serializer.serialize_str(
|
serializer.serialize_str(
|
||||||
// TODO: remove unwrap (?)
|
// TODO: remove unwrap (?)
|
||||||
&format!(
|
&format!("attach://{}", path.file_name().unwrap().to_string_lossy()),
|
||||||
"attach://{}",
|
|
||||||
path.file_name().unwrap().to_string_lossy()
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
InputFile::Memory { data, .. } => {
|
InputFile::Memory { data, .. } => {
|
||||||
// NOTE: file should be actually attached with
|
// NOTE: file should be actually attached with
|
||||||
// multipart/form-data
|
// multipart/form-data
|
||||||
serializer.serialize_str(&format!(
|
serializer.serialize_str(&format!("attach://{}", String::from_utf8_lossy(data)))
|
||||||
"attach://{}",
|
|
||||||
String::from_utf8_lossy(data)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
InputFile::Url(url) => serializer.serialize_str(url),
|
InputFile::Url(url) => serializer.serialize_str(url),
|
||||||
InputFile::FileId(id) => serializer.serialize_str(id),
|
InputFile::FileId(id) => serializer.serialize_str(id),
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue