use crate::Method;
use http::Uri;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[cfg(feature = "worker-0_8")]
pub mod worker_0_8;
#[derive(Debug)]
pub struct Client<E> {
executor: E,
token: String,
}
pub trait ClientExecutor {
type Error;
fn request<T, U>(
&mut self,
uri: Uri,
payload: T,
) -> impl Future<Output = Result<U, Self::Error>> + Send
where
T: Serialize + Send,
U: for<'a> Deserialize<'a>;
}
#[derive(Debug, Error)]
pub enum Error<T> {
#[error(transparent)]
Executor(#[from] T),
#[error("telegram bot api returned error code: {error_code}, description: {description}")]
Api {
error_code: u16,
description: String,
},
}
impl<E> Client<E>
where
E: ClientExecutor,
{
pub fn new(executor: E, token: impl Into<String>) -> Self {
Self {
executor,
token: token.into(),
}
}
pub async fn execute<M>(&mut self, method: M) -> Result<M::Response, Error<E::Error>>
where
M: Method + Send,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum Response<T> {
Success {
#[allow(dead_code)]
ok: monostate::MustBe!(true),
result: T,
},
Failure {
#[allow(dead_code)]
ok: monostate::MustBe!(false),
error_code: u16,
description: String,
},
}
let uri = format!(
"https://api.telegram.org/bot{token}/{name}",
token = self.token,
name = M::NAME,
);
let uri = Uri::try_from(uri).unwrap();
let response = self
.executor
.request::<M, Response<M::Response>>(uri, method)
.await?;
match response {
Response::Success { ok: _, result } => Ok(result),
Response::Failure {
ok: _,
error_code,
description,
} => Err(Error::Api {
error_code,
description,
}),
}
}
}