From e16749e69a035498338bae570c1101e781de9111 Mon Sep 17 00:00:00 2001 From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:26:58 -0400 Subject: [PATCH] enh ratelimiters --- src/core/chat.rs | 15 +++++++++++++-- src/core/ratelimiter.rs | 40 +++++++++++++++++++++++++++++++++++---- src/custom/experiments.rs | 1 + 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/core/chat.rs b/src/core/chat.rs index 4720af7..fe49896 100644 --- a/src/core/chat.rs +++ b/src/core/chat.rs @@ -19,6 +19,8 @@ use crate::core::botinstance::ChType; use crate::core::botlog; pub use ChType::Channel; +use tokio::time::{sleep, Duration}; + #[derive(Clone)] pub struct Chat { pub ratelimiters: Arc>>, // used to limit messages sent per channel @@ -59,6 +61,11 @@ impl Chat { .get_mut(&Channel(String::from(&msg.channel_login))) .expect("ERROR: Issue with Rate limiters"); + // Continue to check the limiter and sleep if required if the minimum is not reached + while let ratelimiter::LimiterResp::Sleep(sleeptime) = contextratelimiter.check_limiter() { + sleep(Duration::from_secs_f64(sleeptime)).await; + } + match contextratelimiter.check_limiter() { ratelimiter::LimiterResp::Allow => { let maxblanks = rand::thread_rng().gen_range(1..=20); @@ -73,8 +80,8 @@ impl Chat { contextratelimiter.increment_counter(); let logstr = format!( - "(#{}) > {} ; Ratelimiers : {:?}", - msg.channel_login, "rate limit counter increase", self.ratelimiters + "(#{}) > {} ; contextratelimiter : {:?}", + msg.channel_login, "rate limit counter increase", contextratelimiter ); botlog::trace( @@ -86,7 +93,11 @@ impl Chat { ratelimiter::LimiterResp::Skip => { // (); // do nothing otherwise } + ratelimiter::LimiterResp::Sleep(_) => { + panic!("ISSUE : sleep was already awaited - Should not happen?"); + } } + Log::flush(); } diff --git a/src/core/ratelimiter.rs b/src/core/ratelimiter.rs index b43abba..6d256e8 100644 --- a/src/core/ratelimiter.rs +++ b/src/core/ratelimiter.rs @@ -1,18 +1,23 @@ const TIME_THRESHOLD_S: u64 = 30; +const TIME_MIN_S_F64: f64 = 1.0; const MSG_THRESHOLD: u32 = 20; use std::time::Instant; +use crate::core::botlog; #[derive(Debug, Clone)] pub struct RateLimiter { timer: Instant, msgcounter: u32, + lastmsgtimer : Instant, } +#[derive(Debug)] pub enum LimiterResp { Allow, // when it's evaluated to be within limits Skip, // as outside of rate limits // Enqueue, // [FUTURE] + Sleep(f64), // Sleep for x seconds } impl Default for RateLimiter { @@ -26,23 +31,50 @@ impl RateLimiter { Self { timer: Instant::now(), msgcounter: 0, + lastmsgtimer: Instant::now(), } } pub fn check_limiter(&mut self) -> LimiterResp { - if self.timer.elapsed().as_secs() >= TIME_THRESHOLD_S { + + + let logstr = format!( + ">> RateLimiter > {:?}",self + ); + + botlog::trace( + logstr.as_str(), + Some("Rate Limiter Inner".to_string()), + None, + ); + + + let rsp = if self.timer.elapsed().as_secs() >= TIME_THRESHOLD_S { self.timer = Instant::now(); self.msgcounter = 0; LimiterResp::Allow - } else if self.msgcounter < MSG_THRESHOLD { + } else if self.msgcounter < MSG_THRESHOLD && + self.lastmsgtimer.elapsed().as_secs_f64() >= TIME_MIN_S_F64 { LimiterResp::Allow } else { // when elapsed() < TIME_THRESHOLD_S && msgcounter >= MSG_THRESHOLD - LimiterResp::Skip - } + // LimiterResp::Skip + LimiterResp::Sleep(TIME_MIN_S_F64 - self.lastmsgtimer.elapsed().as_secs_f64()) + }; + + botlog::trace( + &format!("Limiter Response : {:?} ; Elapsed (as_sec_f64) : {}", + rsp, self.lastmsgtimer.elapsed().as_secs_f64()), + Some("Rate Limiter Inner".to_string()), + None, + ); + + rsp + } pub fn increment_counter(&mut self) { self.msgcounter += 1; + self.lastmsgtimer = Instant::now(); } } diff --git a/src/custom/experiments.rs b/src/custom/experiments.rs index 8b1bece..cda042d 100644 --- a/src/custom/experiments.rs +++ b/src/custom/experiments.rs @@ -66,6 +66,7 @@ async fn good_girl(bot: BotAR, msg: PrivmsgMessage) { if msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase() || msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() + // if msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() { botlog::debug( "Good Girl Detected > Pausechamp",