mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
Add reference implementation of payloads
This commit is contained in:
parent
7e821f2401
commit
fa220a6883
9 changed files with 440 additions and 1 deletions
|
@ -17,6 +17,7 @@ pin-project = "0.4.0-alpha.7"
|
|||
futures-preview = "0.3.0-alpha.19"
|
||||
async-trait = "0.1.13"
|
||||
thiserror = "1.0.2"
|
||||
serde_with_macros = "1.0.1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -21,9 +21,16 @@ pub trait Payload: DynMethod {
|
|||
/// this type has _little_ overhead, so prefer using [json], [multipart] or
|
||||
/// [simple] requests when possible.
|
||||
///
|
||||
/// See [GetMe], [GetUpdates], [SendMessage] and [SendAnimation] for reference
|
||||
/// implementations.
|
||||
///
|
||||
/// [json]: crate::requests::json::Request
|
||||
/// [multipart]: crate::requests::multipart::Request
|
||||
/// [simple]: crate::requests::simple::Request
|
||||
/// [GetMe]: crate::requests::payloads::GetMe
|
||||
/// [GetUpdates]: crate::requests::payloads::GetUpdates
|
||||
/// [SendMessage]: crate::requests::payloads::SendMessage
|
||||
/// [SendAnimation]: crate::requests::payloads::SendAnimation
|
||||
#[must_use = "requests do nothing until sent"]
|
||||
pub struct Request<'b, O> {
|
||||
bot: &'b Bot,
|
||||
|
|
|
@ -9,7 +9,11 @@ pub trait Payload: Serialize + Method {}
|
|||
///
|
||||
/// Note: params will be sent to telegram using [`application/json`]
|
||||
///
|
||||
/// See [GetUpdates] and [SendMessage] for reference implementations.
|
||||
///
|
||||
/// [`application/json`]: https://core.telegram.org/bots/api#making-requests
|
||||
/// [GetUpdates]: crate::requests::payloads::GetUpdates
|
||||
/// [SendMessage]: crate::requests::payloads::SendMessage
|
||||
#[must_use = "requests do nothing until sent"]
|
||||
pub struct Request<'b, P> {
|
||||
bot: &'b Bot,
|
||||
|
|
|
@ -12,7 +12,10 @@ pub trait Payload: Method {
|
|||
///
|
||||
/// Note: params will be sent to telegram using [`multipart/form-data`]
|
||||
///
|
||||
/// See [SendAnimation] for reference implementation.
|
||||
///
|
||||
/// [`multipart/form-data`]: https://core.telegram.org/bots/api#making-requests
|
||||
/// [SendAnimation]: crate::requests::payloads::SendAnimation
|
||||
#[must_use = "requests do nothing until sent"]
|
||||
pub struct Request<'b, P> {
|
||||
bot: &'b Bot,
|
||||
|
|
23
src/requests/payloads/get_me.rs
Normal file
23
src/requests/payloads/get_me.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use crate::{
|
||||
requests::{Method, dynamic},
|
||||
types::User,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Deserialize, Serialize)]
|
||||
/// A filter method for testing your bot's auth token. Requires no parameters.
|
||||
/// Returns basic information about the bot in form of a [`User`] object.
|
||||
///
|
||||
/// [`User`]: crate::types::User
|
||||
pub struct GetMe;
|
||||
|
||||
impl Method for GetMe {
|
||||
type Output = User;
|
||||
|
||||
const METHOD: &'static str = "getMe";
|
||||
}
|
||||
|
||||
impl dynamic::Payload for GetMe {
|
||||
fn kind(&self) -> dynamic::Kind {
|
||||
dynamic::Kind::Simple
|
||||
}
|
||||
}
|
122
src/requests/payloads/get_updates.rs
Normal file
122
src/requests/payloads/get_updates.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
requests::{ResponseResult, json, Method, dynamic},
|
||||
types::Update,
|
||||
};
|
||||
|
||||
/// Use this method to receive incoming updates using long polling ([wiki]).
|
||||
/// An array ([`Vec`]) of [`Update`]s is returned.
|
||||
///
|
||||
/// **Notes:**
|
||||
/// 1. This method will not work if an outgoing webhook is set up.
|
||||
/// 2. In order to avoid getting duplicate updates,
|
||||
/// recalculate offset after each server response.
|
||||
///
|
||||
/// [wiki]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
|
||||
/// [Update]: crate::types::Update
|
||||
/// [Vec]: std::alloc::Vec
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
|
||||
pub struct GetUpdates {
|
||||
/// Identifier of the first update to be returned. Must be greater by one
|
||||
/// than the highest among the identifiers of previously received updates.
|
||||
/// By default, updates starting with the earliest unconfirmed update are
|
||||
/// returned. An update is considered confirmed as soon as [`GetUpdates`] is
|
||||
/// called with an [`offset`] higher than its [`id`]. The negative offset
|
||||
/// can be specified to retrieve updates starting from `-offset` update from
|
||||
/// the end of the updates queue. All previous updates will forgotten.
|
||||
///
|
||||
/// [`GetUpdates`]: self::GetUpdates
|
||||
/// [`offset`]: self::GetUpdates::offset
|
||||
/// [`id`]: crate::types::Update::id
|
||||
pub offset: Option<i32>,
|
||||
/// Limits the number of updates to be retrieved.
|
||||
/// Values between `1`—`100` are accepted. Defaults to `100`.
|
||||
pub limit: Option<u8>,
|
||||
/// Timeout in seconds for long polling. Defaults to `0`,
|
||||
/// i.e. usual short polling. Should be positive, short polling should be
|
||||
/// used for testing purposes only.
|
||||
pub timeout: Option<u32>,
|
||||
/// List the types of updates you want your bot to receive.
|
||||
/// For example, specify [[`Message`], [`EditedChannelPost`],
|
||||
/// [`CallbackQuery`]] to only receive updates of these types.
|
||||
/// See [`AllowedUpdate`] for a complete list of available update types.
|
||||
///
|
||||
/// Specify an empty list to receive all updates regardless of type
|
||||
/// (default). If not specified, the previous setting will be used.
|
||||
///
|
||||
/// **Note:**
|
||||
/// This parameter doesn't affect updates created before the call to the
|
||||
/// [`GetUpdates`], so unwanted updates may be received for a short period
|
||||
/// of time.
|
||||
///
|
||||
/// [`Message`]: self::AllowedUpdate::Message
|
||||
/// [`EditedChannelPost`]: self::AllowedUpdate::EditedChannelPost
|
||||
/// [`CallbackQuery`]: self::AllowedUpdate::CallbackQuery
|
||||
/// [`AllowedUpdate`]: self::AllowedUpdate
|
||||
/// [`GetUpdates`]: self::GetUpdates
|
||||
pub allowed_updates: Option<Vec<AllowedUpdate>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AllowedUpdate {
|
||||
Message,
|
||||
EditedMessage,
|
||||
ChannelPost,
|
||||
EditedChannelPost,
|
||||
InlineQuery,
|
||||
ChosenInlineResult,
|
||||
CallbackQuery,
|
||||
}
|
||||
|
||||
impl Method for GetUpdates {
|
||||
type Output = Vec<Update>;
|
||||
|
||||
const METHOD: &'static str = "getUpdates";
|
||||
}
|
||||
|
||||
impl json::Payload for GetUpdates {}
|
||||
|
||||
impl dynamic::Payload for GetUpdates {
|
||||
fn kind(&self) -> dynamic::Kind {
|
||||
dynamic::Kind::Json(serde_json::to_string(self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl GetUpdates {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
offset: None,
|
||||
limit: None,
|
||||
timeout: None,
|
||||
allowed_updates: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl json::Request<'_, GetUpdates> {
|
||||
pub fn offset(mut self, value: i32) -> Self {
|
||||
self.payload.offset = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn limit(mut self, value: u8) -> Self {
|
||||
self.payload.limit = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn timeout(mut self, value: u32) -> Self {
|
||||
self.payload.timeout = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn allowed_updates<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<Vec<AllowedUpdate>>, // TODO: into or other trait?
|
||||
{
|
||||
self.payload.allowed_updates = Some(value.into());
|
||||
self
|
||||
}
|
||||
}
|
162
src/requests/payloads/send_animation.rs
Normal file
162
src/requests/payloads/send_animation.rs
Normal file
|
@ -0,0 +1,162 @@
|
|||
use reqwest::multipart::Form;
|
||||
|
||||
use crate::{
|
||||
requests::{ResponseResult, multipart, Method, dynamic, form_builder::FormBuilder},
|
||||
types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
|
||||
/// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video
|
||||
/// without sound).
|
||||
///
|
||||
/// On success, the sent Message is returned.
|
||||
///
|
||||
/// Bots can currently send animation files of up to 50 MB in size, this limit
|
||||
/// may be changed in the future.
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
|
||||
pub struct SendAnimation {
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub chat_id: ChatId,
|
||||
/// Animation to send.
|
||||
pub animation: InputFile,
|
||||
/// Duration of sent animation in seconds
|
||||
pub duration: Option<u32>,
|
||||
/// Animation width
|
||||
pub width: Option<u32>,
|
||||
/// Animation height
|
||||
pub height: Option<u32>,
|
||||
/// Thumbnail of the file sent; can be ignored if thumbnail generation for
|
||||
/// the file is supported server-side. The thumbnail should be in JPEG
|
||||
/// format and less than 200 kB in size. A thumbnail‘s width and height
|
||||
/// should not exceed 320. Ignored if the file is not uploaded using
|
||||
/// [`InputFile::File`]. Thumbnails can’t be reused and can be only
|
||||
/// uploaded as a new file, with [`InputFile::File`]
|
||||
///
|
||||
/// [`InputFile::File`]: crate::types::InputFile::File
|
||||
pub thumb: Option<InputFile>,
|
||||
/// Animation caption, `0`-`1024` characters
|
||||
pub caption: Option<String>,
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show
|
||||
/// [bold, italic, fixed-width text or inline URLs] in the media caption.
|
||||
///
|
||||
/// [Markdown]: crate::types::ParseMode::Markdown
|
||||
/// [HTML]: crate::types::ParseMode::HTML
|
||||
/// [bold, italic, fixed-width text or inline URLs]: crate::types::ParseMode
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
/// Sends the message silently. Users will receive a notification with no
|
||||
/// sound.
|
||||
pub disable_notification: Option<bool>,
|
||||
/// If the message is a reply, [id] of the original message
|
||||
///
|
||||
/// [id]: crate::types::Message::id
|
||||
pub reply_to_message_id: Option<i32>,
|
||||
/// Additional interface options
|
||||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl Method for SendAnimation {
|
||||
type Output = Message;
|
||||
|
||||
const METHOD: &'static str = "sendAnimation";
|
||||
}
|
||||
|
||||
impl multipart::Payload for SendAnimation {
|
||||
fn payload(&self) -> Form {
|
||||
FormBuilder::new()
|
||||
.add("chat_id", &self.chat_id)
|
||||
.add("animation", &self.animation)
|
||||
.add("duration", &self.duration)
|
||||
.add("width", &self.width)
|
||||
.add("height", &self.height)
|
||||
.add("thumb", &self.thumb)
|
||||
.add("caption", &self.caption)
|
||||
.add("parse_mode", &self.parse_mode)
|
||||
.add("disable_notification", &self.disable_notification)
|
||||
.add("reply_to_message_id", &self.reply_to_message_id)
|
||||
.add("reply_markup", &self.reply_markup)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl dynamic::Payload for SendAnimation {
|
||||
fn kind(&self) -> dynamic::Kind {
|
||||
dynamic::Kind::Multipart(multipart::Payload::payload(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl SendAnimation {
|
||||
pub fn new<C>(chat_id: C, animation: InputFile) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
{
|
||||
Self {
|
||||
chat_id: chat_id.into(),
|
||||
animation,
|
||||
duration: None,
|
||||
width: None,
|
||||
height: None,
|
||||
thumb: None,
|
||||
caption: None,
|
||||
parse_mode: None,
|
||||
disable_notification: None,
|
||||
reply_to_message_id: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl multipart::Request<'_, SendAnimation> {
|
||||
pub fn chat_id<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.payload.chat_id = value.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn duration(mut self, value: u32) -> Self {
|
||||
self.payload.duration = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn width(mut self, value: u32) -> Self {
|
||||
self.payload.width = Some(value);
|
||||
self
|
||||
}
|
||||
pub fn height(mut self, value: u32) -> Self {
|
||||
self.payload.height = Some(value);
|
||||
self
|
||||
}
|
||||
pub fn thumb(mut self, value: InputFile) -> Self {
|
||||
self.payload.thumb = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn caption<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.payload.caption = Some(value.into());
|
||||
self
|
||||
}
|
||||
pub fn parse_mode(mut self, value: ParseMode) -> Self {
|
||||
self.payload.parse_mode = Some(value);
|
||||
self
|
||||
}
|
||||
pub fn disable_notification(mut self, value: bool) -> Self {
|
||||
self.payload.disable_notification = Some(value);
|
||||
self
|
||||
}
|
||||
pub fn reply_to_message_id(mut self, value: i32) -> Self {
|
||||
self.payload.reply_to_message_id = Some(value);
|
||||
self
|
||||
}
|
||||
pub fn reply_markup<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ReplyMarkup>,
|
||||
{
|
||||
self.payload.reply_markup = Some(value.into());
|
||||
self
|
||||
}
|
||||
}
|
115
src/requests/payloads/send_message.rs
Normal file
115
src/requests/payloads/send_message.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use crate::{
|
||||
requests::{ResponseResult, json, Method, dynamic},
|
||||
types::{ChatId, Message, ParseMode, ReplyMarkup},
|
||||
};
|
||||
|
||||
/// Use this method to send text messages.
|
||||
///
|
||||
/// On success, the sent [`Message`] is returned.
|
||||
///
|
||||
/// [`Message`]: crate::types::Message
|
||||
#[serde_with_macros::skip_serializing_none]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
|
||||
pub struct SendMessage {
|
||||
/// Unique identifier for the target chat or username of the target channel
|
||||
/// (in the format `@channelusername`)
|
||||
pub chat_id: ChatId,
|
||||
/// Text of the message to be sent
|
||||
pub text: String,
|
||||
/// Send [Markdown] or [HTML], if you want Telegram apps to show
|
||||
/// [bold, italic, fixed-width text or inline URLs] in your bot's message.
|
||||
///
|
||||
/// [Markdown]: crate::types::ParseMode::Markdown
|
||||
/// [HTML]: crate::types::ParseMode::HTML
|
||||
/// [bold, italic, fixed-width text or inline URLs]: crate::types::ParseMode
|
||||
pub parse_mode: Option<ParseMode>,
|
||||
/// Disables link previews for links in this message
|
||||
pub disable_web_page_preview: Option<bool>,
|
||||
/// Sends the message silently.
|
||||
/// Users will receive a notification with no sound.
|
||||
pub disable_notification: Option<bool>,
|
||||
/// If the message is a reply, [id] of the original message
|
||||
///
|
||||
/// [id]: crate::types::Message::id
|
||||
pub reply_to_message_id: Option<i32>,
|
||||
/// Additional interface options.
|
||||
pub reply_markup: Option<ReplyMarkup>,
|
||||
}
|
||||
|
||||
impl Method for SendMessage {
|
||||
type Output = Message;
|
||||
|
||||
const METHOD: &'static str = "sendMessage";
|
||||
}
|
||||
|
||||
impl json::Payload for SendMessage {}
|
||||
|
||||
impl dynamic::Payload for SendMessage {
|
||||
fn kind(&self) -> dynamic::Kind {
|
||||
dynamic::Kind::Json(serde_json::to_string(self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl SendMessage {
|
||||
pub fn new<C, S>(chat_id: C, text: S) -> Self
|
||||
where
|
||||
C: Into<ChatId>,
|
||||
S: Into<String>, // TODO: into?
|
||||
{
|
||||
SendMessage {
|
||||
chat_id: chat_id.into(),
|
||||
text: text.into(),
|
||||
parse_mode: None,
|
||||
disable_web_page_preview: None,
|
||||
disable_notification: None,
|
||||
reply_to_message_id: None,
|
||||
reply_markup: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl json::Request<'_, SendMessage> {
|
||||
pub fn chat_id<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ChatId>,
|
||||
{
|
||||
self.payload.chat_id = value.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn text<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<String>, // TODO: into?
|
||||
{
|
||||
self.payload.text = value.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parse_mode(mut self, value: ParseMode) -> Self {
|
||||
self.payload.parse_mode = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disable_web_page_preview(mut self, value: bool) -> Self {
|
||||
self.payload.disable_web_page_preview = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn disable_notification(mut self, value: bool) -> Self {
|
||||
self.payload.disable_notification = Some(value.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reply_to_message_id(mut self, value: i32) -> Self {
|
||||
self.payload.reply_to_message_id = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reply_markup<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<ReplyMarkup>,
|
||||
{
|
||||
self.payload.reply_markup = Some(value.into());
|
||||
self
|
||||
}
|
||||
}
|
|
@ -9,7 +9,9 @@ use std::marker::PhantomData;
|
|||
///
|
||||
/// NOTE: Currently where is only one request without params - [GetMe]
|
||||
///
|
||||
/// [GetMe]: // TODO
|
||||
/// See [GetMe] for reference implementation.
|
||||
///
|
||||
/// [GetMe]: crate::requests::payloads::GetMe
|
||||
#[must_use = "requests do nothing until sent"]
|
||||
pub struct Request<'b, M> {
|
||||
bot: &'b Bot,
|
||||
|
|
Loading…
Add table
Reference in a new issue