tgbot/types/definitions/
response.rs

1use std::{error::Error, fmt};
2
3use serde::Deserialize;
4
5use crate::types::Integer;
6
7/// Represents an API Response.
8#[derive(Clone, Debug, Deserialize)]
9#[serde(from = "RawResponse<T>")]
10pub enum Response<T> {
11    /// Success.
12    Success(T),
13    /// Error.
14    Error(ResponseError),
15}
16
17impl<T> Response<T> {
18    /// Returns a number of seconds left to wait before the request can be repeated.
19    pub fn retry_after(&self) -> Option<u64> {
20        match self {
21            Response::Success(_) => None,
22            Response::Error(err) => err.retry_after(),
23        }
24    }
25
26    /// Converts the response into [`Result`].
27    pub fn into_result(self) -> Result<T, ResponseError> {
28        match self {
29            Response::Success(obj) => Ok(obj),
30            Response::Error(err) => Err(err),
31        }
32    }
33}
34
35impl<T> From<RawResponse<T>> for Response<T> {
36    fn from(raw: RawResponse<T>) -> Self {
37        if raw.ok {
38            if let Some(result) = raw.result {
39                Response::Success(result)
40            } else {
41                Response::Error(ResponseError {
42                    description: String::from("response is ok, but result is not provided"),
43                    error_code: None,
44                    migrate_to_chat_id: None,
45                    retry_after: None,
46                })
47            }
48        } else {
49            Response::Error(ResponseError {
50                description: raw.description.unwrap_or_else(|| String::from("no description")),
51                error_code: raw.error_code,
52                migrate_to_chat_id: raw.parameters.and_then(|x| x.migrate_to_chat_id),
53                retry_after: raw.parameters.and_then(|x| x.retry_after),
54            })
55        }
56    }
57}
58
59/// Represents a response error.
60#[derive(Clone, Debug)]
61pub struct ResponseError {
62    description: String,
63    error_code: Option<Integer>,
64    migrate_to_chat_id: Option<Integer>,
65    retry_after: Option<Integer>,
66}
67
68impl ResponseError {
69    /// Returns a human-readable description of the error.
70    pub fn description(&self) -> &str {
71        &self.description
72    }
73
74    /// Returns an error code.
75    pub fn error_code(&self) -> Option<Integer> {
76        self.error_code
77    }
78
79    /// Returns a flag describing whether a request can be repeated.
80    pub fn can_retry(&self) -> bool {
81        self.retry_after.is_some()
82    }
83
84    /// Returns a number of seconds left to wait before the request can be repeated.
85    pub fn retry_after(&self) -> Option<u64> {
86        self.retry_after.and_then(|x| x.try_into().ok())
87    }
88
89    /// Returns a new identifier of a group which has been migrated to a supergroup.
90    pub fn migrate_to_chat_id(&self) -> Option<Integer> {
91        self.migrate_to_chat_id
92    }
93}
94
95impl Error for ResponseError {}
96
97impl fmt::Display for ResponseError {
98    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
99        write!(out, "a telegram error has occurred: description={}", self.description)?;
100        if let Some(code) = self.error_code {
101            write!(out, "; error_code={code}")?;
102        }
103        if let Some(chat_id) = self.migrate_to_chat_id {
104            write!(out, "; migrate_to_chat_id={chat_id}")?;
105        }
106        if let Some(retry_after) = self.retry_after {
107            write!(out, "; retry_after={retry_after}")?;
108        }
109        Ok(())
110    }
111}
112
113#[derive(Clone, Debug, Deserialize)]
114struct RawResponse<T> {
115    ok: bool,
116    result: Option<T>,
117    description: Option<String>,
118    error_code: Option<Integer>,
119    parameters: Option<RawResponseParameters>,
120}
121
122#[derive(Clone, Copy, Debug, Deserialize)]
123struct RawResponseParameters {
124    migrate_to_chat_id: Option<Integer>,
125    retry_after: Option<Integer>,
126}