use crate::{
connectors::{self, Connector},
download_file, errors,
event_loop::EventLoop,
methods::*,
types::{
callback, chat,
file::{id::AsFileId, File},
inline_message_id, inline_query,
input_file::{
Animation, Audio, ChatPhoto, Document, EditableMedia, GroupMedia,
Photo, PngSticker, Sticker, Video, VideoNote, Voice,
},
keyboard::inline,
message,
parameters::{CallbackAction, ImplicitChatId, Text, UpdateKind},
passport, pre_checkout_query, shipping, user, LabeledPrice,
},
Token,
};
use std::sync::Arc;
#[derive(Debug, Clone)]
#[must_use]
pub struct Bot<C> {
pub(crate) token: Token,
pub(crate) client: Arc<crate::internal::Client<C>>,
}
impl Bot<connectors::Https> {
pub fn new(token: String) -> Self {
Self {
token: Token::new(token),
client: Arc::new(connectors::default()),
}
}
pub fn from_env(env_var: &'static str) -> Self {
Self::new(extract_token(env_var))
}
}
impl<C> Bot<C> {
pub fn event_loop(self) -> EventLoop<C> {
EventLoop::new(self)
}
pub fn add_sticker_to_set<'a>(
&'a self,
user_id: user::Id,
name: &'a str,
png_sticker: PngSticker<'a>,
emojis: &'a str,
) -> AddStickerToSet<'a, C> {
AddStickerToSet::new(
&self.client,
self.token.as_ref(),
user_id,
name,
png_sticker,
emojis,
)
}
pub(crate) fn answer_callback_query<'a>(
&'a self,
callback_query_id: callback::query::id::Ref<'a>,
action: CallbackAction<'a>,
) -> AnswerCallbackQuery<'a, C> {
AnswerCallbackQuery::new(
&self.client,
self.token.as_ref(),
callback_query_id,
action,
)
}
pub(crate) fn answer_inline_query<'a>(
&'a self,
inline_query_id: inline_query::id::Ref<'a>,
results: &'a [inline_query::Result<'a>],
) -> AnswerInlineQuery<'a, C> {
AnswerInlineQuery::new(
&self.client,
self.token.as_ref(),
inline_query_id,
results,
)
}
pub(crate) fn answer_pre_checkout_query<'a>(
&'a self,
pre_checkout_query_id: pre_checkout_query::id::Ref<'a>,
result: Result<(), &'a str>,
) -> AnswerPreCheckoutQuery<'a, C> {
AnswerPreCheckoutQuery::new(
&self.client,
self.token.as_ref(),
pre_checkout_query_id,
result,
)
}
pub(crate) fn answer_shipping_query<'a>(
&'a self,
shipping_query_id: shipping::query::id::Ref<'a>,
result: Result<&'a [shipping::Option<'a>], &'a str>,
) -> AnswerShippingQuery<'a, C> {
AnswerShippingQuery::new(
&self.client,
self.token.as_ref(),
shipping_query_id,
result,
)
}
pub fn create_new_sticker_set<'a>(
&'a self,
user_id: user::Id,
name: &'a str,
title: &'a str,
png_sticker: PngSticker<'a>,
emojis: &'a str,
) -> CreateNewStickerSet<'a, C> {
CreateNewStickerSet::new(
&self.client,
self.token.as_ref(),
user_id,
name,
title,
png_sticker,
emojis,
)
}
pub fn delete_chat_photo<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> DeleteChatPhoto<'a, C> {
DeleteChatPhoto::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn delete_chat_sticker_set<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> DeleteChatStickerSet<'a, C> {
DeleteChatStickerSet::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn delete_message<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
) -> DeleteMessage<'a, C> {
DeleteMessage::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
)
}
pub fn delete_sticker_from_set<'a>(
&'a self,
sticker: &'a str,
) -> DeleteStickerFromSet<'a, C> {
DeleteStickerFromSet::new(&self.client, self.token.as_ref(), sticker)
}
pub(crate) fn delete_webhook(&self) -> DeleteWebhook<'_, C> {
DeleteWebhook::new(&self.client, self.token.as_ref())
}
pub fn edit_inline_caption<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
caption: impl Into<Text<'a>>,
) -> EditInlineCaption<'a, C> {
EditInlineCaption::new(
&self.client,
self.token.as_ref(),
inline_message_id,
caption,
)
}
pub fn edit_inline_location<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
position: (f64, f64),
) -> EditInlineLocation<'a, C> {
EditInlineLocation::new(
&self.client,
self.token.as_ref(),
inline_message_id,
position,
)
}
pub fn edit_inline_media<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
media: impl Into<EditableMedia<'a>>,
) -> EditInlineMedia<'a, C> {
EditInlineMedia::new(
&self.client,
self.token.as_ref(),
inline_message_id,
media,
)
}
pub fn edit_inline_reply_markup<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
reply_markup: inline::Keyboard<'a>,
) -> EditInlineReplyMarkup<'a, C> {
EditInlineReplyMarkup::new(
&self.client,
self.token.as_ref(),
inline_message_id,
reply_markup,
)
}
pub fn edit_inline_text<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
text: impl Into<Text<'a>>,
) -> EditInlineText<'a, C> {
EditInlineText::new(
&self.client,
self.token.as_ref(),
inline_message_id,
text,
)
}
pub fn edit_message_caption<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
caption: impl Into<Text<'a>>,
) -> EditMessageCaption<'a, C> {
EditMessageCaption::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
caption,
)
}
pub fn edit_message_location<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
position: (f64, f64),
) -> EditMessageLocation<'a, C> {
EditMessageLocation::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
position,
)
}
pub fn edit_message_media<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
media: impl Into<EditableMedia<'a>>,
) -> EditMessageMedia<'a, C> {
EditMessageMedia::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
media,
)
}
pub fn edit_message_reply_markup<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
reply_markup: inline::Keyboard<'a>,
) -> EditMessageReplyMarkup<'a, C> {
EditMessageReplyMarkup::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
reply_markup,
)
}
pub fn edit_message_text<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
text: impl Into<Text<'a>>,
) -> EditMessageText<'a, C> {
EditMessageText::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
text,
)
}
pub fn export_chat_invite_link<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> ExportChatInviteLink<'a, C> {
ExportChatInviteLink::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn forward_message<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
from_chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
) -> ForwardMessage<'a, C> {
ForwardMessage::new(
&self.client,
self.token.as_ref(),
chat_id,
from_chat_id,
message_id,
)
}
pub fn get_chat<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> GetChat<'a, C> {
GetChat::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn get_file<'a>(
&'a self,
file_id: &'a impl AsFileId,
) -> GetFile<'a, C> {
GetFile::new(&self.client, self.token.as_ref(), file_id)
}
pub fn get_inline_game_high_scores<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
user_id: user::Id,
) -> GetInlineGameHighScores<'a, C> {
GetInlineGameHighScores::new(
&self.client,
self.token.as_ref(),
inline_message_id,
user_id,
)
}
pub fn get_chat_administrators<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> GetChatAdministrators<'a, C> {
GetChatAdministrators::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn get_chat_member<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
user_id: user::Id,
) -> GetChatMember<'a, C> {
GetChatMember::new(&self.client, self.token.as_ref(), chat_id, user_id)
}
pub fn get_chat_members_count<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> GetChatMembersCount<'a, C> {
GetChatMembersCount::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn get_message_game_high_scores<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
user_id: user::Id,
) -> GetMessageGameHighScores<'a, C> {
GetMessageGameHighScores::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
user_id,
)
}
pub fn get_me(&self) -> GetMe<'_, C> {
GetMe::new(&self.client, self.token.as_ref())
}
pub fn get_sticker_set<'a>(
&'a self,
name: &'a str,
) -> GetStickerSet<'a, C> {
GetStickerSet::new(&self.client, self.token.as_ref(), name)
}
pub(crate) fn get_updates<'a>(
&'a self,
offset: Option<isize>,
limit: Option<u8>,
timeout: Option<u64>,
allowed_updates: Option<&'a [UpdateKind]>,
) -> GetUpdates<'a, C> {
GetUpdates::new(
&self.client,
self.token.as_ref(),
offset,
limit,
timeout,
allowed_updates,
)
}
pub fn get_user_profile_photos(
&self,
user_id: user::Id,
) -> GetUserProfilePhotos<'_, C> {
GetUserProfilePhotos::new(&self.client, self.token.as_ref(), user_id)
}
pub fn get_webhook_info(&self) -> GetWebhookInfo<'_, C> {
GetWebhookInfo::new(&self.client, self.token.as_ref())
}
pub fn kick_chat_member<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
user_id: user::Id,
) -> KickChatMember<'a, C> {
KickChatMember::new(&self.client, self.token.as_ref(), chat_id, user_id)
}
pub fn leave_chat<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> LeaveChat<'a, C> {
LeaveChat::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn pin_chat_message<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
) -> PinChatMessage<'a, C> {
PinChatMessage::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
)
}
pub fn promote_chat_member<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
user_id: user::Id,
) -> PromoteChatMember<'a, C> {
PromoteChatMember::new(
&self.client,
self.token.as_ref(),
chat_id,
user_id,
)
}
pub fn restrict_chat_member<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
user_id: user::Id,
permissions: chat::Permissions,
) -> RestrictChatMember<'a, C> {
RestrictChatMember::new(
&self.client,
self.token.as_ref(),
chat_id,
user_id,
permissions,
)
}
pub fn send_animation<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
animation: Animation<'a>,
) -> SendAnimation<'a, C> {
SendAnimation::new(
&self.client,
self.token.as_ref(),
chat_id,
animation,
)
}
pub fn send_audio<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
audio: Audio<'a>,
) -> SendAudio<'a, C> {
SendAudio::new(&self.client, self.token.as_ref(), chat_id, audio)
}
pub fn send_chat_action<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
action: chat::Action,
) -> SendChatAction<'a, C> {
SendChatAction::new(&self.client, self.token.as_ref(), chat_id, action)
}
pub fn send_contact<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
phone_number: &'a str,
first_name: &'a str,
) -> SendContact<'a, C> {
SendContact::new(
&self.client,
self.token.as_ref(),
chat_id,
phone_number,
first_name,
)
}
pub fn send_game<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
game_short_name: &'a str,
) -> SendGame<'a, C> {
SendGame::new(
&self.client,
self.token.as_ref(),
chat_id,
game_short_name,
)
}
pub fn send_document<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
document: Document<'a>,
) -> SendDocument<'a, C> {
SendDocument::new(&self.client, self.token.as_ref(), chat_id, document)
}
#[allow(clippy::too_many_arguments)]
pub fn send_invoice<'a>(
&'a self,
chat_id: impl Into<chat::Id>,
title: &'a str,
description: &'a str,
payload: &'a str,
provider_token: &'a str,
start_parameter: &'a str,
currency: &'a str,
prices: &'a [LabeledPrice<'a>],
) -> SendInvoice<'a, C> {
SendInvoice::new(
&self.client,
self.token.as_ref(),
chat_id,
title,
description,
payload,
provider_token,
start_parameter,
currency,
prices,
)
}
pub fn send_location<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
position: (f64, f64),
) -> SendLocation<'a, C> {
SendLocation::new(&self.client, self.token.as_ref(), chat_id, position)
}
pub fn send_media_group<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
media: &'a [GroupMedia<'a>],
) -> SendMediaGroup<'a, C> {
SendMediaGroup::new(&self.client, self.token.as_ref(), chat_id, media)
}
pub fn send_message<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
text: impl Into<Text<'a>>,
) -> SendMessage<'a, C> {
SendMessage::new(&self.client, self.token.as_ref(), chat_id, text)
}
pub fn send_photo<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
photo: Photo<'a>,
) -> SendPhoto<'a, C> {
SendPhoto::new(&self.client, self.token.as_ref(), chat_id, photo)
}
pub fn send_poll<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
question: &'a str,
options: &'a [&'a str],
) -> SendPoll<'a, C> {
SendPoll::new(
&self.client,
self.token.as_ref(),
chat_id,
question,
options,
)
}
pub fn send_sticker<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
sticker: Sticker<'a>,
) -> SendSticker<'a, C> {
SendSticker::new(&self.client, self.token.as_ref(), chat_id, sticker)
}
pub fn send_venue<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
position: (f64, f64),
title: &'a str,
address: &'a str,
) -> SendVenue<'a, C> {
SendVenue::new(
&self.client,
self.token.as_ref(),
chat_id,
position,
title,
address,
)
}
pub fn send_video_note<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
video_note: VideoNote<'a>,
) -> SendVideoNote<'a, C> {
SendVideoNote::new(
&self.client,
self.token.as_ref(),
chat_id,
video_note,
)
}
pub fn send_video<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
video: Video<'a>,
) -> SendVideo<'a, C> {
SendVideo::new(&self.client, self.token.as_ref(), chat_id, video)
}
pub fn send_voice<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
voice: Voice<'a>,
) -> SendVoice<'a, C> {
SendVoice::new(&self.client, self.token.as_ref(), chat_id, voice)
}
pub fn set_chat_description<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
description: &'a str,
) -> SetChatDescription<'a, C> {
SetChatDescription::new(
&self.client,
self.token.as_ref(),
chat_id,
description,
)
}
pub fn set_chat_permissions<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
permissions: chat::Permissions,
) -> SetChatPermissions<'a, C> {
SetChatPermissions::new(
&self.client,
self.token.as_ref(),
chat_id,
permissions,
)
}
pub fn set_chat_photo<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
photo: ChatPhoto<'a>,
) -> SetChatPhoto<'a, C> {
SetChatPhoto::new(&self.client, self.token.as_ref(), chat_id, photo)
}
pub fn set_chat_sticker_set<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
sticker_set_name: &'a str,
) -> SetChatStickerSet<'a, C> {
SetChatStickerSet::new(
&self.client,
self.token.as_ref(),
chat_id,
sticker_set_name,
)
}
pub fn set_chat_title<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
title: &'a str,
) -> SetChatTitle<'a, C> {
SetChatTitle::new(&self.client, self.token.as_ref(), chat_id, title)
}
pub fn set_inline_game_score<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
user_id: user::Id,
score: u32,
) -> SetInlineGameScore<'a, C> {
SetInlineGameScore::new(
&self.client,
self.token.as_ref(),
inline_message_id,
user_id,
score,
)
}
pub fn set_message_game_score<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
user_id: user::Id,
score: u32,
) -> SetMessageGameScore<'a, C> {
SetMessageGameScore::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
user_id,
score,
)
}
pub fn set_passport_data_errors<'a>(
&'a self,
user_id: user::Id,
errors: &'a [passport::element::Error<'a>],
) -> SetPassportDataErrors<'a, C> {
SetPassportDataErrors::new(
&self.client,
self.token.as_ref(),
user_id,
errors,
)
}
pub fn set_sticker_position_in_set<'a>(
&'a self,
sticker: &'a str,
position: u32,
) -> SetStickerPositionInSet<'a, C> {
SetStickerPositionInSet::new(
&self.client,
self.token.as_ref(),
sticker,
position,
)
}
pub(crate) fn set_webhook<'a>(
&'a self,
url: &'a str,
certificate: Option<&'a str>,
max_connections: Option<u8>,
allowed_updates: Option<&'a [UpdateKind]>,
) -> SetWebhook<'a, C> {
SetWebhook::new(
&self.client,
self.token.as_ref(),
url,
certificate,
max_connections,
allowed_updates,
)
}
pub fn stop_inline_location<'a>(
&'a self,
inline_message_id: inline_message_id::Ref<'a>,
) -> StopInlineLocation<'a, C> {
StopInlineLocation::new(
&self.client,
self.token.as_ref(),
inline_message_id,
)
}
pub fn stop_message_location<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
) -> StopMessageLocation<'a, C> {
StopMessageLocation::new(
&self.client,
self.token.as_ref(),
chat_id,
message_id,
)
}
pub fn stop_poll<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
message_id: message::Id,
) -> StopPoll<'a, C> {
StopPoll::new(&self.client, self.token.as_ref(), chat_id, message_id)
}
pub fn unban_chat_member<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
user_id: user::Id,
) -> UnbanChatMember<'a, C> {
UnbanChatMember::new(
&self.client,
self.token.as_ref(),
chat_id,
user_id,
)
}
pub fn unpin_chat_message<'a>(
&'a self,
chat_id: impl ImplicitChatId<'a>,
) -> UnpinChatMessage<'a, C> {
UnpinChatMessage::new(&self.client, self.token.as_ref(), chat_id)
}
pub fn upload_sticker_file<'a>(
&'a self,
user_id: user::Id,
png_sticker: &'a [u8],
) -> UploadStickerFile<'a, C> {
UploadStickerFile::new(
&self.client,
self.token.as_ref(),
user_id,
png_sticker,
)
}
}
impl<C: Connector> Bot<C> {
pub fn with_connector(token: String, connector: C) -> Self {
Self {
token: Token::new(token),
client: Arc::new(connectors::create_client(connector)),
}
}
pub fn from_env_with_connector(
env_var: &'static str,
connector: C,
) -> Self {
Self::with_connector(extract_token(env_var), connector)
}
pub async fn download_file(
&self,
file: &File,
) -> Result<Vec<u8>, errors::Download> {
download_file(&self.client, self.token.as_ref(), file).await
}
}
#[macro_export]
macro_rules! from_env {
($var:literal) => {{
let token = env!($var).to_string();
$crate::Bot::new(token)
}};
($var:literal,) => {
$crate::from_env!($var)
};
($var:literal, $connector:expr) => {{
let token = env!($var).to_string();
$crate::Bot::with_connector(token, $connector)
}};
($var:literal, $connector:expr,) => {
$crate::from_env!($var, $connector)
};
() => {
compile_error!(
"the macro must be invoked as `from_env!(\"<VAR_NAME>\")` or \
`from_env!(\"<VAR_NAME>\", connector)`"
)
};
($($x:tt)+) => {
$crate::from_env!()
};
}
fn extract_token(env_var: &'static str) -> String {
std::env::var(env_var).unwrap_or_else(|_| {
panic!("\n[tbot] Bot's token in {} was not specified\n", env_var)
})
}