rusty-rl 0.1.0

simple ratelimit helper
Documentation
use std::{
    collections::HashMap,
    iter::Inspect,
    time::{Duration, Instant},
};

use crate::{FixedBucket, Selfb};

/// fixed bucket
///
/// ```
///     let b = FixedBucket::new(600, 10).bucket(90, 10.0)
/// ```
impl FixedBucket {
    pub fn new(total_request: u64, minutes: u64) -> Self {
        FixedBucket {
            request: total_request,
            duration: Duration::from_secs(minutes * 60),
            capacity: 0,
            rates: 0.0,
            last_update: HashMap::new(),
            requests: HashMap::new(),
        }
    }
    pub fn bucket(self, capacity: u64, rates: f64) -> Self {
        let rates = rates / 1000.0;
        FixedBucket {
            request: self.request,
            duration: self.duration,
            capacity: capacity,
            rates: rates,
            last_update: self.last_update,
            requests: self.requests,
        }
    }
    fn bucket_update(&mut self, key: String) {
        let now = Instant::now();
        let (tokens, b) = self.last_update.entry(key).or_insert((0.0, now));
        println!("{}", tokens);
        let current_time = now.duration_since(*b).as_millis();
        let token = (self.rates * current_time as f64).ceil();
        *tokens = (*tokens + token).min(self.capacity as f64);
        *b = now;
    }
    fn fixed_bucket(&mut self, key: String) -> bool {
        let now = Instant::now();
        let (tokens, b) = self.requests.entry(key).or_insert((0, now));
        let current = now.duration_since(*b);
        // println!("{:?} {:?} {:?} {}", b, current, self.duration, tokens);
        if current > self.duration {
            *b = now;
            *tokens = 0;
        }
        if *tokens <= self.request {
            *tokens += 1;
            true
        } else {
            false
        }
    }
    pub fn allow(&mut self, ip: impl Into<String> + Copy, token: f64) -> Selfb {
        let ip = ip.into();
        let request = self.fixed_bucket(ip.clone());
        if request {
            self.bucket_update(ip.clone());
            let (tokens, _) = self.last_update.get_mut(&ip).unwrap();
            if *tokens >= token {
                *tokens -= token;
                Selfb {
                    is_allowed: true,
                    remaning_count: *tokens as u64,
                }
            } else {
                Selfb {
                    is_allowed: false,
                    remaning_count: *tokens as u64,
                }
            }
        } else {
            Selfb {
                is_allowed: false,
                remaning_count: 0,
            }
        }
    }
}