mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
Merge pull request #2 from teloxide/unstrict_get_updates
add `GetUpdatesNonStrict` - fail proof version of `GetUpdates`
This commit is contained in:
commit
0a397d8900
8 changed files with 175 additions and 13 deletions
|
@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `client_from_env` was moved from `teloxide::utils` to crate root of `teloxide-core`
|
||||
- To simplify `GetUpdates` request it was changed to simply return `Vec<Update>`
|
||||
(instead of `Vec<Result<Update, (Value, serde_json::Error)>>`)
|
||||
- `GetUpdatesNonStrict` 'telegram' method, that behaves just like `GetUpdates` but doesn't
|
||||
fail if one of updates fails to be deserialized
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@ use crate::{
|
|||
EditInlineMessageText, EditMessageCaption, EditMessageLiveLocation, EditMessageMedia,
|
||||
EditMessageReplyMarkup, EditMessageText, ExportChatInviteLink, ForwardMessage, GetChat,
|
||||
GetChatAdministrators, GetChatMember, GetChatMembersCount, GetFile, GetGameHighScores,
|
||||
GetMe, GetMyCommands, GetStickerSet, GetUpdates, GetUserProfilePhotos, GetWebhookInfo,
|
||||
KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember, RestrictChatMember,
|
||||
SendAnimation, SendAudio, SendChatAction, SendChatActionKind, SendContact, SendDice,
|
||||
SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
|
||||
SendPoll, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice,
|
||||
SetChatAdministratorCustomTitle, SetChatDescription, SetChatPermissions, SetChatPhoto,
|
||||
SetChatStickerSet, SetChatTitle, SetGameScore, SetMyCommands, SetStickerPositionInSet,
|
||||
SetStickerSetThumb, SetWebhook, StopInlineMessageLiveLocation, StopMessageLiveLocation,
|
||||
StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile,
|
||||
GetMe, GetMyCommands, GetStickerSet, GetUpdates, GetUpdatesNonStrict, GetUserProfilePhotos,
|
||||
GetWebhookInfo, KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember,
|
||||
RestrictChatMember, SendAnimation, SendAudio, SendChatAction, SendChatActionKind,
|
||||
SendContact, SendDice, SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup,
|
||||
SendMessage, SendPhoto, SendPoll, SendSticker, SendVenue, SendVideo, SendVideoNote,
|
||||
SendVoice, SetChatAdministratorCustomTitle, SetChatDescription, SetChatPermissions,
|
||||
SetChatPhoto, SetChatStickerSet, SetChatTitle, SetGameScore, SetMyCommands,
|
||||
SetStickerPositionInSet, SetStickerSetThumb, SetWebhook, StopInlineMessageLiveLocation,
|
||||
StopMessageLiveLocation, StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile,
|
||||
},
|
||||
types::{
|
||||
BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia,
|
||||
|
@ -39,6 +39,18 @@ impl Bot {
|
|||
GetUpdates::new(self.clone())
|
||||
}
|
||||
|
||||
/// This is non strict version of [`get_updates`], this means that if it
|
||||
/// will fail to deserialize some updates, it won't fail entirely, but
|
||||
/// will just return some errors.
|
||||
///
|
||||
/// Note: this is not a 'real' telegram method, this is simply
|
||||
/// [`get_updates`] with changed return type.
|
||||
///
|
||||
/// [`get_updates`]: crate::Bot::get_updates
|
||||
pub fn get_updates_non_strict(&self) -> GetUpdatesNonStrict {
|
||||
GetUpdatesNonStrict::new(self.clone())
|
||||
}
|
||||
|
||||
/// Use this method to specify a url and receive incoming updates via an
|
||||
/// outgoing webhook.
|
||||
///
|
||||
|
|
|
@ -21,15 +21,13 @@ use crate::{
|
|||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct GetUpdates {
|
||||
#[serde(skip_serializing)]
|
||||
bot: Bot,
|
||||
pub(crate) bot: Bot,
|
||||
pub(crate) offset: Option<i32>,
|
||||
pub(crate) limit: Option<u8>,
|
||||
pub(crate) timeout: Option<u32>,
|
||||
pub(crate) allowed_updates: Option<Vec<AllowedUpdate>>,
|
||||
}
|
||||
|
||||
// TODO: Add version of this method that will ignore unparsed updates,
|
||||
// to be bullet proof
|
||||
#[async_trait::async_trait]
|
||||
impl Request for GetUpdates {
|
||||
type Output = Vec<Update>;
|
||||
|
|
97
src/requests/all/get_updates_non_strict.rs
Normal file
97
src/requests/all/get_updates_non_strict.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
net,
|
||||
requests::{GetUpdates, Request, ResponseResult},
|
||||
types::{AllowedUpdate, NonStrictVec, Update},
|
||||
Bot,
|
||||
};
|
||||
|
||||
/// This is non strict version of [`GetUpdates`], this means that if it will
|
||||
/// fail to deserialize some updates, it won't fail entirely, but will just
|
||||
/// return some errors.
|
||||
///
|
||||
/// Note: this is not a 'real' telegram method, this is simply [`GetUpdates`]
|
||||
/// with changed return type.
|
||||
///
|
||||
/// [`GetUpdates`]: crate::requests::GetUpdates
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct GetUpdatesNonStrict(pub GetUpdates);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Request for GetUpdatesNonStrict {
|
||||
type Output = NonStrictVec<Update>;
|
||||
|
||||
async fn send(&self) -> ResponseResult<Self::Output> {
|
||||
net::request_json(self.0.bot.client(), self.0.bot.token(), "getUpdates", &self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl GetUpdatesNonStrict {
|
||||
pub(crate) fn new(bot: Bot) -> Self {
|
||||
Self(GetUpdates::new(bot))
|
||||
}
|
||||
|
||||
/// 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 fn offset(mut self, value: i32) -> Self {
|
||||
self.0.offset = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Limits the number of updates to be retrieved.
|
||||
///
|
||||
/// Values between `1`—`100` are accepted. Defaults to `100`.
|
||||
pub fn limit(mut self, value: u8) -> Self {
|
||||
self.0.limit = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// 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 fn timeout(mut self, value: u32) -> Self {
|
||||
self.0.timeout = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// [`Bot::get_updates`], 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
|
||||
/// [`Bot::get_updates`]: crate::Bot::get_updates
|
||||
pub fn allowed_updates<T>(mut self, value: T) -> Self
|
||||
where
|
||||
T: Into<Vec<AllowedUpdate>>,
|
||||
{
|
||||
self.0.allowed_updates = Some(value.into());
|
||||
self
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ mod get_me;
|
|||
mod get_my_commands;
|
||||
mod get_sticker_set;
|
||||
mod get_updates;
|
||||
mod get_updates_non_strict;
|
||||
mod get_user_profile_photos;
|
||||
mod get_webhook_info;
|
||||
mod kick_chat_member;
|
||||
|
@ -107,6 +108,7 @@ pub use get_me::*;
|
|||
pub use get_my_commands::*;
|
||||
pub use get_sticker_set::*;
|
||||
pub use get_updates::*;
|
||||
pub use get_updates_non_strict::*;
|
||||
pub use get_user_profile_photos::*;
|
||||
pub use get_webhook_info::*;
|
||||
pub use kick_chat_member::*;
|
||||
|
|
|
@ -266,7 +266,7 @@ impl<'de> serde::de::Visitor<'de> for PrivateChatKindVisitor {
|
|||
write!(f, r#"field equal to "private""#)
|
||||
}
|
||||
|
||||
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
|
||||
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
match v {
|
||||
"private" => Ok(()),
|
||||
_ => Err(E::invalid_value(serde::de::Unexpected::Str(v), &r#""private""#)),
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub use country_code::*;
|
||||
pub use currency::*;
|
||||
pub use mime_wrapper::*;
|
||||
pub use non_strict_vec::*;
|
||||
|
||||
mod country_code;
|
||||
mod currency;
|
||||
mod mime_wrapper;
|
||||
mod non_strict_vec;
|
||||
|
|
49
src/types/non_telegram_types/non_strict_vec.rs
Normal file
49
src/types/non_telegram_types/non_strict_vec.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde_json::{from_value, Value};
|
||||
|
||||
/// Similar to `Vec<T>` but if it fails to deserialize element, it just saves
|
||||
/// `Err((value, err))`
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
#[serde(from = "Vec<serde_json::Value>")]
|
||||
#[serde(bound = "T: DeserializeOwned")]
|
||||
pub struct NonStrictVec<T>(pub Vec<Result<T, (serde_json::Value, serde_json::Error)>>);
|
||||
|
||||
impl<T: DeserializeOwned> From<Vec<serde_json::Value>> for NonStrictVec<T> {
|
||||
fn from(vec: Vec<Value>) -> Self {
|
||||
Self(vec.into_iter().map(|val| from_value(val.clone()).map_err(|e| (val, e))).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::types::Update;
|
||||
|
||||
let x: NonStrictVec<Update> = serde_json::from_str(
|
||||
r#"[{
|
||||
"update_id": 923808447,
|
||||
"message": {
|
||||
"message_id": 361678,
|
||||
"from": {
|
||||
"id": 218485655,
|
||||
"is_bot": false,
|
||||
"first_name": "вафель",
|
||||
"last_name": "🧇",
|
||||
"username": "WaffleLapkin",
|
||||
"language_code": "en"
|
||||
},
|
||||
"chat": {
|
||||
"id": 218485655,
|
||||
"first_name": "вафель",
|
||||
"last_name": "🧇",
|
||||
"username": "WaffleLapkin",
|
||||
"type": "private"
|
||||
},
|
||||
"date": 1595860067,
|
||||
"text": "s"
|
||||
}
|
||||
}]"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(x.0.first().unwrap().is_ok())
|
||||
}
|
Loading…
Add table
Reference in a new issue