use std::sync::atomic::{AtomicU64, Ordering};
pub const HOURLY_LIMIT: u64 = 5000;
pub const WARN_BELOW: u64 = 1500;
pub const SLOW_BELOW_PERCENT: u64 = 20;
pub const STOP_BELOW_PERCENT: u64 = 5;
const UNKNOWN: u64 = u64::MAX;
static REMAINING: AtomicU64 = AtomicU64::new(UNKNOWN);
pub fn note(remaining: u64) {
REMAINING.store(remaining, Ordering::Relaxed);
}
pub fn remaining() -> Option<u64> {
let r = REMAINING.load(Ordering::Relaxed);
(r != UNKNOWN).then_some(r)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Throttle {
Normal,
Slow,
Stop,
}
pub fn throttle_for(remaining: Option<u64>) -> Throttle {
let percent_of_limit = |r: u64| r * 100 / HOURLY_LIMIT;
match remaining {
Some(r) if percent_of_limit(r) < STOP_BELOW_PERCENT => Throttle::Stop,
Some(r) if percent_of_limit(r) < SLOW_BELOW_PERCENT => Throttle::Slow,
_ => Throttle::Normal,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn thresholds() {
assert_eq!(throttle_for(None), Throttle::Normal);
assert_eq!(throttle_for(Some(5000)), Throttle::Normal);
assert_eq!(throttle_for(Some(1000)), Throttle::Normal); assert_eq!(throttle_for(Some(999)), Throttle::Slow);
assert_eq!(throttle_for(Some(250)), Throttle::Slow); assert_eq!(throttle_for(Some(249)), Throttle::Stop);
assert_eq!(throttle_for(Some(0)), Throttle::Stop);
}
}