enhanced ratelimiter
This commit is contained in:
parent
3028b1abfe
commit
b1c2c2b099
3 changed files with 112 additions and 59 deletions
54
Cargo.lock
generated
54
Cargo.lock
generated
|
@ -93,9 +93,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.3"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -103,9 +103,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.4"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenv"
|
name = "dotenv"
|
||||||
|
@ -235,15 +235,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.150"
|
version = "0.2.151"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.11"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
|
@ -278,9 +278,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.9"
|
version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
|
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
@ -335,15 +335,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.18.0"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.60"
|
version = "0.10.61"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
|
checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -373,9 +373,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.96"
|
version = "0.9.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
|
checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -495,15 +495,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.25"
|
version = "0.38.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -580,9 +580,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.39"
|
version = "2.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -604,18 +604,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.50"
|
version = "1.0.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.50"
|
version = "1.0.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -624,9 +624,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.34.0"
|
version = "1.35.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
|
checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
50
src/main.rs
50
src/main.rs
|
@ -6,11 +6,17 @@ use twitch_irc::SecureTCPTransport;
|
||||||
use twitch_irc::TwitchIRCClient;
|
use twitch_irc::TwitchIRCClient;
|
||||||
use twitch_irc::message::ServerMessage;
|
use twitch_irc::message::ServerMessage;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::time::Instant;
|
// use std::time::Instant;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
// mod helpers;
|
// mod helpers;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
||||||
|
mod ratelimiter;
|
||||||
|
use ratelimiter::RateLimiter;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
|
|
||||||
|
@ -47,7 +53,7 @@ pub async fn main() {
|
||||||
// client.join("modulatingforcebot".to_owned()).unwrap();
|
// client.join("modulatingforcebot".to_owned()).unwrap();
|
||||||
// client.say("modulatingforcebot".to_owned(), "Connected!".to_owned()).await.unwrap();
|
// client.say("modulatingforcebot".to_owned(), "Connected!".to_owned()).await.unwrap();
|
||||||
|
|
||||||
for chnl in botchannels {
|
for chnl in &botchannels {
|
||||||
client.join(chnl.to_owned()).unwrap();
|
client.join(chnl.to_owned()).unwrap();
|
||||||
// client.say(chnl.to_owned(), "Connected!".to_owned()).await.unwrap();
|
// client.say(chnl.to_owned(), "Connected!".to_owned()).await.unwrap();
|
||||||
client.say(chnl.to_owned(), "annytfLurk".to_owned()).await.unwrap();
|
client.say(chnl.to_owned(), "annytfLurk".to_owned()).await.unwrap();
|
||||||
|
@ -55,11 +61,16 @@ pub async fn main() {
|
||||||
|
|
||||||
// Adding rate limit functionality to be under : https://dev.twitch.tv/docs/irc/#rate-limits
|
// Adding rate limit functionality to be under : https://dev.twitch.tv/docs/irc/#rate-limits
|
||||||
|
|
||||||
let mut ratelimittimer = false.to_owned();
|
|
||||||
|
|
||||||
let mut ratelimitstart = Instant::now();
|
// ratelimiters are a hashmap of channel and a corresponding rate limiter
|
||||||
let mut ratelimitcounter = 0;
|
let mut ratelimiters:HashMap<String,RateLimiter> = HashMap::new();
|
||||||
|
|
||||||
|
for chnl in &botchannels {
|
||||||
|
let n = RateLimiter::new();
|
||||||
|
ratelimiters.insert(chnl.to_owned(),n);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}",ratelimiters);
|
||||||
|
|
||||||
let join_handle = tokio::spawn(async move {
|
let join_handle = tokio::spawn(async move {
|
||||||
while let Some(message) = incoming_messages.recv().await {
|
while let Some(message) = incoming_messages.recv().await {
|
||||||
|
@ -74,22 +85,12 @@ pub async fn main() {
|
||||||
}
|
}
|
||||||
ServerMessage::Privmsg(msg) => {
|
ServerMessage::Privmsg(msg) => {
|
||||||
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
|
println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
|
||||||
if !ratelimittimer {
|
|
||||||
println!("(#{}) > {}", msg.channel_login, "started rate limit timer");
|
|
||||||
// ratelimitstart = Instant::now();
|
|
||||||
// ratelimittimer = true;
|
|
||||||
( ratelimittimer , ratelimitstart ) = ( true , Instant::now() );
|
|
||||||
} else if ratelimittimer && ratelimitstart.elapsed().as_secs() < 30 && ratelimitcounter >= 20 {
|
|
||||||
// skip iteration if rate limit is being reached
|
|
||||||
println!("(#{}) > {}", msg.channel_login, "rate limit reached");
|
|
||||||
continue;
|
|
||||||
} else if ratelimitstart.elapsed().as_secs() >= 30 {
|
|
||||||
println!("(#{}) > {}", msg.channel_login, "rate limit timer reset");
|
|
||||||
// ratelimittimer = false;
|
|
||||||
// ratelimitcounter = 0;
|
|
||||||
( ratelimittimer , ratelimitcounter ) = ( false , 0 ) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
let contextratelimiter = ratelimiters.get_mut(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
|
||||||
|
|
||||||
|
match contextratelimiter.check_limiter() {
|
||||||
|
ratelimiter::LimiterResp::Allow => {
|
||||||
let maxblanks = rand::thread_rng().gen_range(1..=5);
|
let maxblanks = rand::thread_rng().gen_range(1..=5);
|
||||||
let mut outmsg = "GotTrolled ".to_owned();
|
let mut outmsg = "GotTrolled ".to_owned();
|
||||||
|
|
||||||
|
@ -100,8 +101,13 @@ pub async fn main() {
|
||||||
|
|
||||||
client.say_in_reply_to(&msg,outmsg).await.unwrap();
|
client.say_in_reply_to(&msg,outmsg).await.unwrap();
|
||||||
println!("(#{}) > {}", msg.channel_login, "rate limit counter increase");
|
println!("(#{}) > {}", msg.channel_login, "rate limit counter increase");
|
||||||
ratelimitcounter += 1;
|
contextratelimiter.increment_counter();
|
||||||
// client.say(msg.channel_login, "GotTrolled".to_owned()).await.unwrap();
|
println!("{:?}",ratelimiters);
|
||||||
|
},
|
||||||
|
ratelimiter::LimiterResp::Skip => {
|
||||||
|
(); // do nothing otherwise
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ServerMessage::Whisper(msg) => {
|
ServerMessage::Whisper(msg) => {
|
||||||
println!("(w) {}: {}", msg.sender.name, msg.message_text);
|
println!("(w) {}: {}", msg.sender.name, msg.message_text);
|
||||||
|
|
47
src/ratelimiter.rs
Normal file
47
src/ratelimiter.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
const TIME_THRESHOLD_S: u64 = 30;
|
||||||
|
const MSG_THRESHOLD: u32 = 20;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RateLimiter {
|
||||||
|
timer: Instant,
|
||||||
|
msgcounter: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LimiterResp {
|
||||||
|
Allow, // when it's evaluated to be within limits
|
||||||
|
Skip, // as outside of rate limits
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl RateLimiter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
timer: Instant::now(),
|
||||||
|
msgcounter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_limiter(&mut self) -> LimiterResp {
|
||||||
|
|
||||||
|
if self.timer.elapsed().as_secs() >= TIME_THRESHOLD_S {
|
||||||
|
// # [x] elapsed >= TIME_THRESHOLD_S
|
||||||
|
self.timer = Instant::now();
|
||||||
|
self.msgcounter = 0;
|
||||||
|
LimiterResp::Allow
|
||||||
|
} else if self.msgcounter < MSG_THRESHOLD {
|
||||||
|
// # [x] elapsed < TIME_THRESHOLD_S && msgcounter < MSG_THRESHOLD
|
||||||
|
LimiterResp::Allow
|
||||||
|
// } else if self.msgcounter >= MSG_THRESHOLD {
|
||||||
|
} else {
|
||||||
|
// # [x] elapsed < TIME_THRESHOLD_S && msgcounter >= MSG_THRESHOLD
|
||||||
|
LimiterResp::Skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_counter(&mut self) -> () {
|
||||||
|
self.msgcounter += 1;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue