From 552425d3b5342b5ecbd115d98bf6bda8d7861948 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Mon, 9 Sep 2024 16:32:46 +0200 Subject: [PATCH 1/6] refactor: improve module structure This also improves the documentation of the crate as there are no internal re-exports anymore and everything has a dedicated path. BREAKING CHANGES: - There should now be only a single path to import a specific object. - HttpError is integrated into the Error enum variant --- examples/api_trait_implementation.rs | 58 ++---- examples/async_custom_client.rs | 3 +- examples/async_file_upload.rs | 5 +- examples/async_get_me.rs | 3 +- examples/async_reply_to_message_updates.rs | 9 +- examples/custom_client.rs | 3 +- examples/get_me.rs | 3 +- examples/inline_keyboard.rs | 9 +- examples/reply_keyboard.rs | 9 +- examples/reply_to_message_updates.rs | 8 +- src/api.rs | 33 +--- src/api/async_telegram_api_impl.rs | 76 ++------ src/api/telegram_api_impl.rs | 139 ++++----------- src/api_traits.rs | 43 +---- src/api_traits/async_telegram_api.rs | 198 +++++---------------- src/api_traits/telegram_api.rs | 198 +++++---------------- src/error.rs | 47 +++++ src/lib.rs | 35 ++-- src/objects.rs | 8 +- src/{api_params.rs => parameters.rs} | 39 ++-- src/parse_mode.rs | 7 +- src/response.rs | 41 +++++ 22 files changed, 320 insertions(+), 654 deletions(-) create mode 100644 src/error.rs rename src/{api_params.rs => parameters.rs} (98%) create mode 100644 src/response.rs diff --git a/examples/api_trait_implementation.rs b/examples/api_trait_implementation.rs index 853f4f8..f477a20 100644 --- a/examples/api_trait_implementation.rs +++ b/examples/api_trait_implementation.rs @@ -1,7 +1,8 @@ -use frankenstein::ErrorResponse; -use frankenstein::SendMessageParams; +use frankenstein::parameters::SendMessageParams; +use frankenstein::response::ErrorResponse; use frankenstein::TelegramApi; -use isahc::{prelude::*, Request}; +use isahc::prelude::*; +use isahc::Request; use std::path::PathBuf; static TOKEN: &str = "TOKEN"; @@ -14,16 +15,10 @@ pub struct Api { #[derive(Debug)] pub enum Error { - HttpError(HttpError), + HttpError { code: u16, message: String }, ApiError(ErrorResponse), } -#[derive(Debug)] -pub struct HttpError { - pub code: u16, - pub message: String, -} - impl Api { #[must_use] pub fn new(api_key: &str) -> Self { @@ -40,24 +35,14 @@ impl Api { impl From for Error { fn from(error: isahc::http::Error) -> Self { let message = format!("{error:?}"); - let error = HttpError { code: 500, message }; - Self::HttpError(error) - } -} - -impl From for Error { - fn from(error: std::io::Error) -> Self { - let message = format!("{error:?}"); - let error = HttpError { code: 500, message }; - Self::HttpError(error) + Self::HttpError { code: 500, message } } } impl From for Error { fn from(error: isahc::Error) -> Self { let message = format!("{error:?}"); - let error = HttpError { code: 500, message }; - Self::HttpError(error) + Self::HttpError { code: 500, message } } } @@ -81,21 +66,18 @@ impl TelegramApi for Api { } }; - let text = response.text()?; + let text = response.text().map_err(|error| { + let message = error.to_string(); + Error::HttpError { code: 500, message } + })?; let parsed_result: Result = serde_json::from_str(&text); - parsed_result.map_err(|_| { - let parsed_error: Result = - serde_json::from_str(&text); - - match parsed_error { - Ok(result) => Error::ApiError(result), - Err(error) => { - let message = format!("{error:?}"); - let error = HttpError { code: 500, message }; - Error::HttpError(error) - } + parsed_result.map_err(|_| match serde_json::from_str::(&text) { + Ok(result) => Error::ApiError(result), + Err(error) => { + let message = format!("{error:?}"); + Error::HttpError { code: 500, message } } }) } @@ -108,12 +90,8 @@ impl TelegramApi for Api { _params: T1, _files: Vec<(&str, PathBuf)>, ) -> Result { - let error = HttpError { - code: 500, - message: "isahc doesn't support form data requests".to_string(), - }; - - Err(Error::HttpError(error)) + let message = "isahc doesn't support form data requests".to_string(); + Err(Error::HttpError { code: 500, message }) } } diff --git a/examples/async_custom_client.rs b/examples/async_custom_client.rs index fd1ecfc..73e6680 100644 --- a/examples/async_custom_client.rs +++ b/examples/async_custom_client.rs @@ -1,5 +1,4 @@ -use frankenstein::AsyncApi; -use frankenstein::AsyncTelegramApi; +use frankenstein::{AsyncApi, AsyncTelegramApi}; use std::time::Duration; static TOKEN: &str = "API_TOKEN"; diff --git a/examples/async_file_upload.rs b/examples/async_file_upload.rs index 2d7bee9..5751820 100644 --- a/examples/async_file_upload.rs +++ b/examples/async_file_upload.rs @@ -1,6 +1,5 @@ -use frankenstein::api_params::SendPhotoParams; -use frankenstein::AsyncApi; -use frankenstein::AsyncTelegramApi; +use frankenstein::parameters::SendPhotoParams; +use frankenstein::{AsyncApi, AsyncTelegramApi}; static TOKEN: &str = "TOKEN"; static CHAT_ID: i64 = 1; diff --git a/examples/async_get_me.rs b/examples/async_get_me.rs index 6a69d06..ef0e104 100644 --- a/examples/async_get_me.rs +++ b/examples/async_get_me.rs @@ -1,5 +1,4 @@ -use frankenstein::AsyncApi; -use frankenstein::AsyncTelegramApi; +use frankenstein::{AsyncApi, AsyncTelegramApi}; static TOKEN: &str = "API_TOKEN"; diff --git a/examples/async_reply_to_message_updates.rs b/examples/async_reply_to_message_updates.rs index a2e1827..ed5114f 100644 --- a/examples/async_reply_to_message_updates.rs +++ b/examples/async_reply_to_message_updates.rs @@ -1,9 +1,6 @@ -use frankenstein::AsyncTelegramApi; -use frankenstein::GetUpdatesParams; -use frankenstein::Message; -use frankenstein::ReplyParameters; -use frankenstein::SendMessageParams; -use frankenstein::{AsyncApi, UpdateContent}; +use frankenstein::objects::{Message, UpdateContent}; +use frankenstein::parameters::{GetUpdatesParams, ReplyParameters, SendMessageParams}; +use frankenstein::{AsyncApi, AsyncTelegramApi}; static TOKEN: &str = "API_TOKEN"; diff --git a/examples/custom_client.rs b/examples/custom_client.rs index 4a6b462..a586042 100644 --- a/examples/custom_client.rs +++ b/examples/custom_client.rs @@ -1,5 +1,4 @@ -use frankenstein::Api; -use frankenstein::TelegramApi; +use frankenstein::{Api, TelegramApi}; use std::time::Duration; static TOKEN: &str = "API_TOKEN"; diff --git a/examples/get_me.rs b/examples/get_me.rs index 1ca279f..7ce6198 100644 --- a/examples/get_me.rs +++ b/examples/get_me.rs @@ -1,5 +1,4 @@ -use frankenstein::Api; -use frankenstein::TelegramApi; +use frankenstein::{Api, TelegramApi}; static TOKEN: &str = "API_TOKEN"; diff --git a/examples/inline_keyboard.rs b/examples/inline_keyboard.rs index 7dae94f..86ea0bc 100644 --- a/examples/inline_keyboard.rs +++ b/examples/inline_keyboard.rs @@ -1,9 +1,6 @@ -use frankenstein::Api; -use frankenstein::InlineKeyboardButton; -use frankenstein::InlineKeyboardMarkup; -use frankenstein::ReplyMarkup; -use frankenstein::SendMessageParams; -use frankenstein::TelegramApi; +use frankenstein::objects::{InlineKeyboardButton, InlineKeyboardMarkup}; +use frankenstein::parameters::{ReplyMarkup, SendMessageParams}; +use frankenstein::{Api, TelegramApi}; // replace with your token static TOKEN: &str = "TOKEN"; diff --git a/examples/reply_keyboard.rs b/examples/reply_keyboard.rs index 9780a7f..625a485 100644 --- a/examples/reply_keyboard.rs +++ b/examples/reply_keyboard.rs @@ -1,9 +1,6 @@ -use frankenstein::Api; -use frankenstein::KeyboardButton; -use frankenstein::ReplyKeyboardMarkup; -use frankenstein::ReplyMarkup; -use frankenstein::SendMessageParams; -use frankenstein::TelegramApi; +use frankenstein::objects::{KeyboardButton, ReplyKeyboardMarkup}; +use frankenstein::parameters::{ReplyMarkup, SendMessageParams}; +use frankenstein::{Api, TelegramApi}; // replace with your token static TOKEN: &str = "TOKEN"; diff --git a/examples/reply_to_message_updates.rs b/examples/reply_to_message_updates.rs index 2c13873..e79f55d 100644 --- a/examples/reply_to_message_updates.rs +++ b/examples/reply_to_message_updates.rs @@ -1,8 +1,6 @@ -use frankenstein::GetUpdatesParams; -use frankenstein::ReplyParameters; -use frankenstein::SendMessageParams; -use frankenstein::TelegramApi; -use frankenstein::{Api, UpdateContent}; +use frankenstein::objects::UpdateContent; +use frankenstein::parameters::{GetUpdatesParams, ReplyParameters, SendMessageParams}; +use frankenstein::{Api, TelegramApi}; static TOKEN: &str = "API_TOKEN"; diff --git a/src/api.rs b/src/api.rs index 90f2c05..951461a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,34 +1,9 @@ -use crate::api_traits::ErrorResponse; -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "async-http-client")] -pub mod async_telegram_api_impl; #[cfg(feature = "async-http-client")] pub use async_telegram_api_impl::*; - -#[cfg(feature = "http-client")] -pub mod telegram_api_impl; #[cfg(feature = "http-client")] pub use telegram_api_impl::*; -pub static BASE_API_URL: &str = "https://api.telegram.org/bot"; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, thiserror::Error)] -#[serde(untagged)] -pub enum Error { - #[error("{0}")] - Http(HttpError), - #[error("Api Error {0:?}")] - Api(ErrorResponse), - #[error("Decode Error {0}")] - Decode(String), - #[error("Encode Error {0}")] - Encode(String), -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, thiserror::Error)] -#[error("Http Error {code}: {message}")] -pub struct HttpError { - pub code: u16, - pub message: String, -} +#[cfg(feature = "async-http-client")] +mod async_telegram_api_impl; +#[cfg(feature = "http-client")] +mod telegram_api_impl; diff --git a/src/api/async_telegram_api_impl.rs b/src/api/async_telegram_api_impl.rs index 501df7f..a8431a8 100644 --- a/src/api/async_telegram_api_impl.rs +++ b/src/api/async_telegram_api_impl.rs @@ -1,7 +1,5 @@ -use super::Error; -use super::HttpError; use crate::api_traits::AsyncTelegramApi; -use crate::api_traits::ErrorResponse; +use crate::error::Error; use async_trait::async_trait; use reqwest::multipart; use serde_json::Value; @@ -24,7 +22,7 @@ pub struct AsyncApi { impl AsyncApi { /// Create a new `AsyncApi`. You can use [`AsyncApi::new_url`] or [`AsyncApi::builder`] for more options. pub fn new(api_key: &str) -> Self { - Self::new_url(format!("{}{api_key}", super::BASE_API_URL)) + Self::new_url(format!("{}{api_key}", crate::BASE_API_URL)) } /// Create a new `AsyncApi`. You can use [`AsyncApi::builder`] for more options. @@ -45,51 +43,17 @@ impl AsyncApi { match response.text().await { Ok(message) => { if status_code == 200 { - let success_response: T = Self::parse_json(&message)?; - return Ok(success_response); + Ok(Self::parse_json(&message)?) + } else { + Err(Error::Api(Self::parse_json(&message)?)) } - - let error_response: ErrorResponse = Self::parse_json(&message)?; - Err(Error::Api(error_response)) - } - Err(e) => { - let err = Error::Decode(format!("Failed to decode response: {e:?}")); - Err(err) } + Err(error) => Err(Error::Decode(error.to_string())), } } fn parse_json(body: &str) -> Result { - let json_result: Result = serde_json::from_str(body); - - match json_result { - Ok(result) => Ok(result), - - Err(e) => { - let err = Error::Decode(format!("{e:?} : {body:?}")); - Err(err) - } - } - } -} - -impl From for Error { - fn from(error: reqwest::Error) -> Self { - let message = error.to_string(); - let code = error - .status() - .map_or(500, |status_code| status_code.as_u16()); - - let error = HttpError { code, message }; - Self::Http(error) - } -} - -impl From for Error { - fn from(error: std::io::Error) -> Self { - let message = error.to_string(); - - Self::Encode(message) + serde_json::from_str(body).map_err(|e| Error::Decode(format!("{e:?} : {body:?}"))) } } @@ -162,8 +126,9 @@ impl AsyncTelegramApi for AsyncApi { } for (parameter_name, file_path, file_name) in files_with_paths { - let file = File::open(file_path).await?; - + let file = File::open(file_path) + .await + .map_err(|error| Error::Encode(error.to_string()))?; let part = multipart::Part::stream(file).file_name(file_name); form = form.part(parameter_name, part); } @@ -179,10 +144,8 @@ impl AsyncTelegramApi for AsyncApi { #[cfg(test)] mod async_tests { - use super::AsyncApi; - use super::Error; - use crate::api_params::SendMessageParams; - use crate::api_traits::ErrorResponse; + use super::*; + use crate::parameters::SendMessageParams; use crate::AsyncTelegramApi; #[tokio::test] @@ -224,16 +187,13 @@ mod async_tests { .await; let api = AsyncApi::new_url(server.url()); - if let Err(Error::Api(ErrorResponse { - ok: false, - description, - error_code: 400, - parameters: None, - })) = api.send_message(¶ms).await - { - assert_eq!("Bad Request: chat not found".to_string(), description); + if let Err(Error::Api(error)) = dbg!(api.send_message(¶ms).await) { + assert_eq!(error.description, "Bad Request: chat not found"); + assert_eq!(error.error_code, 400); + assert_eq!(error.parameters, None); + assert!(!error.ok); } else { - panic!("Error was expected but there is none"); + panic!("API Error expected"); } } } diff --git a/src/api/telegram_api_impl.rs b/src/api/telegram_api_impl.rs index a1c2151..0fe1bc8 100644 --- a/src/api/telegram_api_impl.rs +++ b/src/api/telegram_api_impl.rs @@ -1,6 +1,5 @@ -use super::Error; -use super::HttpError; use crate::api_traits::TelegramApi; +use crate::error::Error; use multipart::client::lazy::Multipart; use serde_json::Value; use std::path::PathBuf; @@ -20,7 +19,7 @@ pub struct Api { impl Api { /// Create a new `Api`. You can use [`Api::new_url`] or [`Api::builder`] for more options. pub fn new(api_key: &str) -> Self { - Self::new_url(format!("{}{api_key}", super::BASE_API_URL)) + Self::new_url(format!("{}{api_key}", crate::BASE_API_URL)) } /// Create a new `Api`. You can use [`Api::builder`] for more options. @@ -55,27 +54,6 @@ impl Api { } } -impl From for Error { - fn from(error: ureq::Error) -> Self { - match error { - ureq::Error::Status(code, response) => match response.into_string() { - Ok(message) => match serde_json::from_str(&message) { - Ok(json_result) => Self::Api(json_result), - Err(_) => Self::Http(HttpError { code, message }), - }, - Err(_) => Self::Http(HttpError { - code, - message: "Failed to decode response".to_string(), - }), - }, - ureq::Error::Transport(transport_error) => Self::Http(HttpError { - message: format!("{transport_error:?}"), - code: 500, - }), - } - } -} - impl TelegramApi for Api { type Error = Error; @@ -163,81 +141,29 @@ impl TelegramApi for Api { #[cfg(test)] mod tests { use super::*; - use crate::api_params::AnswerCallbackQueryParams; - use crate::api_params::AnswerInlineQueryParams; - use crate::api_params::BanChatMemberParams; - use crate::api_params::BotCommandScope; - use crate::api_params::BotCommandScopeChat; - use crate::api_params::ChatAction; - use crate::api_params::ChatId; - use crate::api_params::CopyMessageParams; - use crate::api_params::CreateChatInviteLinkParams; - use crate::api_params::DeleteChatPhotoParams; - use crate::api_params::DeleteChatStickerSetParams; - use crate::api_params::DeleteMessageParams; - use crate::api_params::DeleteMyCommandsParams; - use crate::api_params::DeleteWebhookParams; - use crate::api_params::EditChatInviteLinkParams; - use crate::api_params::EditMessageCaptionParams; - use crate::api_params::EditMessageLiveLocationParams; - use crate::api_params::EditMessageMediaParams; - use crate::api_params::EditMessageTextParams; - use crate::api_params::ExportChatInviteLinkParams; - use crate::api_params::FileUpload; - use crate::api_params::ForwardMessageParams; - use crate::api_params::GetChatAdministratorsParams; - use crate::api_params::GetChatMemberCountParams; - use crate::api_params::GetChatMemberParams; - use crate::api_params::GetChatParams; - use crate::api_params::GetFileParams; - use crate::api_params::GetMyCommandsParams; - use crate::api_params::GetStickerSetParams; - use crate::api_params::GetUpdatesParams; - use crate::api_params::GetUserProfilePhotosParams; - use crate::api_params::InlineQueryResult; - use crate::api_params::InputFile; - use crate::api_params::InputMedia; - use crate::api_params::InputMediaPhoto; - use crate::api_params::LeaveChatParams; - use crate::api_params::Media; - use crate::api_params::PinChatMessageParams; - use crate::api_params::PromoteChatMemberParams; - use crate::api_params::RestrictChatMemberParams; - use crate::api_params::RevokeChatInviteLinkParams; - use crate::api_params::SendAnimationParams; - use crate::api_params::SendAudioParams; - use crate::api_params::SendChatActionParams; - use crate::api_params::SendContactParams; - use crate::api_params::SendDiceParams; - use crate::api_params::SendDocumentParams; - use crate::api_params::SendLocationParams; - use crate::api_params::SendMediaGroupParams; - use crate::api_params::SendMessageParams; - use crate::api_params::SendPhotoParams; - use crate::api_params::SendPollParams; - use crate::api_params::SendStickerParams; - use crate::api_params::SendVenueParams; - use crate::api_params::SendVideoNoteParams; - use crate::api_params::SendVideoParams; - use crate::api_params::SendVoiceParams; - use crate::api_params::SetChatAdministratorCustomTitleParams; - use crate::api_params::SetChatDescriptionParams; - use crate::api_params::SetChatPermissionsParams; - use crate::api_params::SetChatPhotoParams; - use crate::api_params::SetChatStickerSetParams; - use crate::api_params::SetChatTitleParams; - use crate::api_params::SetMyCommandsParams; - use crate::api_params::SetWebhookParams; - use crate::api_params::StopMessageLiveLocationParams; - use crate::api_params::StopPollParams; - use crate::api_params::UnbanChatMemberParams; - use crate::api_params::UnpinChatMessageParams; - use crate::api_traits::ErrorResponse; - use crate::objects::BotCommand; - use crate::objects::ChatPermissions; - use crate::objects::InlineQueryResultVenue; - use crate::objects::InputPollOption; - use crate::AllowedUpdate; + use crate::objects::{ + AllowedUpdate, BotCommand, ChatPermissions, InlineQueryResultVenue, InputPollOption, + }; + use crate::parameters::{ + AnswerCallbackQueryParams, AnswerInlineQueryParams, BanChatMemberParams, BotCommandScope, + BotCommandScopeChat, ChatAction, ChatId, CopyMessageParams, CreateChatInviteLinkParams, + DeleteChatPhotoParams, DeleteChatStickerSetParams, DeleteMessageParams, + DeleteMyCommandsParams, DeleteWebhookParams, EditChatInviteLinkParams, + EditMessageCaptionParams, EditMessageLiveLocationParams, EditMessageMediaParams, + EditMessageTextParams, ExportChatInviteLinkParams, FileUpload, ForwardMessageParams, + GetChatAdministratorsParams, GetChatMemberCountParams, GetChatMemberParams, GetChatParams, + GetFileParams, GetMyCommandsParams, GetStickerSetParams, GetUpdatesParams, + GetUserProfilePhotosParams, InlineQueryResult, InputFile, InputMedia, InputMediaPhoto, + LeaveChatParams, Media, PinChatMessageParams, PromoteChatMemberParams, + RestrictChatMemberParams, RevokeChatInviteLinkParams, SendAnimationParams, SendAudioParams, + SendChatActionParams, SendContactParams, SendDiceParams, SendDocumentParams, + SendLocationParams, SendMediaGroupParams, SendMessageParams, SendPhotoParams, + SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, SendVideoParams, + SendVoiceParams, SetChatAdministratorCustomTitleParams, SetChatDescriptionParams, + SetChatPermissionsParams, SetChatPhotoParams, SetChatStickerSetParams, SetChatTitleParams, + SetMyCommandsParams, SetWebhookParams, StopMessageLiveLocationParams, StopPollParams, + UnbanChatMemberParams, UnpinChatMessageParams, + }; #[test] fn new_sets_correct_url() { @@ -310,16 +236,13 @@ mod tests { .create(); let api = Api::new_url(server.url()); - if let Err(Error::Api(ErrorResponse { - ok: false, - description, - error_code: 400, - parameters: None, - })) = api.send_message(¶ms) - { - assert_eq!("Bad Request: chat not found".to_string(), description); + if let Err(Error::Api(error)) = dbg!(api.send_message(¶ms)) { + assert_eq!(error.description, "Bad Request: chat not found"); + assert_eq!(error.error_code, 400); + assert_eq!(error.parameters, None); + assert!(!error.ok); } else { - panic!("Error was expected but there is none"); + panic!("API Error expected"); } } diff --git a/src/api_traits.rs b/src/api_traits.rs index fbc430e..2e512af 100644 --- a/src/api_traits.rs +++ b/src/api_traits.rs @@ -1,48 +1,9 @@ -use crate::objects::{Message, ResponseParameters}; -use serde::{Deserialize, Serialize}; - #[cfg(feature = "async-telegram-trait")] -pub mod async_telegram_api; - +mod async_telegram_api; #[cfg(feature = "telegram-trait")] -pub mod telegram_api; +mod telegram_api; #[cfg(feature = "async-telegram-trait")] pub use async_telegram_api::*; - #[cfg(feature = "telegram-trait")] pub use telegram_api::*; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -pub struct MethodResponse { - /// Always true - pub ok: bool, - pub result: T, - #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, -} - -/// Error on an unsuccessful request. -/// -/// `ok` equals false and the error is explained in the `description`. -/// An Integer `error_code` field is also returned, but its contents are subject to change in the future. -/// Some errors may also have an optional field `parameters` of the type `ResponseParameters`, which can help to automatically handle the error. -/// -/// See -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -pub struct ErrorResponse { - /// Always false - pub ok: bool, - pub description: String, - /// Contents are subject to change in the future - pub error_code: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub parameters: Option, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum EditMessageResponse { - Message(MethodResponse), - Bool(MethodResponse), -} diff --git a/src/api_traits/async_telegram_api.rs b/src/api_traits/async_telegram_api.rs index f72e1db..dbc77cd 100644 --- a/src/api_traits/async_telegram_api.rs +++ b/src/api_traits/async_telegram_api.rs @@ -1,154 +1,50 @@ -use super::EditMessageResponse; -use super::MethodResponse; -use crate::api_params::AddStickerToSetParams; -use crate::api_params::AnswerCallbackQueryParams; -use crate::api_params::AnswerInlineQueryParams; -use crate::api_params::AnswerPreCheckoutQueryParams; -use crate::api_params::AnswerShippingQueryParams; -use crate::api_params::AnswerWebAppQueryParams; -use crate::api_params::ApproveChatJoinRequestParams; -use crate::api_params::BanChatMemberParams; -use crate::api_params::BanChatSenderChatParams; -use crate::api_params::CloseForumTopicParams; -use crate::api_params::CloseGeneralForumTopicParams; -use crate::api_params::CopyMessageParams; -use crate::api_params::CopyMessagesParams; -use crate::api_params::CreateChatInviteLinkParams; -use crate::api_params::CreateChatSubscriptionInviteLinkParams; -use crate::api_params::CreateForumTopicParams; -use crate::api_params::CreateInvoiceLinkParams; -use crate::api_params::CreateNewStickerSetParams; -use crate::api_params::DeclineChatJoinRequestParams; -use crate::api_params::DeleteChatPhotoParams; -use crate::api_params::DeleteChatStickerSetParams; -use crate::api_params::DeleteForumTopicParams; -use crate::api_params::DeleteMessageParams; -use crate::api_params::DeleteMessagesParams; -use crate::api_params::DeleteMyCommandsParams; -use crate::api_params::DeleteStickerFromSetParams; -use crate::api_params::DeleteStickerSetParams; -use crate::api_params::DeleteWebhookParams; -use crate::api_params::EditChatInviteLinkParams; -use crate::api_params::EditChatSubscriptionInviteLinkParams; -use crate::api_params::EditForumTopicParams; -use crate::api_params::EditGeneralForumTopicParams; -use crate::api_params::EditMessageCaptionParams; -use crate::api_params::EditMessageLiveLocationParams; -use crate::api_params::EditMessageMediaParams; -use crate::api_params::EditMessageReplyMarkupParams; -use crate::api_params::EditMessageTextParams; -use crate::api_params::ExportChatInviteLinkParams; -use crate::api_params::FileUpload; -use crate::api_params::ForwardMessageParams; -use crate::api_params::ForwardMessagesParams; -use crate::api_params::GetBusinessConnectionParams; -use crate::api_params::GetChatAdministratorsParams; -use crate::api_params::GetChatMemberCountParams; -use crate::api_params::GetChatMemberParams; -use crate::api_params::GetChatMenuButtonParams; -use crate::api_params::GetChatParams; -use crate::api_params::GetCustomEmojiStickersParams; -use crate::api_params::GetFileParams; -use crate::api_params::GetGameHighScoresParams; -use crate::api_params::GetMyCommandsParams; -use crate::api_params::GetMyDefaultAdministratorRightsParams; -use crate::api_params::GetMyDescriptionParams; -use crate::api_params::GetMyNameParams; -use crate::api_params::GetMyShortDescriptionParams; -use crate::api_params::GetStarTransactionsParams; -use crate::api_params::GetStickerSetParams; -use crate::api_params::GetUpdatesParams; -use crate::api_params::GetUserChatBoostsParams; -use crate::api_params::GetUserProfilePhotosParams; -use crate::api_params::HideGeneralForumTopicParams; -use crate::api_params::InputMedia; -use crate::api_params::LeaveChatParams; -use crate::api_params::Media; -use crate::api_params::PinChatMessageParams; -use crate::api_params::PromoteChatMemberParams; -use crate::api_params::RefundStarPaymentParams; -use crate::api_params::ReopenForumTopicParams; -use crate::api_params::ReopenGeneralForumTopicParams; -use crate::api_params::ReplaceStickerInSetParams; -use crate::api_params::RestrictChatMemberParams; -use crate::api_params::RevokeChatInviteLinkParams; -use crate::api_params::SendAnimationParams; -use crate::api_params::SendAudioParams; -use crate::api_params::SendChatActionParams; -use crate::api_params::SendContactParams; -use crate::api_params::SendDiceParams; -use crate::api_params::SendDocumentParams; -use crate::api_params::SendGameParams; -use crate::api_params::SendInvoiceParams; -use crate::api_params::SendLocationParams; -use crate::api_params::SendMediaGroupParams; -use crate::api_params::SendMessageParams; -use crate::api_params::SendPaidMediaParams; -use crate::api_params::SendPhotoParams; -use crate::api_params::SendPollParams; -use crate::api_params::SendStickerParams; -use crate::api_params::SendVenueParams; -use crate::api_params::SendVideoNoteParams; -use crate::api_params::SendVideoParams; -use crate::api_params::SendVoiceParams; -use crate::api_params::SetChatAdministratorCustomTitleParams; -use crate::api_params::SetChatDescriptionParams; -use crate::api_params::SetChatMenuButtonParams; -use crate::api_params::SetChatPermissionsParams; -use crate::api_params::SetChatPhotoParams; -use crate::api_params::SetChatStickerSetParams; -use crate::api_params::SetChatTitleParams; -use crate::api_params::SetCustomEmojiStickerSetThumbnailParams; -use crate::api_params::SetGameScoreParams; -use crate::api_params::SetMessageReactionParams; -use crate::api_params::SetMyCommandsParams; -use crate::api_params::SetMyDefaultAdministratorRightsParams; -use crate::api_params::SetMyDescriptionParams; -use crate::api_params::SetMyNameParams; -use crate::api_params::SetMyShortDescriptionParams; -use crate::api_params::SetStickerEmojiListParams; -use crate::api_params::SetStickerKeywordsParams; -use crate::api_params::SetStickerMaskPositionParams; -use crate::api_params::SetStickerPositionInSetParams; -use crate::api_params::SetStickerSetThumbnailParams; -use crate::api_params::SetStickerSetTitleParams; -use crate::api_params::SetWebhookParams; -use crate::api_params::StopMessageLiveLocationParams; -use crate::api_params::StopPollParams; -use crate::api_params::UnbanChatMemberParams; -use crate::api_params::UnbanChatSenderChatParams; -use crate::api_params::UnhideGeneralForumTopicParams; -use crate::api_params::UnpinAllChatMessagesParams; -use crate::api_params::UnpinAllForumTopicMessagesParams; -use crate::api_params::UnpinChatMessageParams; -use crate::api_params::UploadStickerFileParams; -use crate::objects::BotCommand; -use crate::objects::BotDescription; -use crate::objects::BotName; -use crate::objects::BotShortDescription; -use crate::objects::BusinessConnection; -use crate::objects::ChatAdministratorRights; -use crate::objects::ChatFullInfo; -use crate::objects::ChatInviteLink; -use crate::objects::ChatMember; -use crate::objects::File as FileObject; -use crate::objects::ForumTopic; -use crate::objects::GameHighScore; -use crate::objects::InputSticker; -use crate::objects::MenuButton; -use crate::objects::Message; -use crate::objects::MessageId; -use crate::objects::Poll; -use crate::objects::SentWebAppMessage; -use crate::objects::StarTransactions; -use crate::objects::StickerSet; -use crate::objects::Update; -use crate::objects::User; -use crate::objects::UserChatBoosts; -use crate::objects::UserProfilePhotos; -use crate::objects::WebhookInfo; -use crate::Sticker; -use crate::UnpinAllGeneralForumTopicMessagesParams; +use crate::objects::{ + BotCommand, BotDescription, BotName, BotShortDescription, BusinessConnection, + ChatAdministratorRights, ChatFullInfo, ChatInviteLink, ChatMember, File as FileObject, + ForumTopic, GameHighScore, InputSticker, MenuButton, Message, MessageId, Poll, + SentWebAppMessage, StarTransactions, Sticker, StickerSet, Update, User, UserChatBoosts, + UserProfilePhotos, WebhookInfo, +}; +use crate::parameters::{ + AddStickerToSetParams, AnswerCallbackQueryParams, AnswerInlineQueryParams, + AnswerPreCheckoutQueryParams, AnswerShippingQueryParams, AnswerWebAppQueryParams, + ApproveChatJoinRequestParams, BanChatMemberParams, BanChatSenderChatParams, + CloseForumTopicParams, CloseGeneralForumTopicParams, CopyMessageParams, CopyMessagesParams, + CreateChatInviteLinkParams, CreateChatSubscriptionInviteLinkParams, CreateForumTopicParams, + CreateInvoiceLinkParams, CreateNewStickerSetParams, DeclineChatJoinRequestParams, + DeleteChatPhotoParams, DeleteChatStickerSetParams, DeleteForumTopicParams, DeleteMessageParams, + DeleteMessagesParams, DeleteMyCommandsParams, DeleteStickerFromSetParams, + DeleteStickerSetParams, DeleteWebhookParams, EditChatInviteLinkParams, + EditChatSubscriptionInviteLinkParams, EditForumTopicParams, EditGeneralForumTopicParams, + EditMessageCaptionParams, EditMessageLiveLocationParams, EditMessageMediaParams, + EditMessageReplyMarkupParams, EditMessageTextParams, ExportChatInviteLinkParams, FileUpload, + ForwardMessageParams, ForwardMessagesParams, GetBusinessConnectionParams, + GetChatAdministratorsParams, GetChatMemberCountParams, GetChatMemberParams, + GetChatMenuButtonParams, GetChatParams, GetCustomEmojiStickersParams, GetFileParams, + GetGameHighScoresParams, GetMyCommandsParams, GetMyDefaultAdministratorRightsParams, + GetMyDescriptionParams, GetMyNameParams, GetMyShortDescriptionParams, + GetStarTransactionsParams, GetStickerSetParams, GetUpdatesParams, GetUserChatBoostsParams, + GetUserProfilePhotosParams, HideGeneralForumTopicParams, InputMedia, LeaveChatParams, Media, + PinChatMessageParams, PromoteChatMemberParams, RefundStarPaymentParams, ReopenForumTopicParams, + ReopenGeneralForumTopicParams, ReplaceStickerInSetParams, RestrictChatMemberParams, + RevokeChatInviteLinkParams, SendAnimationParams, SendAudioParams, SendChatActionParams, + SendContactParams, SendDiceParams, SendDocumentParams, SendGameParams, SendInvoiceParams, + SendLocationParams, SendMediaGroupParams, SendMessageParams, SendPaidMediaParams, + SendPhotoParams, SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, + SendVideoParams, SendVoiceParams, SetChatAdministratorCustomTitleParams, + SetChatDescriptionParams, SetChatMenuButtonParams, SetChatPermissionsParams, + SetChatPhotoParams, SetChatStickerSetParams, SetChatTitleParams, + SetCustomEmojiStickerSetThumbnailParams, SetGameScoreParams, SetMessageReactionParams, + SetMyCommandsParams, SetMyDefaultAdministratorRightsParams, SetMyDescriptionParams, + SetMyNameParams, SetMyShortDescriptionParams, SetStickerEmojiListParams, + SetStickerKeywordsParams, SetStickerMaskPositionParams, SetStickerPositionInSetParams, + SetStickerSetThumbnailParams, SetStickerSetTitleParams, SetWebhookParams, + StopMessageLiveLocationParams, StopPollParams, UnbanChatMemberParams, + UnbanChatSenderChatParams, UnhideGeneralForumTopicParams, UnpinAllChatMessagesParams, + UnpinAllForumTopicMessagesParams, UnpinAllGeneralForumTopicMessagesParams, + UnpinChatMessageParams, UploadStickerFileParams, +}; +use crate::response::{EditMessageResponse, MethodResponse}; use async_trait::async_trait; use std::path::PathBuf; diff --git a/src/api_traits/telegram_api.rs b/src/api_traits/telegram_api.rs index 5da9d19..7485299 100644 --- a/src/api_traits/telegram_api.rs +++ b/src/api_traits/telegram_api.rs @@ -1,154 +1,50 @@ -use super::EditMessageResponse; -use super::MethodResponse; -use crate::api_params::AddStickerToSetParams; -use crate::api_params::AnswerCallbackQueryParams; -use crate::api_params::AnswerInlineQueryParams; -use crate::api_params::AnswerPreCheckoutQueryParams; -use crate::api_params::AnswerShippingQueryParams; -use crate::api_params::AnswerWebAppQueryParams; -use crate::api_params::ApproveChatJoinRequestParams; -use crate::api_params::BanChatMemberParams; -use crate::api_params::BanChatSenderChatParams; -use crate::api_params::CloseForumTopicParams; -use crate::api_params::CloseGeneralForumTopicParams; -use crate::api_params::CopyMessageParams; -use crate::api_params::CopyMessagesParams; -use crate::api_params::CreateChatInviteLinkParams; -use crate::api_params::CreateChatSubscriptionInviteLinkParams; -use crate::api_params::CreateForumTopicParams; -use crate::api_params::CreateInvoiceLinkParams; -use crate::api_params::CreateNewStickerSetParams; -use crate::api_params::DeclineChatJoinRequestParams; -use crate::api_params::DeleteChatPhotoParams; -use crate::api_params::DeleteChatStickerSetParams; -use crate::api_params::DeleteForumTopicParams; -use crate::api_params::DeleteMessageParams; -use crate::api_params::DeleteMessagesParams; -use crate::api_params::DeleteMyCommandsParams; -use crate::api_params::DeleteStickerFromSetParams; -use crate::api_params::DeleteStickerSetParams; -use crate::api_params::DeleteWebhookParams; -use crate::api_params::EditChatInviteLinkParams; -use crate::api_params::EditChatSubscriptionInviteLinkParams; -use crate::api_params::EditForumTopicParams; -use crate::api_params::EditGeneralForumTopicParams; -use crate::api_params::EditMessageCaptionParams; -use crate::api_params::EditMessageLiveLocationParams; -use crate::api_params::EditMessageMediaParams; -use crate::api_params::EditMessageReplyMarkupParams; -use crate::api_params::EditMessageTextParams; -use crate::api_params::ExportChatInviteLinkParams; -use crate::api_params::FileUpload; -use crate::api_params::ForwardMessageParams; -use crate::api_params::ForwardMessagesParams; -use crate::api_params::GetBusinessConnectionParams; -use crate::api_params::GetChatAdministratorsParams; -use crate::api_params::GetChatMemberCountParams; -use crate::api_params::GetChatMemberParams; -use crate::api_params::GetChatMenuButtonParams; -use crate::api_params::GetChatParams; -use crate::api_params::GetFileParams; -use crate::api_params::GetGameHighScoresParams; -use crate::api_params::GetMyCommandsParams; -use crate::api_params::GetMyDefaultAdministratorRightsParams; -use crate::api_params::GetMyDescriptionParams; -use crate::api_params::GetMyNameParams; -use crate::api_params::GetMyShortDescriptionParams; -use crate::api_params::GetStarTransactionsParams; -use crate::api_params::GetStickerSetParams; -use crate::api_params::GetUpdatesParams; -use crate::api_params::GetUserChatBoostsParams; -use crate::api_params::GetUserProfilePhotosParams; -use crate::api_params::HideGeneralForumTopicParams; -use crate::api_params::InputMedia; -use crate::api_params::LeaveChatParams; -use crate::api_params::Media; -use crate::api_params::PinChatMessageParams; -use crate::api_params::PromoteChatMemberParams; -use crate::api_params::RefundStarPaymentParams; -use crate::api_params::ReopenForumTopicParams; -use crate::api_params::ReopenGeneralForumTopicParams; -use crate::api_params::ReplaceStickerInSetParams; -use crate::api_params::RestrictChatMemberParams; -use crate::api_params::RevokeChatInviteLinkParams; -use crate::api_params::SendAnimationParams; -use crate::api_params::SendAudioParams; -use crate::api_params::SendChatActionParams; -use crate::api_params::SendContactParams; -use crate::api_params::SendDiceParams; -use crate::api_params::SendDocumentParams; -use crate::api_params::SendGameParams; -use crate::api_params::SendInvoiceParams; -use crate::api_params::SendLocationParams; -use crate::api_params::SendMediaGroupParams; -use crate::api_params::SendMessageParams; -use crate::api_params::SendPaidMediaParams; -use crate::api_params::SendPhotoParams; -use crate::api_params::SendPollParams; -use crate::api_params::SendStickerParams; -use crate::api_params::SendVenueParams; -use crate::api_params::SendVideoNoteParams; -use crate::api_params::SendVideoParams; -use crate::api_params::SendVoiceParams; -use crate::api_params::SetChatAdministratorCustomTitleParams; -use crate::api_params::SetChatDescriptionParams; -use crate::api_params::SetChatMenuButtonParams; -use crate::api_params::SetChatPermissionsParams; -use crate::api_params::SetChatPhotoParams; -use crate::api_params::SetChatStickerSetParams; -use crate::api_params::SetChatTitleParams; -use crate::api_params::SetCustomEmojiStickerSetThumbnailParams; -use crate::api_params::SetGameScoreParams; -use crate::api_params::SetMessageReactionParams; -use crate::api_params::SetMyCommandsParams; -use crate::api_params::SetMyDefaultAdministratorRightsParams; -use crate::api_params::SetMyDescriptionParams; -use crate::api_params::SetMyNameParams; -use crate::api_params::SetMyShortDescriptionParams; -use crate::api_params::SetStickerEmojiListParams; -use crate::api_params::SetStickerKeywordsParams; -use crate::api_params::SetStickerMaskPositionParams; -use crate::api_params::SetStickerPositionInSetParams; -use crate::api_params::SetStickerSetThumbnailParams; -use crate::api_params::SetStickerSetTitleParams; -use crate::api_params::SetWebhookParams; -use crate::api_params::StopMessageLiveLocationParams; -use crate::api_params::StopPollParams; -use crate::api_params::UnbanChatMemberParams; -use crate::api_params::UnbanChatSenderChatParams; -use crate::api_params::UnhideGeneralForumTopicParams; -use crate::api_params::UnpinAllChatMessagesParams; -use crate::api_params::UnpinAllForumTopicMessagesParams; -use crate::api_params::UnpinChatMessageParams; -use crate::api_params::UploadStickerFileParams; -use crate::objects::BotCommand; -use crate::objects::BotDescription; -use crate::objects::BotName; -use crate::objects::BotShortDescription; -use crate::objects::BusinessConnection; -use crate::objects::ChatAdministratorRights; -use crate::objects::ChatFullInfo; -use crate::objects::ChatInviteLink; -use crate::objects::ChatMember; -use crate::objects::File as FileObject; -use crate::objects::ForumTopic; -use crate::objects::GameHighScore; -use crate::objects::InputSticker; -use crate::objects::MenuButton; -use crate::objects::Message; -use crate::objects::MessageId; -use crate::objects::Poll; -use crate::objects::SentWebAppMessage; -use crate::objects::StarTransactions; -use crate::objects::StickerSet; -use crate::objects::Update; -use crate::objects::User; -use crate::objects::UserChatBoosts; -use crate::objects::UserProfilePhotos; -use crate::objects::WebhookInfo; -use crate::GetCustomEmojiStickersParams; -use crate::Sticker; -use crate::UnpinAllGeneralForumTopicMessagesParams; +use crate::objects::{ + BotCommand, BotDescription, BotName, BotShortDescription, BusinessConnection, + ChatAdministratorRights, ChatFullInfo, ChatInviteLink, ChatMember, File as FileObject, + ForumTopic, GameHighScore, InputSticker, MenuButton, Message, MessageId, Poll, + SentWebAppMessage, StarTransactions, Sticker, StickerSet, Update, User, UserChatBoosts, + UserProfilePhotos, WebhookInfo, +}; +use crate::parameters::{ + AddStickerToSetParams, AnswerCallbackQueryParams, AnswerInlineQueryParams, + AnswerPreCheckoutQueryParams, AnswerShippingQueryParams, AnswerWebAppQueryParams, + ApproveChatJoinRequestParams, BanChatMemberParams, BanChatSenderChatParams, + CloseForumTopicParams, CloseGeneralForumTopicParams, CopyMessageParams, CopyMessagesParams, + CreateChatInviteLinkParams, CreateChatSubscriptionInviteLinkParams, CreateForumTopicParams, + CreateInvoiceLinkParams, CreateNewStickerSetParams, DeclineChatJoinRequestParams, + DeleteChatPhotoParams, DeleteChatStickerSetParams, DeleteForumTopicParams, DeleteMessageParams, + DeleteMessagesParams, DeleteMyCommandsParams, DeleteStickerFromSetParams, + DeleteStickerSetParams, DeleteWebhookParams, EditChatInviteLinkParams, + EditChatSubscriptionInviteLinkParams, EditForumTopicParams, EditGeneralForumTopicParams, + EditMessageCaptionParams, EditMessageLiveLocationParams, EditMessageMediaParams, + EditMessageReplyMarkupParams, EditMessageTextParams, ExportChatInviteLinkParams, FileUpload, + ForwardMessageParams, ForwardMessagesParams, GetBusinessConnectionParams, + GetChatAdministratorsParams, GetChatMemberCountParams, GetChatMemberParams, + GetChatMenuButtonParams, GetChatParams, GetCustomEmojiStickersParams, GetFileParams, + GetGameHighScoresParams, GetMyCommandsParams, GetMyDefaultAdministratorRightsParams, + GetMyDescriptionParams, GetMyNameParams, GetMyShortDescriptionParams, + GetStarTransactionsParams, GetStickerSetParams, GetUpdatesParams, GetUserChatBoostsParams, + GetUserProfilePhotosParams, HideGeneralForumTopicParams, InputMedia, LeaveChatParams, Media, + PinChatMessageParams, PromoteChatMemberParams, RefundStarPaymentParams, ReopenForumTopicParams, + ReopenGeneralForumTopicParams, ReplaceStickerInSetParams, RestrictChatMemberParams, + RevokeChatInviteLinkParams, SendAnimationParams, SendAudioParams, SendChatActionParams, + SendContactParams, SendDiceParams, SendDocumentParams, SendGameParams, SendInvoiceParams, + SendLocationParams, SendMediaGroupParams, SendMessageParams, SendPaidMediaParams, + SendPhotoParams, SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, + SendVideoParams, SendVoiceParams, SetChatAdministratorCustomTitleParams, + SetChatDescriptionParams, SetChatMenuButtonParams, SetChatPermissionsParams, + SetChatPhotoParams, SetChatStickerSetParams, SetChatTitleParams, + SetCustomEmojiStickerSetThumbnailParams, SetGameScoreParams, SetMessageReactionParams, + SetMyCommandsParams, SetMyDefaultAdministratorRightsParams, SetMyDescriptionParams, + SetMyNameParams, SetMyShortDescriptionParams, SetStickerEmojiListParams, + SetStickerKeywordsParams, SetStickerMaskPositionParams, SetStickerPositionInSetParams, + SetStickerSetThumbnailParams, SetStickerSetTitleParams, SetWebhookParams, + StopMessageLiveLocationParams, StopPollParams, UnbanChatMemberParams, + UnbanChatSenderChatParams, UnhideGeneralForumTopicParams, UnpinAllChatMessagesParams, + UnpinAllForumTopicMessagesParams, UnpinAllGeneralForumTopicMessagesParams, + UnpinChatMessageParams, UploadStickerFileParams, +}; +use crate::response::{EditMessageResponse, MethodResponse}; use std::path::PathBuf; pub trait TelegramApi { diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..6e5a057 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, thiserror::Error)] +#[serde(untagged)] +pub enum Error { + #[error("Http Error {code}: {message}")] + Http { code: u16, message: String }, + #[error("Api Error {0:?}")] + Api(crate::response::ErrorResponse), + #[error("Decode Error {0}")] + Decode(String), + #[error("Encode Error {0}")] + Encode(String), +} + +#[cfg(feature = "reqwest")] +impl From for Error { + fn from(error: reqwest::Error) -> Self { + let message = error.to_string(); + let code = error + .status() + .map_or(500, |status_code| status_code.as_u16()); + Self::Http { code, message } + } +} + +#[cfg(feature = "ureq")] +impl From for Error { + fn from(error: ureq::Error) -> Self { + match error { + ureq::Error::Status(code, response) => match response.into_string() { + Ok(message) => match serde_json::from_str(&message) { + Ok(json_result) => Self::Api(json_result), + Err(_) => Self::Http { code, message }, + }, + Err(_) => Self::Http { + code, + message: "Failed to decode response".to_string(), + }, + }, + ureq::Error::Transport(transport_error) => Self::Http { + message: format!("{transport_error:?}"), + code: 500, + }, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 3912f55..ecafd01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,27 +1,24 @@ -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -pub mod api; - -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -pub mod api_traits; - -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -pub use api::*; - -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -pub use api_traits::*; - -#[doc(hidden)] #[cfg(feature = "async-http-client")] pub use reqwest; - -#[doc(hidden)] #[cfg(feature = "http-client")] pub use ureq; -pub mod api_params; +#[cfg(any(feature = "http-client", feature = "async-http-client"))] +mod api; +#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] +mod api_traits; +mod error; pub mod objects; +pub mod parameters; mod parse_mode; +pub mod response; + +#[cfg(any(feature = "http-client", feature = "async-http-client"))] +pub use api::*; +#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] +pub use api_traits::*; +pub use error::Error; +pub use parse_mode::ParseMode; -pub use api_params::*; -pub use objects::*; -pub use parse_mode::*; +/// Default Bot API URL +pub const BASE_API_URL: &str = "https://api.telegram.org/bot"; diff --git a/src/objects.rs b/src/objects.rs index 9eb8099..6864cda 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -1,9 +1,11 @@ +//! Objects returned or used with the Telegram API. + #![allow(deprecated)] -use super::api_params::FileUpload; -use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder as Builder; +use crate::parameters::FileUpload; use crate::ParseMode; +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder as Builder; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] diff --git a/src/api_params.rs b/src/parameters.rs similarity index 98% rename from src/api_params.rs rename to src/parameters.rs index a99d6f0..3070dfb 100644 --- a/src/api_params.rs +++ b/src/parameters.rs @@ -1,23 +1,26 @@ -#![allow(deprecated)] +//! Parameters to Telegram API methods. + +#![allow(clippy::module_name_repetitions)] + use crate::objects::{ - BotCommand, ChatAdministratorRights, ChatPermissions, ForceReply, InlineKeyboardMarkup, - InlineQueryResultArticle, InlineQueryResultAudio, InlineQueryResultCachedAudio, - InlineQueryResultCachedDocument, InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif, - InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker, InlineQueryResultCachedVideo, - InlineQueryResultCachedVoice, InlineQueryResultContact, InlineQueryResultDocument, - InlineQueryResultGame, InlineQueryResultGif, InlineQueryResultLocation, - InlineQueryResultMpeg4Gif, InlineQueryResultPhoto, InlineQueryResultVenue, - InlineQueryResultVideo, InlineQueryResultVoice, InputPaidMedia, InputPollOption, InputSticker, - LabeledPrice, LinkPreviewOptions, MaskPosition, MenuButton, MessageEntity, - PassportElementErrorDataField, PassportElementErrorFile, PassportElementErrorFiles, - PassportElementErrorFrontSide, PassportElementErrorReverseSide, PassportElementErrorSelfie, - PassportElementErrorTranslationFile, PassportElementErrorTranslationFiles, - PassportElementErrorUnspecified, PollType, ReactionType, ReplyKeyboardMarkup, - ReplyKeyboardRemove, ShippingOption, StickerFormat, StickerType, WebAppInfo, + AllowedUpdate, BotCommand, ChatAdministratorRights, ChatPermissions, ForceReply, + InlineKeyboardMarkup, InlineQueryResultArticle, InlineQueryResultAudio, + InlineQueryResultCachedAudio, InlineQueryResultCachedDocument, InlineQueryResultCachedGif, + InlineQueryResultCachedMpeg4Gif, InlineQueryResultCachedPhoto, InlineQueryResultCachedSticker, + InlineQueryResultCachedVideo, InlineQueryResultCachedVoice, InlineQueryResultContact, + InlineQueryResultDocument, InlineQueryResultGame, InlineQueryResultGif, + InlineQueryResultLocation, InlineQueryResultMpeg4Gif, InlineQueryResultPhoto, + InlineQueryResultVenue, InlineQueryResultVideo, InlineQueryResultVoice, InputPaidMedia, + InputPollOption, InputSticker, LabeledPrice, LinkPreviewOptions, MaskPosition, MenuButton, + MessageEntity, PassportElementErrorDataField, PassportElementErrorFile, + PassportElementErrorFiles, PassportElementErrorFrontSide, PassportElementErrorReverseSide, + PassportElementErrorSelfie, PassportElementErrorTranslationFile, + PassportElementErrorTranslationFiles, PassportElementErrorUnspecified, PollType, ReactionType, + ReplyKeyboardMarkup, ReplyKeyboardRemove, ShippingOption, StickerFormat, StickerType, + WebAppInfo, }; -use crate::{AllowedUpdate, ParseMode}; -use serde::Deserialize; -use serde::Serialize; +use crate::parse_mode::ParseMode; +use serde::{Deserialize, Serialize}; use std::path::PathBuf; use typed_builder::TypedBuilder as Builder; diff --git a/src/parse_mode.rs b/src/parse_mode.rs index e3bc0f1..89b51af 100644 --- a/src/parse_mode.rs +++ b/src/parse_mode.rs @@ -1,10 +1,12 @@ #![allow(deprecated)] +use serde::{Deserialize, Serialize}; use std::fmt::Display; use std::str::FromStr; -use serde::{Deserialize, Serialize}; - +/// Text Formatting Options +/// +/// See #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum ParseMode { #[serde(rename = "HTML")] @@ -18,6 +20,7 @@ pub enum ParseMode { impl FromStr for ParseMode { type Err = (); + fn from_str(s: &str) -> Result { match s { "HTML" | "Html" | "html" => Ok(Self::Html), diff --git a/src/response.rs b/src/response.rs new file mode 100644 index 0000000..d4791c1 --- /dev/null +++ b/src/response.rs @@ -0,0 +1,41 @@ +//! Raw reponse objects returned by the Telegram API. +//! +//! Mainly useful when implementing the `TelegramApi` trait. + +#![allow(clippy::module_name_repetitions)] + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct MethodResponse { + /// Always true + pub ok: bool, + pub result: T, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, +} + +/// Error on an unsuccessful request. +/// +/// `ok` equals false and the error is explained in the `description`. +/// An Integer `error_code` field is also returned, but its contents are subject to change in the future. +/// Some errors may also have an optional field `parameters` of the type `ResponseParameters`, which can help to automatically handle the error. +/// +/// See +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct ErrorResponse { + /// Always false + pub ok: bool, + pub description: String, + /// Contents are subject to change in the future + pub error_code: u64, + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum EditMessageResponse { + Message(MethodResponse), + Bool(MethodResponse), +} From 4d82cc5cf27331abae6c0933dce735a9271aae39 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Tue, 10 Sep 2024 12:03:01 +0200 Subject: [PATCH 2/6] refactor(example): inline struct creation --- examples/api_trait_implementation.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/api_trait_implementation.rs b/examples/api_trait_implementation.rs index f477a20..1f254bb 100644 --- a/examples/api_trait_implementation.rs +++ b/examples/api_trait_implementation.rs @@ -66,19 +66,19 @@ impl TelegramApi for Api { } }; - let text = response.text().map_err(|error| { - let message = error.to_string(); - Error::HttpError { code: 500, message } + let text = response.text().map_err(|error| Error::HttpError { + code: 500, + message: error.to_string(), })?; let parsed_result: Result = serde_json::from_str(&text); parsed_result.map_err(|_| match serde_json::from_str::(&text) { Ok(result) => Error::ApiError(result), - Err(error) => { - let message = format!("{error:?}"); - Error::HttpError { code: 500, message } - } + Err(error) => Error::HttpError { + code: 500, + message: format!("{error:?}"), + }, }) } From 8eaef6f357e74026559fc7e9e578f30eef68ec06 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Tue, 10 Sep 2024 12:11:11 +0200 Subject: [PATCH 3/6] refactor: flatten module structure They are exported on top level anyway, so there is no real need for the folders --- src/api.rs | 9 ------ src/api_traits.rs | 9 ------ ...telegram_api_impl.rs => client_reqwest.rs} | 2 +- .../telegram_api_impl.rs => client_ureq.rs} | 2 +- src/lib.rs | 28 ++++++++++++------- .../async_telegram_api.rs => trait_async.rs} | 0 .../telegram_api.rs => trait_sync.rs} | 0 7 files changed, 20 insertions(+), 30 deletions(-) delete mode 100644 src/api.rs delete mode 100644 src/api_traits.rs rename src/{api/async_telegram_api_impl.rs => client_reqwest.rs} (99%) rename src/{api/telegram_api_impl.rs => client_ureq.rs} (99%) rename src/{api_traits/async_telegram_api.rs => trait_async.rs} (100%) rename src/{api_traits/telegram_api.rs => trait_sync.rs} (100%) diff --git a/src/api.rs b/src/api.rs deleted file mode 100644 index 951461a..0000000 --- a/src/api.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(feature = "async-http-client")] -pub use async_telegram_api_impl::*; -#[cfg(feature = "http-client")] -pub use telegram_api_impl::*; - -#[cfg(feature = "async-http-client")] -mod async_telegram_api_impl; -#[cfg(feature = "http-client")] -mod telegram_api_impl; diff --git a/src/api_traits.rs b/src/api_traits.rs deleted file mode 100644 index 2e512af..0000000 --- a/src/api_traits.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(feature = "async-telegram-trait")] -mod async_telegram_api; -#[cfg(feature = "telegram-trait")] -mod telegram_api; - -#[cfg(feature = "async-telegram-trait")] -pub use async_telegram_api::*; -#[cfg(feature = "telegram-trait")] -pub use telegram_api::*; diff --git a/src/api/async_telegram_api_impl.rs b/src/client_reqwest.rs similarity index 99% rename from src/api/async_telegram_api_impl.rs rename to src/client_reqwest.rs index a8431a8..4b2d8d7 100644 --- a/src/api/async_telegram_api_impl.rs +++ b/src/client_reqwest.rs @@ -1,5 +1,5 @@ -use crate::api_traits::AsyncTelegramApi; use crate::error::Error; +use crate::trait_async::AsyncTelegramApi; use async_trait::async_trait; use reqwest::multipart; use serde_json::Value; diff --git a/src/api/telegram_api_impl.rs b/src/client_ureq.rs similarity index 99% rename from src/api/telegram_api_impl.rs rename to src/client_ureq.rs index 0fe1bc8..49963d4 100644 --- a/src/api/telegram_api_impl.rs +++ b/src/client_ureq.rs @@ -1,5 +1,5 @@ -use crate::api_traits::TelegramApi; use crate::error::Error; +use crate::trait_sync::TelegramApi; use multipart::client::lazy::Multipart; use serde_json::Value; use std::path::PathBuf; diff --git a/src/lib.rs b/src/lib.rs index ecafd01..cb3a066 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,24 +1,32 @@ -#[cfg(feature = "async-http-client")] +#[cfg(feature = "reqwest")] pub use reqwest; -#[cfg(feature = "http-client")] +#[cfg(feature = "ureq")] pub use ureq; -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -mod api; -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -mod api_traits; +#[cfg(feature = "async-http-client")] +mod client_reqwest; +#[cfg(feature = "http-client")] +mod client_ureq; mod error; pub mod objects; pub mod parameters; mod parse_mode; pub mod response; +#[cfg(feature = "async-telegram-trait")] +mod trait_async; +#[cfg(feature = "telegram-trait")] +mod trait_sync; -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -pub use api::*; -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -pub use api_traits::*; +#[cfg(feature = "async-http-client")] +pub use client_reqwest::*; +#[cfg(feature = "http-client")] +pub use client_ureq::*; pub use error::Error; pub use parse_mode::ParseMode; +#[cfg(feature = "async-telegram-trait")] +pub use trait_async::AsyncTelegramApi; +#[cfg(feature = "telegram-trait")] +pub use trait_sync::TelegramApi; /// Default Bot API URL pub const BASE_API_URL: &str = "https://api.telegram.org/bot"; diff --git a/src/api_traits/async_telegram_api.rs b/src/trait_async.rs similarity index 100% rename from src/api_traits/async_telegram_api.rs rename to src/trait_async.rs diff --git a/src/api_traits/telegram_api.rs b/src/trait_sync.rs similarity index 100% rename from src/api_traits/telegram_api.rs rename to src/trait_sync.rs From a6ce27051d94c9251566713a908b24287c28533c Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Tue, 10 Sep 2024 12:17:16 +0200 Subject: [PATCH 4/6] refactor(example): reduce name repetition --- examples/api_trait_implementation.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/api_trait_implementation.rs b/examples/api_trait_implementation.rs index 1f254bb..6eebf05 100644 --- a/examples/api_trait_implementation.rs +++ b/examples/api_trait_implementation.rs @@ -15,8 +15,8 @@ pub struct Api { #[derive(Debug)] pub enum Error { - HttpError { code: u16, message: String }, - ApiError(ErrorResponse), + Http { code: u16, message: String }, + Api(ErrorResponse), } impl Api { @@ -35,14 +35,14 @@ impl Api { impl From for Error { fn from(error: isahc::http::Error) -> Self { let message = format!("{error:?}"); - Self::HttpError { code: 500, message } + Self::Http { code: 500, message } } } impl From for Error { fn from(error: isahc::Error) -> Self { let message = format!("{error:?}"); - Self::HttpError { code: 500, message } + Self::Http { code: 500, message } } } @@ -66,7 +66,7 @@ impl TelegramApi for Api { } }; - let text = response.text().map_err(|error| Error::HttpError { + let text = response.text().map_err(|error| Error::Http { code: 500, message: error.to_string(), })?; @@ -74,8 +74,8 @@ impl TelegramApi for Api { let parsed_result: Result = serde_json::from_str(&text); parsed_result.map_err(|_| match serde_json::from_str::(&text) { - Ok(result) => Error::ApiError(result), - Err(error) => Error::HttpError { + Ok(result) => Error::Api(result), + Err(error) => Error::Http { code: 500, message: format!("{error:?}"), }, @@ -91,7 +91,7 @@ impl TelegramApi for Api { _files: Vec<(&str, PathBuf)>, ) -> Result { let message = "isahc doesn't support form data requests".to_string(); - Err(Error::HttpError { code: 500, message }) + Err(Error::Http { code: 500, message }) } } From 8d419b19641e3dac299735d10c50243ee28c5362 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Tue, 10 Sep 2024 22:54:18 +0200 Subject: [PATCH 5/6] refactor: write error variable name longer while error is nicer, err prevents another line break so its sometimes preferred --- examples/reply_to_message_updates.rs | 6 ++---- src/client_reqwest.rs | 4 ++-- src/client_ureq.rs | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/reply_to_message_updates.rs b/examples/reply_to_message_updates.rs index e79f55d..e7158b0 100644 --- a/examples/reply_to_message_updates.rs +++ b/examples/reply_to_message_updates.rs @@ -21,15 +21,13 @@ fn main() { let reply_parameters = ReplyParameters::builder() .message_id(message.message_id) .build(); - let send_message_params = SendMessageParams::builder() .chat_id(message.chat.id) .text("hello") .reply_parameters(reply_parameters) .build(); - - if let Err(err) = api.send_message(&send_message_params) { - println!("Failed to send message: {err:?}"); + if let Err(error) = api.send_message(&send_message_params) { + println!("Failed to send message: {error:?}"); } } update_params.offset = Some(i64::from(update.update_id) + 1); diff --git a/src/client_reqwest.rs b/src/client_reqwest.rs index d602de7..4b16f10 100644 --- a/src/client_reqwest.rs +++ b/src/client_reqwest.rs @@ -34,7 +34,7 @@ impl AsyncApi { where Params: serde::ser::Serialize + std::fmt::Debug, { - serde_json::to_string(params).map_err(|e| Error::Encode(format!("{e:?} : {params:?}"))) + serde_json::to_string(params).map_err(|err| Error::Encode(format!("{err:?} : {params:?}"))) } pub async fn decode_response(response: reqwest::Response) -> Result @@ -55,7 +55,7 @@ impl AsyncApi { } fn parse_json(body: &str) -> Result { - serde_json::from_str(body).map_err(|e| Error::Decode(format!("{e:?} : {body:?}"))) + serde_json::from_str(body).map_err(|error| Error::Decode(format!("{error:?} : {body:?}"))) } } diff --git a/src/client_ureq.rs b/src/client_ureq.rs index 6ce0b57..52259ee 100644 --- a/src/client_ureq.rs +++ b/src/client_ureq.rs @@ -31,7 +31,7 @@ impl Api { where Params: serde::ser::Serialize + std::fmt::Debug, { - serde_json::to_string(params).map_err(|e| Error::Encode(format!("{e:?} : {params:?}"))) + serde_json::to_string(params).map_err(|err| Error::Encode(format!("{err:?} : {params:?}"))) } pub fn decode_response(response: Response) -> Result @@ -41,7 +41,7 @@ impl Api { match response.into_string() { Ok(message) => serde_json::from_str(&message) .map_err(|error| Error::Decode(format!("{error:?} : {message:?}"))), - Err(e) => Err(Error::Decode(format!("Failed to decode response: {e:?}"))), + Err(err) => Err(Error::Decode(format!("Failed to decode response: {err:?}"))), } } } From c6701935c7a84ae4dddd77e7b909c86ef52bf7e3 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Tue, 10 Sep 2024 22:56:14 +0200 Subject: [PATCH 6/6] fix(error): dont specify kind in text again the kind already contains this information --- src/client_ureq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client_ureq.rs b/src/client_ureq.rs index 52259ee..039e04f 100644 --- a/src/client_ureq.rs +++ b/src/client_ureq.rs @@ -41,7 +41,7 @@ impl Api { match response.into_string() { Ok(message) => serde_json::from_str(&message) .map_err(|error| Error::Decode(format!("{error:?} : {message:?}"))), - Err(err) => Err(Error::Decode(format!("Failed to decode response: {err:?}"))), + Err(error) => Err(Error::Decode(format!("{error:?}"))), } } }