use std::{error::Error, sync::Arc, time::Duration};
use crate::gen_types::ResponseParameters;
use anyhow::Result;
use reqwest::multipart::Form;
use serde::{Deserialize, Serialize};
pub use reqwest::multipart::Part;
#[derive(Serialize, Deserialize, Debug)]
pub struct Response {
pub ok: bool,
pub result: Option<serde_json::Value>,
pub error_code: Option<i64>,
pub description: Option<String>,
pub parameters: Option<ResponseParameters>,
#[serde(skip, default)]
pub floods: Option<Vec<ResponseFlood>>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ResponseFlood {
pub ok: bool,
pub result: Option<serde_json::Value>,
pub error_code: Option<i64>,
pub description: Option<String>,
pub parameters: Option<ResponseParameters>,
}
impl Response {
pub async fn wait(&self) -> bool {
if let Some(ref params) = self.parameters {
if let Some(retry) = params.get_retry_after() {
tokio::time::sleep(Duration::from_secs(retry as u64)).await;
return true;
}
}
false
}
fn get_flood(&self) -> ResponseFlood {
ResponseFlood {
ok: self.ok,
result: self.result.clone(),
error_code: self.error_code,
description: self.description.clone(),
parameters: self.parameters.clone(),
}
}
}
pub type BotResult<T> = Result<T, ApiError>;
#[derive(Debug)]
struct BotState {
client: reqwest::Client,
token: String,
api: String,
auto_wait: bool,
}
#[derive(Debug)]
enum ErrResponse {
Response(Response),
Err(anyhow::Error),
}
#[derive(Debug)]
pub struct ApiError(ErrResponse);
impl ApiError {
pub(crate) fn from_response(resp: Response) -> Self {
Self(ErrResponse::Response(resp))
}
pub fn get_response(&self) -> Option<&'_ Response> {
if let ErrResponse::Response(ref response) = self.0 {
Some(response)
} else {
None
}
}
}
impl From<anyhow::Error> for ApiError {
fn from(value: anyhow::Error) -> Self {
Self(ErrResponse::Err(value))
}
}
impl From<reqwest::Error> for ApiError {
fn from(value: reqwest::Error) -> Self {
Self(ErrResponse::Err(anyhow::anyhow!(value)))
}
}
impl From<serde_json::Error> for ApiError {
fn from(value: serde_json::Error) -> Self {
Self(ErrResponse::Err(anyhow::anyhow!(value)))
}
}
impl Error for ApiError {}
impl std::fmt::Display for ApiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
ErrResponse::Response(Response {
description: Some(ref d),
..
}) => f.write_str(d)?,
ErrResponse::Response(Response { error_code, .. }) => {
f.write_str(&error_code.unwrap_or(-1).to_string())?
}
ErrResponse::Err(ref err) => f.write_str(&err.to_string())?,
};
Ok(())
}
}
#[derive(Debug)]
pub struct Bot(Arc<BotState>);
impl Default for Response {
fn default() -> Self {
Response {
ok: true,
result: None,
error_code: None,
description: None,
parameters: None,
floods: None,
}
}
}
pub struct BotBuilder(BotState);
impl BotBuilder {
pub fn new<T>(token: T) -> Result<Self>
where
T: Into<String>,
{
let client = reqwest::ClientBuilder::new().https_only(true).build()?;
Ok(Self(BotState {
client,
token: token.into(),
api: "https://api.telegram.org".to_owned(),
auto_wait: true,
}))
}
pub fn api<T>(mut self, api: T) -> Self
where
T: Into<String>,
{
self.0.api = api.into();
self
}
pub fn auto_wait(mut self, auto_wait: bool) -> Self {
self.0.auto_wait = auto_wait;
self
}
pub fn build(self) -> Bot {
Bot(Arc::new(self.0))
}
}
impl Bot {
#[deprecated]
pub fn new_auto_wait<T>(token: T, auto_wait: bool) -> Result<Self>
where
T: Into<String>,
{
let client = reqwest::ClientBuilder::new().https_only(true).build()?;
Ok(Self(Arc::new(BotState {
client,
token: token.into(),
api: "https://api.telegram.org".to_owned(),
auto_wait,
})))
}
#[deprecated]
#[allow(deprecated)]
pub fn new<T>(token: T) -> Result<Self>
where
T: Into<String>,
{
Self::new_auto_wait(token, false)
}
fn get_endpoint(&self, endpoint: &str) -> String {
format!("{}/bot{}/{}", self.0.api, self.0.token, endpoint)
}
pub async fn post<T>(&self, endpoint: &str, body: T) -> BotResult<Response>
where
T: Serialize,
{
let endpoint = self.get_endpoint(endpoint);
let mut floods = if self.0.auto_wait {
Some(Vec::<ResponseFlood>::new())
} else {
None
};
loop {
let resp = self
.0
.client
.post(&endpoint)
.query(&body)
.send()
.await
.map_err(|e| e.without_url())?;
let bytes = resp.bytes().await?;
let mut resp: Response = serde_json::from_slice(&bytes)?;
if self.0.auto_wait && resp.wait().await {
floods.as_mut().unwrap().push(resp.get_flood());
continue;
} else {
if let Some(floods) = floods {
resp.floods = Some(floods);
}
return Ok(resp);
}
}
}
pub async fn post_empty(&self, endpoint: &str) -> BotResult<Response> {
let endpoint = self.get_endpoint(endpoint);
let mut floods = if self.0.auto_wait {
Some(Vec::<ResponseFlood>::new())
} else {
None
};
loop {
let resp = self
.0
.client
.post(&endpoint)
.send()
.await
.map_err(|e| e.without_url())?;
let bytes = resp.bytes().await?;
let mut resp: Response = serde_json::from_slice(&bytes)?;
if self.0.auto_wait && resp.wait().await {
floods.as_mut().unwrap().push(resp.get_flood());
continue;
} else {
if let Some(floods) = floods {
resp.floods = Some(floods);
}
return Ok(resp);
}
}
}
pub async fn post_data<T>(&self, endpoint: &str, body: T, data: Form) -> BotResult<Response>
where
T: Serialize,
{
let endpoint = self.get_endpoint(endpoint);
let resp = self
.0
.client
.post(&endpoint)
.query(&body)
.multipart(data)
.send()
.await
.map_err(|e| e.without_url())?;
let bytes = resp.bytes().await?;
let mut resp: Response = serde_json::from_slice(&bytes)?;
if self.0.auto_wait {
resp.wait().await;
resp.floods = Some(vec![resp.get_flood()]);
}
Ok(resp)
}
}
impl Clone for Bot {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}