rust-mc-status 2.0.0

High-performance asynchronous Rust library for querying Minecraft server status (Java & Bedrock)
Documentation
# Rust Minecraft Server Status Library

[![Crates.io](https://img.shields.io/crates/v/rust-mc-status)](https://crates.io/crates/rust-mc-status)
[![Documentation](https://docs.rs/rust-mc-status/badge.svg)](https://docs.rs/rust-mc-status)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

A high-performance, asynchronous Rust library for querying the status of both Minecraft Java Edition and Bedrock Edition servers.

## Features

*   **Dual Protocol Support**: Ping both Minecraft Java Edition (`25565`) and Bedrock Edition (`19132`) servers
*   **Async/Await**: Built on Tokio for non-blocking operations and high concurrency
*   **Batch Queries**: Ping multiple servers in parallel with configurable concurrency limits
*   **DNS Caching**: Automatically caches DNS lookups and SRV records to reduce latency for repeated queries
*   **SRV Record Support**: Automatically resolves SRV records for Java servers (mimics Minecraft client behavior)
*   **Structured Data**: Returns richly structured, serializable data (using `serde`), including version info, player counts, MOTD, map, gamemode, plugins, mods and more
*   **Favicon Handling**: Easily retrieve and save server favicons (Java Edition only)
*   **Robust Error Handling**: Comprehensive error types using `thiserror`
*   **Extended Information**: Detailed data about plugins, mods, DNS and more
*   **High Performance**: Optimized with connection pooling, DNS caching, and efficient memory usage

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
rust-mc-status = "2.0.0"
tokio = { version = "*", features = ["full"] }
```

## Quick Start

### Basic Usage

```rust
use rust_mc_status::{McClient, ServerEdition};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = McClient::new()
        .with_timeout(Duration::from_secs(5))
        .with_max_parallel(10);

    // Ping a Java server (automatically uses SRV lookup if port not specified)
    let status = client.ping("mc.hypixel.net", ServerEdition::Java).await?;
    println!("Server is online: {}", status.online);
    println!("Latency: {:.2} ms", status.latency);

    if let Some((online, max)) = status.players() {
        println!("Players: {}/{}", online, max);
    }

    Ok(())
}
```

### Batch Queries

```rust
use rust_mc_status::{McClient, ServerEdition, ServerInfo};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = McClient::new();
    let servers = vec![
        ServerInfo {
            address: "mc.hypixel.net".to_string(),
            edition: ServerEdition::Java,
        },
        ServerInfo {
            address: "geo.hivebedrock.network:19132".to_string(),
            edition: ServerEdition::Bedrock,
        },
    ];

    let results = client.ping_many(&servers).await;
    for (server, result) in results {
        match result {
            Ok(status) => println!("{}: Online ({}ms)", server.address, status.latency),
            Err(e) => println!("{}: Error - {}", server.address, e),
        }
    }
    
    Ok(())
}
```

## SRV Record Lookup

When pinging Java servers without an explicit port, the library automatically performs an SRV DNS lookup for `_minecraft._tcp.{hostname}`. This mimics the behavior of the official Minecraft client.

### How It Works

1. **Without explicit port** (e.g., `"mc.hypixel.net"`):
   - Queries `_minecraft._tcp.mc.hypixel.net` for SRV records
   - If found, uses the target host and port from the SRV record
   - If not found, uses the default port (25565)
   - Results are cached for 5 minutes

2. **With explicit port** (e.g., `"mc.hypixel.net:25565"`):
   - Skips SRV lookup entirely
   - Uses the specified host and port directly

### Example

```rust
use rust_mc_status::{McClient, ServerEdition};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = McClient::new();

    // This will perform SRV lookup for _minecraft._tcp.example.com
    let status = client.ping("example.com", ServerEdition::Java).await?;

    // This will skip SRV lookup and use port 25565 directly
    let status = client.ping("example.com:25565", ServerEdition::Java).await?;

    Ok(())
}
```

## Examples

The library includes several example programs:

*   **`basic_usage.rs`** - Basic server status queries and error handling
*   **`advanced_usage.rs`** - Advanced features including batch queries, plugins, mods, and favicons
*   **`srv_lookup_example.rs`** - Detailed demonstration of SRV record lookup
*   **`performance_test.rs`** - Performance benchmarking and speed tests
*   **`cache_management.rs`** - Cache management and statistics

Run examples with:

```bash
cargo run --example basic_usage
cargo run --example advanced_usage
cargo run --example srv_lookup_example
cargo run --example performance_test --release  # Use --release for accurate performance measurements
cargo run --example cache_management
```

## API Documentation

### McClient

The main client for making server status queries.

```rust
let client = McClient::new()
    .with_timeout(Duration::from_secs(5))      // Set request timeout
    .with_max_parallel(10);                     // Set max concurrent queries
```

**Methods:**
*   `new()` - Create a new client with default settings
*   `with_timeout(timeout)` - Set the request timeout
*   `with_max_parallel(max)` - Set the maximum number of parallel queries
*   `timeout()` - Get the current request timeout
*   `max_parallel()` - Get the maximum number of parallel queries
*   `ping(address, edition)` - Ping a single server
*   `ping_java(address)` - Ping a Java Edition server
*   `ping_bedrock(address)` - Ping a Bedrock Edition server
*   `ping_many(servers)` - Ping multiple servers in parallel
*   `clear_dns_cache()` - Clear DNS cache
*   `clear_srv_cache()` - Clear SRV record cache
*   `clear_all_caches()` - Clear all caches
*   `cache_stats()` - Get cache statistics
*   `resolve_dns_timed(host, port)` - Resolve DNS and measure resolution time (useful for cache benchmarking)
*   `is_online(address, edition)` - Quick check if server is online (faster than `ping`)

### ServerStatus

The result of a successful ping.

```rust
pub struct ServerStatus {
    pub online: bool,              // Whether the server is online
    pub ip: String,                // Resolved IP address
    pub port: u16,                 // Server port
    pub hostname: String,          // Original hostname
    pub latency: f64,              // Latency in milliseconds
    pub dns: Option<DnsInfo>,      // DNS information
    pub data: ServerData,          // Server-specific data
}

impl ServerStatus {
    pub fn players(&self) -> Option<(i64, i64)>;  // Get (online, max) players
}
```

### JavaStatus

Java Edition server information.

```rust
pub struct JavaStatus {
    pub version: JavaVersion,       // Version information
    pub players: JavaPlayers,       // Player information
    pub description: String,        // Server description (MOTD)
    pub favicon: Option<String>,    // Base64-encoded favicon
    pub map: Option<String>,        // Current map name
    pub gamemode: Option<String>,   // Game mode
    pub software: Option<String>,   // Server software
    pub plugins: Option<Vec<JavaPlugin>>,  // List of plugins
    pub mods: Option<Vec<JavaMod>>,        // List of mods
}

impl JavaStatus {
    pub fn save_favicon(&self, filename: &str) -> Result<(), McError>;
}
```

### BedrockStatus

Bedrock Edition server information.

```rust
pub struct BedrockStatus {
    pub edition: String,            // Minecraft edition
    pub motd: String,               // Message of the day
    pub version: String,            // Server version
    pub online_players: String,     // Online players count
    pub max_players: String,        // Maximum players
    pub map: Option<String>,        // Current map name
    pub software: Option<String>,   // Server software
    pub game_mode: String,          // Game mode
    // ... and more
}
```

## Error Handling

The library provides comprehensive error types:

```rust
use rust_mc_status::McError;

match client.ping("server.com", ServerEdition::Java).await {
    Ok(status) => println!("Server is online!"),
    Err(McError::Timeout) => println!("Request timed out"),
    Err(McError::DnsError(msg)) => println!("DNS error: {}", msg),
    Err(McError::ConnectionError(msg)) => println!("Connection error: {}", msg),
    Err(e) => println!("Other error: {}", e),
}
```

See the [documentation](https://docs.rs/rust-mc-status) for a complete list of error types.

## Performance

The library is optimized for performance:

*   **DNS Caching**: DNS lookups and SRV records are cached for 5 minutes
*   **Connection Pooling**: Efficient connection management
*   **Parallel Processing**: Batch queries run in parallel with configurable limits
*   **Memory Efficient**: Pre-allocated buffers and efficient data structures
*   **Async I/O**: Non-blocking I/O operations using Tokio

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Version

Current version: **2.0.0**

See [CHANGELOG.md](CHANGELOG.md) for detailed version history, new features, and migration guide.