Merge pull request 'Enh RateLimiters with Async Sleep' (#25) from chat_async_sleep into main
All checks were successful
ci/woodpecker/push/cargo-checks Pipeline was successful
All checks were successful
ci/woodpecker/push/cargo-checks Pipeline was successful
Reviewed-on: #25
This commit is contained in:
commit
53c5780322
3 changed files with 50 additions and 6 deletions
|
@ -19,6 +19,8 @@ use crate::core::botinstance::ChType;
|
||||||
use crate::core::botlog;
|
use crate::core::botlog;
|
||||||
pub use ChType::Channel;
|
pub use ChType::Channel;
|
||||||
|
|
||||||
|
use tokio::time::{sleep, Duration};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Chat {
|
pub struct Chat {
|
||||||
pub ratelimiters: Arc<Mutex<HashMap<ChType, RateLimiter>>>, // used to limit messages sent per channel
|
pub ratelimiters: Arc<Mutex<HashMap<ChType, RateLimiter>>>, // used to limit messages sent per channel
|
||||||
|
@ -59,6 +61,11 @@ impl Chat {
|
||||||
.get_mut(&Channel(String::from(&msg.channel_login)))
|
.get_mut(&Channel(String::from(&msg.channel_login)))
|
||||||
.expect("ERROR: Issue with Rate limiters");
|
.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() {
|
match contextratelimiter.check_limiter() {
|
||||||
ratelimiter::LimiterResp::Allow => {
|
ratelimiter::LimiterResp::Allow => {
|
||||||
let maxblanks = rand::thread_rng().gen_range(1..=20);
|
let maxblanks = rand::thread_rng().gen_range(1..=20);
|
||||||
|
@ -73,8 +80,8 @@ impl Chat {
|
||||||
contextratelimiter.increment_counter();
|
contextratelimiter.increment_counter();
|
||||||
|
|
||||||
let logstr = format!(
|
let logstr = format!(
|
||||||
"(#{}) > {} ; Ratelimiers : {:?}",
|
"(#{}) > {} ; contextratelimiter : {:?}",
|
||||||
msg.channel_login, "rate limit counter increase", self.ratelimiters
|
msg.channel_login, "rate limit counter increase", contextratelimiter
|
||||||
);
|
);
|
||||||
|
|
||||||
botlog::trace(
|
botlog::trace(
|
||||||
|
@ -86,7 +93,11 @@ impl Chat {
|
||||||
ratelimiter::LimiterResp::Skip => {
|
ratelimiter::LimiterResp::Skip => {
|
||||||
// (); // do nothing otherwise
|
// (); // do nothing otherwise
|
||||||
}
|
}
|
||||||
|
ratelimiter::LimiterResp::Sleep(_) => {
|
||||||
|
panic!("ISSUE : sleep was already awaited - Should not happen?");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::flush();
|
Log::flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
const TIME_THRESHOLD_S: u64 = 30;
|
const TIME_THRESHOLD_S: u64 = 30;
|
||||||
|
const TIME_MIN_S_F64: f64 = 1.0;
|
||||||
const MSG_THRESHOLD: u32 = 20;
|
const MSG_THRESHOLD: u32 = 20;
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use crate::core::botlog;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RateLimiter {
|
pub struct RateLimiter {
|
||||||
timer: Instant,
|
timer: Instant,
|
||||||
msgcounter: u32,
|
msgcounter: u32,
|
||||||
|
lastmsgtimer : Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum LimiterResp {
|
pub enum LimiterResp {
|
||||||
Allow, // when it's evaluated to be within limits
|
Allow, // when it's evaluated to be within limits
|
||||||
Skip, // as outside of rate limits
|
Skip, // as outside of rate limits
|
||||||
// Enqueue, // [FUTURE]
|
// Enqueue, // [FUTURE]
|
||||||
|
Sleep(f64), // Sleep for x seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RateLimiter {
|
impl Default for RateLimiter {
|
||||||
|
@ -26,23 +31,50 @@ impl RateLimiter {
|
||||||
Self {
|
Self {
|
||||||
timer: Instant::now(),
|
timer: Instant::now(),
|
||||||
msgcounter: 0,
|
msgcounter: 0,
|
||||||
|
lastmsgtimer: Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_limiter(&mut self) -> LimiterResp {
|
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.timer = Instant::now();
|
||||||
self.msgcounter = 0;
|
self.msgcounter = 0;
|
||||||
LimiterResp::Allow
|
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
|
LimiterResp::Allow
|
||||||
} else {
|
} else {
|
||||||
// when elapsed() < TIME_THRESHOLD_S && msgcounter >= MSG_THRESHOLD
|
// 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) {
|
pub fn increment_counter(&mut self) {
|
||||||
self.msgcounter += 1;
|
self.msgcounter += 1;
|
||||||
|
self.lastmsgtimer = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ async fn good_girl(bot: BotAR, msg: PrivmsgMessage) {
|
||||||
|
|
||||||
if msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
|
if msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase()
|
||||||
|| msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
|
|| msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
|
||||||
|
// if msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase()
|
||||||
{
|
{
|
||||||
botlog::debug(
|
botlog::debug(
|
||||||
"Good Girl Detected > Pausechamp",
|
"Good Girl Detected > Pausechamp",
|
||||||
|
|
Loading…
Reference in a new issue