minecraft-pinger 0.1.0

A high-performance, asynchronous Rust library for pinging Minecraft servers to retrieve status, players, and metadata.
Documentation
use crate::bedrock::model::BedrockPing;
use crate::error::PingError;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use rand::Rng;
use std::time::{SystemTime, UNIX_EPOCH};

const MAGIC: u128 = 0x00ffff00fefefefefdfdfdfd12345678;

fn try_split_to(buffer: &mut Bytes, size: usize) -> Option<Bytes> {
    if buffer.len() >= size {
        Some(buffer.split_to(size))
    } else {
        None
    }
}

pub(crate) fn create_ping() -> Result<Bytes, PingError> {
    let mut data = BytesMut::with_capacity(33);
    data.put_u8(0x1);
    
    let time = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map_err(|_| PingError::Init("SystemTime before UNIX_EPOCH".into()))?
        .as_millis() as u64;
        
    data.put_u64(time);
    data.put_u128(MAGIC);

    let mut guid = [0u8; 8];
    rand::rng().fill_bytes(&mut guid);

    data.put_slice(&guid);

    Ok(data.freeze())
}

pub(crate) fn read_response(buffer: &mut Bytes) -> Result<BedrockPing, PingError> {
    let _packet_id = buffer.try_get_u8()
        .map_err(|_| PingError::ReadPacket("Packet id not found".to_string()))?;

    let _timestamp = buffer.try_get_u64()
        .map_err(|_| PingError::ReadPacket("Timestamp not found".to_string()))?;

    let _server_guid = buffer.try_get_u64()
        .map_err(|_| PingError::ReadPacket("Server guid not found".to_string()))?;

    let _magic = buffer.try_get_u128()
        .map_err(|_| PingError::ReadPacket("Magic id not found".to_string()))?;


    let string_size = buffer.try_get_u16()
        .map_err(|_| PingError::ReadPacket("String size not found".to_string()))?;

    let string_data = try_split_to(buffer, string_size as usize)
        .ok_or(PingError::ReadPacket("String data not found".to_string()))?;

    let str = String::from_utf8(string_data.into())?;

    Ok(str.try_into()?)
}