mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
implement get_me
caching
This commit is contained in:
parent
2cabc5fb4e
commit
954c410c1b
6 changed files with 180 additions and 1 deletions
|
@ -32,6 +32,7 @@ uuid = { version = "0.8.1", features = ["v4"] } # for attaching input files
|
|||
derive_more = "0.99.9"
|
||||
mime = "0.3.16"
|
||||
thiserror = "1.0.20"
|
||||
once_cell = "1.4.0"
|
||||
|
||||
[features]
|
||||
# features those require nightly compiler
|
||||
|
|
155
src/bot/cache_me.rs
Normal file
155
src/bot/cache_me.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
use futures::{
|
||||
future,
|
||||
future::{ok, Ready},
|
||||
task::{Context, Poll},
|
||||
Future,
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::{
|
||||
payloads::GetMe,
|
||||
requests::{HasPayload, Request, Requester},
|
||||
types::User,
|
||||
};
|
||||
|
||||
/// `get_me` cache.
|
||||
///
|
||||
/// Bot's user is hardly ever changed, so sometimes it's reasonable to cache
|
||||
/// response from `get_me` method.
|
||||
pub struct CacheMe<B> {
|
||||
bot: B,
|
||||
me: Arc<OnceCell<User>>,
|
||||
}
|
||||
|
||||
impl<B> CacheMe<B> {
|
||||
/// Creates new cache.
|
||||
///
|
||||
/// Note: it's recommended to use [`RequesterExt::cache_me`] instead.
|
||||
pub fn new(bot: B) -> CacheMe<B> {
|
||||
Self { bot, me: Arc::new(OnceCell::new()) }
|
||||
}
|
||||
|
||||
/// Allows to access inner bot
|
||||
pub fn inner(&self) -> &B {
|
||||
&self.bot
|
||||
}
|
||||
|
||||
/// Unwraps inner bot
|
||||
pub fn into_inner(self) -> B {
|
||||
self.bot
|
||||
}
|
||||
|
||||
/// Clear cache.
|
||||
///
|
||||
/// Returns cached response from `get_me`, if it was cached.
|
||||
///
|
||||
/// Note: internally this uses [`Arc::make_mut`] so this will **not**
|
||||
/// clear cache of clones of self.
|
||||
pub fn clear(&mut self) -> Option<User> {
|
||||
Arc::make_mut(&mut self.me).take()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Requester> Requester for CacheMe<B> {
|
||||
type GetMe = CachedMeRequest<B::GetMe>;
|
||||
|
||||
fn get_me(&self) -> Self::GetMe {
|
||||
match self.me.get() {
|
||||
Some(user) => CachedMeRequest(Inner::Ready(user.clone()), GetMe::new()),
|
||||
None => CachedMeRequest(
|
||||
Inner::Pending(self.bot.get_me(), Arc::clone(&self.me)),
|
||||
GetMe::new(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CachedMeRequest<R: Request<Payload = GetMe>>(Inner<R>, GetMe);
|
||||
|
||||
enum Inner<R: Request<Payload = GetMe>> {
|
||||
Ready(User),
|
||||
Pending(R, Arc<OnceCell<User>>),
|
||||
}
|
||||
|
||||
impl<R: Request<Payload = GetMe>> Request for CachedMeRequest<R> {
|
||||
type Err = R::Err;
|
||||
type Send = Send<R>;
|
||||
type SendRef = SendRef<R>;
|
||||
|
||||
fn send(self) -> Self::Send {
|
||||
let fut = match self.0 {
|
||||
Inner::Ready(user) => future::Either::Left(ok(user)),
|
||||
Inner::Pending(req, cell) => future::Either::Right(Init(req.send(), cell)),
|
||||
};
|
||||
Send(fut)
|
||||
}
|
||||
|
||||
fn send_ref(&self) -> Self::SendRef {
|
||||
let fut = match &self.0 {
|
||||
Inner::Ready(user) => future::Either::Left(ok(user.clone())),
|
||||
Inner::Pending(req, cell) => {
|
||||
future::Either::Right(Init(req.send_ref(), Arc::clone(cell)))
|
||||
}
|
||||
};
|
||||
SendRef(fut)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Request<Payload = GetMe>> HasPayload for CachedMeRequest<R> {
|
||||
type Payload = GetMe;
|
||||
|
||||
fn payload_mut(&mut self) -> &mut Self::Payload {
|
||||
&mut self.1
|
||||
}
|
||||
|
||||
fn payload_ref(&self) -> &Self::Payload {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
type ReadyUser<Err> = Ready<Result<User, Err>>;
|
||||
|
||||
#[pin_project::pin_project]
|
||||
pub struct Send<R: Request<Payload = GetMe>>(
|
||||
#[pin] future::Either<ReadyUser<R::Err>, Init<R::Send, User>>,
|
||||
);
|
||||
|
||||
impl<R: Request<Payload = GetMe>> Future for Send<R> {
|
||||
type Output = Result<User, R::Err>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.0.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
pub struct SendRef<R: Request<Payload = GetMe>>(
|
||||
#[pin] future::Either<ReadyUser<R::Err>, Init<R::SendRef, User>>,
|
||||
);
|
||||
|
||||
impl<R: Request<Payload = GetMe>> Future for SendRef<R> {
|
||||
type Output = Result<User, R::Err>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.0.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
struct Init<F, T>(#[pin] F, Arc<OnceCell<T>>);
|
||||
|
||||
impl<F: Future<Output = Result<T, E>>, T: Clone, E> Future for Init<F, T> {
|
||||
type Output = Result<T, E>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
match this.0.poll(cx) {
|
||||
Poll::Ready(Ok(ok)) => Poll::Ready(Ok(this.1.get_or_init(|| ok).clone())),
|
||||
poll @ Poll::Ready(_) | poll @ Poll::Pending => poll,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,8 +14,11 @@ use crate::{
|
|||
};
|
||||
|
||||
mod api;
|
||||
mod cache_me;
|
||||
mod download;
|
||||
|
||||
pub use cache_me::CacheMe;
|
||||
|
||||
pub(crate) const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN";
|
||||
pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY";
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub use crate::payloads::{GetMeSetters as _};
|
||||
pub use crate::payloads::GetMeSetters as _;
|
||||
|
|
|
@ -10,12 +10,14 @@ mod all;
|
|||
mod json;
|
||||
mod multipart;
|
||||
mod requester;
|
||||
mod requester_ext;
|
||||
mod utils;
|
||||
|
||||
pub use all::*;
|
||||
pub use json::JsonRequest;
|
||||
pub use multipart::MultipartRequest;
|
||||
pub use requester::Requester;
|
||||
pub use requester_ext::RequesterExt;
|
||||
|
||||
/// A type that is returned after making a request to Telegram.
|
||||
pub type ResponseResult<T> = Result<T, crate::RequestError>;
|
||||
|
|
18
src/requests/requester_ext.rs
Normal file
18
src/requests/requester_ext.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use crate::{bot::CacheMe, requests::Requester};
|
||||
|
||||
pub trait RequesterExt: Requester {
|
||||
/// Add `get_me` caching ability, see [`CacheMe`] for more.
|
||||
fn cache_me(self) -> CacheMe<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
CacheMe::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RequesterExt for T
|
||||
where
|
||||
T: Requester,
|
||||
{
|
||||
/* use default impls */
|
||||
}
|
Loading…
Add table
Reference in a new issue