use maxbot::{MaxClient, SendMessageParamsBuilder, set_global_max_rps, set_global_base_url};
use std::time::{Duration, Instant};
use std::env;
#[tokio::main]
async fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <rps> [token] [chat_id]", args[0]);
eprintln!(" rps - requests per second (positive integer)");
eprintln!(" token - optional, fallback to MAXBOT_TOKEN env var");
eprintln!(" chat_id - optional, fallback to CHAT_ID env var");
std::process::exit(1);
}
let rps: usize = match args[1].parse() {
Ok(v) if v > 0 => v,
_ => {
eprintln!("Invalid RPS, must be positive integer");
std::process::exit(1);
}
};
let token = if args.len() >= 3 {
args[2].clone()
} else {
match env::var("MAXBOT_TOKEN") {
Ok(v) => v,
Err(_) => {
eprintln!("Missing MAXBOT_TOKEN (neither argument nor env)");
std::process::exit(1);
}
}
};
let chat_id: i64 = if args.len() >= 4 {
match args[3].parse() {
Ok(v) => v,
Err(_) => {
eprintln!("Invalid CHAT_ID argument");
std::process::exit(1);
}
}
} else {
match env::var("CHAT_ID") {
Ok(v) => match v.parse() {
Ok(id) => id,
Err(_) => {
eprintln!("Invalid CHAT_ID in environment");
std::process::exit(1);
}
},
Err(_) => {
eprintln!("Missing CHAT_ID (neither argument nor env)");
std::process::exit(1);
}
}
};
if let Ok(proxy_url) = env::var("MAXBOT_PROXY") {
println!("Using proxy base URL: {}", proxy_url);
set_global_base_url(proxy_url);
}
set_global_max_rps(rps);
println!("Starting stress test with {} requests per second.", rps);
println!("Sending messages to chat {}...", chat_id);
let client = MaxClient::new(token);
let interval = Duration::from_millis(1000 / rps as u64);
let mut msg_counter = 0;
let start_time = Instant::now();
loop {
msg_counter += 1;
let text = format!("Stress test message #{}", msg_counter);
let builder = SendMessageParamsBuilder::new()
.text(text)
.chat_id(chat_id)
.silent();
let before = Instant::now();
let result = client.send_message_builder(builder).await;
let elapsed = before.elapsed();
match result {
Ok(ids) => {
let mid = ids.first().unwrap();
print!("\rSent #{} (mid={}, took {} ms)", msg_counter, mid, elapsed.as_millis());
tokio::time::sleep(interval).await;
}
Err(e) => {
let err_str = e.to_string();
if err_str.contains("429") || err_str.contains("too.many.requests") {
let total_sec = start_time.elapsed().as_secs_f64();
let successful = msg_counter - 1;
println!("\n\nRate limit hit after {} successful messages.", successful);
println!("Error: {}", err_str);
println!("Test finished. Sent {} messages in {:.2} seconds (avg {:.2} msg/sec).",
successful, total_sec, successful as f64 / total_sec);
return;
} else {
eprintln!("\nUnexpected error: {}", err_str);
std::process::exit(1);
}
}
}
}
}