use reqwest::Client as HTTP;
pub struct Client(rate_limit::Ratelimit<HTTP>);
impl Client {
pub fn new() -> Self {
Self(rate_limit::Ratelimit::new(
HTTP::new(),
1,
std::time::Duration::from_secs(2),
))
}
pub(crate) async fn borrow<'a>(&'a self) -> impl std::ops::Deref<Target = HTTP> + 'a {
self.0.borrow().await
}
}
mod rate_limit {
use std::time::Duration;
use flume::{bounded as channel, Receiver, Sender};
use std::ops::Deref;
pub struct Ratelimit<T> {
inner: T,
recv: Receiver<()>,
send: Sender<()>,
wait_time: Duration,
}
struct RatelimitGuard<'a, T> {
inner: &'a T,
send: &'a Sender<()>,
wait_time: &'a Duration,
}
impl<T> Ratelimit<T> {
pub fn new(inner: T, count: usize, wait_time: Duration) -> Self {
let (send, recv) = channel(count);
(0..count).for_each(|_| {
send.send(()).ok();
});
Self {
inner,
send,
recv,
wait_time,
}
}
pub async fn borrow<'a>(&'a self) -> impl Deref<Target = T> + 'a {
self.recv.recv_async().await.unwrap();
RatelimitGuard {
inner: &self.inner,
send: &self.send,
wait_time: &self.wait_time,
}
}
}
impl<'a, T> Deref for RatelimitGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<'a, T> Drop for RatelimitGuard<'a, T> {
fn drop(&mut self) {
let send = self.send.clone();
let wait_time = self.wait_time.clone();
tokio::spawn(async move {
tokio::time::sleep(wait_time).await;
send.send_async(()).await.ok();
});
}
}
}