1use thiserror::Error;
2
3#[derive(Debug, Error)]
5pub enum Error {
6 #[error("Telegram API error {error_code}: {description}")]
8 Api {
9 error_code: u16,
11 description: String,
13 migrate_to_chat_id: Option<i64>,
15 retry_after: Option<u32>,
17 },
18
19 #[error("HTTP error: {0}")]
21 Http(#[from] reqwest::Error),
22
23 #[error("Serialization error: {0}")]
25 Serialization(#[from] serde_json::Error),
26
27 #[error("Response decode error: {0}")]
29 Decode(String),
30
31 #[error("Rate limited: retry after {retry_after}s")]
33 RateLimit {
34 retry_after: u32,
36 },
37
38 #[error("Invalid bot token format")]
40 InvalidToken,
41
42 #[error("Missing required parameter: {0}")]
44 MissingParam(&'static str),
45}
46
47impl Error {
48 #[must_use]
50 pub fn is_rate_limit(&self) -> bool {
51 matches!(
52 self,
53 Self::RateLimit { .. }
54 | Self::Api {
55 error_code: 429,
56 ..
57 }
58 )
59 }
60
61 #[must_use]
63 pub fn retry_after(&self) -> Option<u32> {
64 match self {
65 Self::RateLimit { retry_after } => Some(*retry_after),
66 Self::Api { retry_after, .. } => *retry_after,
67 _ => None,
68 }
69 }
70
71 #[must_use]
73 pub fn is_blocked(&self) -> bool {
74 matches!(self, Self::Api { error_code: 403, description, .. }
75 if description.contains("bot was blocked"))
76 }
77
78 #[must_use]
80 pub fn is_chat_not_found(&self) -> bool {
81 matches!(self, Self::Api { error_code: 400, description, .. }
82 if description.contains("chat not found"))
83 }
84}
85
86pub type Result<T> = std::result::Result<T, Error>;