use rust_mc_status::{McClient, ServerEdition, ServerInfo};
use std::time::{Duration, Instant};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Performance Test for rust-mc-status ===\n");
let client = McClient::new()
.with_timeout(Duration::from_secs(10))
.with_max_parallel(10);
let test_servers = vec![
("mc.hypixel.net", ServerEdition::Java),
("geo.hivebedrock.network:19132", ServerEdition::Bedrock),
];
println!("Test Configuration:");
println!(" Timeout: 10 seconds");
println!(" Max parallel: 10");
println!(" Test servers: {} servers\n", test_servers.len());
println!("{}", "=".repeat(70));
println!();
println!("Test 1: Single Server Ping (Cold Cache)");
println!("{}", "-".repeat(70));
for (address, edition) in &test_servers {
let start = Instant::now();
match client.ping(address, *edition).await {
Ok(status) => {
let elapsed = start.elapsed();
println!(
" Server: {} ({:?})",
address,
edition
);
println!(" Status: ✅ Online");
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Server latency: {:.2} ms", status.latency);
println!(" DNS + Connection overhead: {:.2} ms",
elapsed.as_secs_f64() * 1000.0 - status.latency);
}
Err(e) => {
let elapsed = start.elapsed();
println!(" Server: {} ({:?})", address, edition);
println!(" Status: ❌ Error: {}", e);
println!(" Time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
}
}
println!();
}
println!("{}", "=".repeat(70));
println!();
println!("Test 2: Single Server Ping (Warm Cache)");
println!("{}", "-".repeat(70));
for (address, edition) in &test_servers {
let start = Instant::now();
match client.ping(address, *edition).await {
Ok(status) => {
let elapsed = start.elapsed();
println!(
" Server: {} ({:?})",
address,
edition
);
println!(" Status: ✅ Online");
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Server latency: {:.2} ms", status.latency);
println!(" DNS + Connection overhead: {:.2} ms",
elapsed.as_secs_f64() * 1000.0 - status.latency);
println!(" Cache hit: ✅ (DNS and SRV records cached)");
}
Err(e) => {
let elapsed = start.elapsed();
println!(" Server: {} ({:?})", address, edition);
println!(" Status: ❌ Error: {}", e);
println!(" Time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
}
}
println!();
}
println!("{}", "=".repeat(70));
println!();
println!("Test 3: Batch Ping Performance");
println!("{}", "-".repeat(70));
let servers: Vec<ServerInfo> = test_servers
.iter()
.map(|(address, edition)| ServerInfo {
address: address.to_string(),
edition: *edition,
})
.collect();
println!(" Servers: {}", servers.len());
println!(" Max parallel: {}\n", client.max_parallel());
let start = Instant::now();
let results = client.ping_many(&servers).await;
let elapsed = start.elapsed();
let successful = results.iter().filter(|(_, r)| r.is_ok()).count();
let failed = results.len() - successful;
println!(" Results:");
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Successful: {}/{}", successful, servers.len());
println!(" Failed: {}", failed);
println!(" Average time per server: {:.2} ms",
elapsed.as_secs_f64() * 1000.0 / servers.len() as f64);
if successful > 0 {
let avg_latency: f64 = results
.iter()
.filter_map(|(_, r)| r.as_ref().ok())
.map(|s| s.latency)
.sum::<f64>() / successful as f64;
println!(" Average server latency: {:.2} ms", avg_latency);
}
println!();
println!("{}", "=".repeat(70));
println!();
println!("Test 4: SRV Lookup Performance");
println!("{}", "-".repeat(70));
let java_server = "mc.hypixel.net";
println!(" Test A: Without port (SRV lookup enabled)");
let start = Instant::now();
match client.ping_java(java_server).await {
Ok(status) => {
let elapsed = start.elapsed();
println!(" Server: {}", java_server);
println!(" Status: ✅ Online");
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Port used: {}", status.port);
}
Err(e) => {
let elapsed = start.elapsed();
println!(" Server: {}", java_server);
println!(" Status: ❌ Error: {}", e);
println!(" Time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
}
}
println!();
println!(" Test B: With port (SRV lookup disabled)");
let start = Instant::now();
match client.ping_java(&format!("{}:25565", java_server)).await {
Ok(status) => {
let elapsed = start.elapsed();
println!(" Server: {}:25565", java_server);
println!(" Status: ✅ Online");
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Port used: {}", status.port);
}
Err(e) => {
let elapsed = start.elapsed();
println!(" Server: {}:25565", java_server);
println!(" Status: ❌ Error: {}", e);
println!(" Time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
}
}
println!();
println!("{}", "=".repeat(70));
println!();
println!("Test 5: Concurrent Requests Performance");
println!("{}", "-".repeat(70));
let concurrent_tests = vec![1, 5, 10, 20];
for ¶llel in &concurrent_tests {
let test_client = McClient::new()
.with_timeout(Duration::from_secs(10))
.with_max_parallel(parallel);
println!(" Max parallel: {}", parallel);
let start = Instant::now();
let results = test_client.ping_many(&servers).await;
let elapsed = start.elapsed();
let successful = results.iter().filter(|(_, r)| r.is_ok()).count();
println!(" Servers: {}", servers.len());
println!(" Successful: {}/{}", successful, servers.len());
println!(" Total time: {:.2} ms", elapsed.as_secs_f64() * 1000.0);
println!(" Time per server: {:.2} ms",
elapsed.as_secs_f64() * 1000.0 / servers.len() as f64);
println!();
}
println!("{}", "=".repeat(70));
println!();
println!("Test 6: Stress Test (10 iterations)");
println!("{}", "-".repeat(70));
let iterations = 10;
let mut times = Vec::new();
let mut latencies = Vec::new();
for i in 1..=iterations {
let start = Instant::now();
match client.ping(test_servers[0].0, test_servers[0].1).await {
Ok(status) => {
let elapsed = start.elapsed();
times.push(elapsed.as_secs_f64() * 1000.0);
latencies.push(status.latency);
if i % 5 == 0 {
println!(" Iteration {}/{}: {:.2} ms (latency: {:.2} ms)",
i, iterations, elapsed.as_secs_f64() * 1000.0, status.latency);
}
}
Err(e) => {
let elapsed = start.elapsed();
times.push(elapsed.as_secs_f64() * 1000.0);
println!(" Iteration {}/{}: Error - {} ({:.2} ms)",
i, iterations, e, elapsed.as_secs_f64() * 1000.0);
}
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
if !times.is_empty() {
let avg_time = times.iter().sum::<f64>() / times.len() as f64;
let min_time = times.iter().fold(f64::INFINITY, |a, &b| a.min(b));
let max_time = times.iter().fold(0.0_f64, |a, &b| a.max(b));
println!();
println!(" Statistics:");
println!(" Average time: {:.2} ms", avg_time);
println!(" Min time: {:.2} ms", min_time);
println!(" Max time: {:.2} ms", max_time);
if !latencies.is_empty() {
let avg_latency = latencies.iter().sum::<f64>() / latencies.len() as f64;
let min_latency = latencies.iter().fold(f64::INFINITY, |a, &b| a.min(b));
let max_latency = latencies.iter().fold(0.0_f64, |a, &b| a.max(b));
println!(" Average latency: {:.2} ms", avg_latency);
println!(" Min latency: {:.2} ms", min_latency);
println!(" Max latency: {:.2} ms", max_latency);
}
}
println!();
println!("{}", "=".repeat(70));
println!();
println!("Test 7: Cache Statistics");
println!("{}", "-".repeat(70));
let stats = client.cache_stats();
println!(" DNS cache entries: {}", stats.dns_entries);
println!(" SRV cache entries: {}", stats.srv_entries);
println!(" Total cache entries: {}", stats.dns_entries + stats.srv_entries);
println!();
println!(" Clearing all caches...");
client.clear_all_caches();
let stats_after = client.cache_stats();
println!(" After clearing:");
println!(" DNS cache entries: {}", stats_after.dns_entries);
println!(" SRV cache entries: {}", stats_after.srv_entries);
println!();
println!("{}", "=".repeat(70));
println!();
println!("Performance test completed!");
println!();
println!("Tips for better performance:");
println!(" - Use batch queries (ping_many) for multiple servers");
println!(" - Adjust max_parallel based on your needs");
println!(" - DNS and SRV records are cached for 5 minutes");
println!(" - Use explicit ports to skip SRV lookup if not needed");
println!(" - Run with --release flag for optimal performance");
println!(" - Use clear_all_caches() to free memory or force fresh lookups");
Ok(())
}