rust-mc-status 3.0.0

High-performance asynchronous Rust library for querying Minecraft server status (Java & Bedrock)
Documentation
//! Cache management example for the rust-mc-status library.
//!
//! Demonstrates DNS/SRV and response cache behaviour:
//! - Viewing cache statistics
//! - Cache warm-up and hit behaviour
//! - Clearing caches
//! - Performance impact of caching
//!
//! Run with:
//!   cargo run --example cache_management

use rust_mc_status::{McClient, StatusExt};
use std::time::{Duration, Instant};

fn sep() {
    println!("\n{}\n", "".repeat(50));
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Cache Management ===\n");

    // ═══════════════════════════════════════════════════════════
    //  ЧАСТЬ 1 — DNS / SRV кэш
    // ═══════════════════════════════════════════════════════════

    println!("── DNS / SRV cache ──────────────────────────────\n");

    let client = McClient::builder()
        .timeout(Duration::from_secs(15))
        .dns_cache_size(512) // default: 1024
        .build();

    // ─── 1. Initial state ─────────────────────────────────────

    println!("1. Initial cache state (empty)");
    let stats = client.cache_stats().await;
    println!("   DNS entries      : {}", stats.dns_entries);
    println!("   SRV entries      : {}", stats.srv_entries);
    println!("   Response entries : {}", stats.response_entries);

    // ─── 2. Populate DNS cache ────────────────────────────────

    println!("\n2. Pinging servers to populate DNS cache…");
    let t0 = Instant::now();
    let _  = client.java("mc.hypixel.net").await;
    let first_ping = t0.elapsed();

    let _ = client.bedrock("geo.hivebedrock.network:19132").await;

    let stats = client.cache_stats().await;
    println!("   After 2 pings:");
    println!("   DNS entries : {}", stats.dns_entries);
    println!("   SRV entries : {}", stats.srv_entries);
    println!("   First ping  : {:.0} ms (includes DNS + network)", first_ping.as_millis());

    // ─── 3. DNS cache hit ─────────────────────────────────────
    //
    // DNS resolved from cache — saves ~10–50 ms per request.
    // Network latency still applies.

    println!("\n3. Repeat ping (DNS from cache, network still happens)");
    let t1 = Instant::now();
    let _  = client.java("mc.hypixel.net").await;
    let cached_ping = t1.elapsed();
    let saved = first_ping.saturating_sub(cached_ping);
    println!("   Cached ping : {:.0} ms", cached_ping.as_millis());
    println!("   Saved       : ~{:.0} ms (DNS lookup avoided)", saved.as_millis());

    // ─── 4. Clear DNS cache ───────────────────────────────────

    println!("\n4. Clearing DNS/SRV caches");
    client.clear_caches().await;
    let stats = client.cache_stats().await;
    println!("   DNS entries : {} (cleared)", stats.dns_entries);
    println!("   SRV entries : {} (cleared)", stats.srv_entries);

    sep();

    // ═══════════════════════════════════════════════════════════
    //  ЧАСТЬ 2 — Response кэш
    // ═══════════════════════════════════════════════════════════

    println!("── Response cache ───────────────────────────────\n");

    // Response кэш возвращает полный ServerStatus мгновенно —
    // никакого сетевого запроса, 0 ms.
    // TTL задаёт как долго результат считается свежим.

    let client = McClient::builder()
        .timeout(Duration::from_secs(15))
        .response_cache(Duration::from_secs(60), 100)
        // ↑ TTL = 60 s, LRU capacity = 100 servers
        .build();

    // ─── 5. Первый пинг — живой запрос ───────────────────────

    println!("5. First ping — live request (cache miss)");
    let t2 = Instant::now();
    match client.java("mc.hypixel.net").await {
        Ok(s) => {
            let elapsed = t2.elapsed();
            println!("{} ms — {} — cached: {}", elapsed.as_millis(), s.display_players(), s.is_cached());
        }
        Err(e) => println!("{e}"),
    }

    let stats = client.cache_stats().await;
    println!("   Response entries : {} (populated)", stats.response_entries);

    // ─── 6. Второй пинг — из response кэша ───────────────────

    println!("\n6. Second ping — instant response (cache hit)");
    let t3 = Instant::now();
    match client.java("mc.hypixel.net").await {
        Ok(s) => {
            let elapsed = t3.elapsed();
            println!("{} ms — {} — cached: {}", elapsed.as_millis(), s.display_players(), s.is_cached());
            if s.is_cached() {
                println!("   ⚡ Returned from cache instantly — no network request");
            }
        }
        Err(e) => println!("{e}"),
    }

    // ─── 7. Несколько серверов ────────────────────────────────

    println!("\n7. Caching multiple servers");
    let servers = ["mc.hypixel.net", "mc.mineplex.com"];

    for server in &servers {
        let _ = client.java(*server).await;
    }

    let stats = client.cache_stats().await;
    println!("   Response entries : {}", stats.response_entries);

    // Все повторные пинги — мгновенные
    for server in &servers {
        let t = Instant::now();
        match client.java(*server).await {
            Ok(s)  => println!("   {}{} ms (cached: {})", server, t.elapsed().as_millis(), s.is_cached()),
            Err(e) => println!("   {} → ❌ {e}", server),
        }
    }

    // ─── 8. Сброс только response кэша ───────────────────────

    println!("\n8. Clear response cache only");
    client.clear_response_cache().await;
    let stats = client.cache_stats().await;
    println!("   Response entries : {} (cleared)", stats.response_entries);
    println!("   DNS entries      : {} (untouched)", stats.dns_entries);

    // После сброса — снова живой запрос, но DNS всё ещё в кэше
    println!("\n9. Ping after response cache clear (live again, DNS still cached)");
    let t4 = Instant::now();
    match client.java("mc.hypixel.net").await {
        Ok(s) => {
            println!("{} ms — cached: {} (DNS was still cached → faster than first ping)",
                t4.elapsed().as_millis(), s.is_cached());
        }
        Err(e) => println!("{e}"),
    }

    // ─── Summary ──────────────────────────────────────────────

    sep();
    println!("Summary:\n");
    println!("  ┌─────────────────┬──────────────────────────────────────────┐");
    println!("  │ Кэш             │ Что ускоряет                             │");
    println!("  ├─────────────────┼──────────────────────────────────────────┤");
    println!("  │ DNS/SRV         │ Резолвинг хоста (~10–50 ms)              │");
    println!("  │ Response        │ Весь пинг (~0 ms, возвращает старый TTL) │");
    println!("  └─────────────────┴──────────────────────────────────────────┘");
    println!();
    println!("  DNS TTL          : 5 минут (автоматическое истечение)");
    println!("  Response TTL     : задаётся через with_response_cache_ttl()");
    println!("  clear_caches()          → сбрасывает DNS + SRV");
    println!("  clear_response_cache()  → сбрасывает только response");
    println!("  Клонированные клиенты   → разделяют один Arc<> кэш");

    Ok(())
}