use crate::{
conf::Conf,
share::{bufs_to_utf16_str, create_tcp_socket},
MspErr,
};
use serde::Serialize;
use std::io::{Read, Write};
#[derive(Serialize, Debug)]
pub struct LegacyServer {
pub protocol_version: i32,
pub server_version: String,
pub motd: String,
pub online_players: i32,
pub max_players: i32,
}
impl std::fmt::Display for LegacyServer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)?
)
}
}
#[derive(Serialize, Debug)]
pub struct LegacyBetaServer {
pub motd: String,
pub online_players: i32,
pub max_players: i32,
}
impl std::fmt::Display for LegacyBetaServer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
serde_json::to_string_pretty(self).map_err(|_| std::fmt::Error)?
)
}
}
pub fn get_legacy_server_status(conf: &Conf) -> Result<LegacyServer, MspErr> {
let mut socket = create_tcp_socket(conf)?;
let mut bufs = Vec::<u8>::new();
socket.write(&mut Vec::from([0xFE, 0x01]))?;
socket.read_to_end(&mut bufs)?;
process_legacy_server_bufs(bufs.as_slice())
}
pub fn get_beta_legacy_server_status(conf: &Conf) -> Result<LegacyBetaServer, MspErr> {
let mut socket = create_tcp_socket(conf)?;
let mut bufs = [0u8; 1];
socket.write(&[0xFE])?;
socket.read(&mut bufs)?;
if bufs.get(0) != Some(&0xFF) {
return Err(MspErr::DataErr(format!(
"Packet response excepted start with: 0xFF, but got: 0x{:02X}",
bufs[0]
)));
}
let mut bufs = [0u8; 2];
socket.read(&mut bufs)?;
let mut bufs = vec![0u8; (u16::from_be_bytes(bufs) * 2) as usize];
socket.read(&mut bufs)?;
let server_info = bufs_to_utf16_str(bufs.as_slice())?;
let server_split = server_info.split("§").collect::<Vec<_>>();
build_beta_legacy_server(server_split)
}
fn build_legacy_server(data: Vec<&str>) -> Result<LegacyServer, MspErr> {
if data.len() != 5 {
return Err(MspErr::DataErr(format!(
"Expected return is 5 parts of server information, but {} were obtained.",
data.len()
)));
}
Ok(LegacyServer {
protocol_version: data[0].parse::<i32>()?,
server_version: data[1].into(),
motd: data[2].into(),
online_players: data[3].parse::<i32>()?,
max_players: data[4].parse::<i32>()?,
})
}
fn build_beta_legacy_server(data: Vec<&str>) -> Result<LegacyBetaServer, MspErr> {
if data.len() != 3 {
return Err(MspErr::DataErr(format!(
"Expected return is 3 parts of server information, but {} were obtained.",
data.len()
)));
}
Ok(LegacyBetaServer {
motd: data[2].into(),
online_players: data[3].parse::<i32>()?,
max_players: data[4].parse::<i32>()?,
})
}
pub fn process_legacy_server_bufs(bufs: &[u8]) -> Result<LegacyServer, MspErr> {
if bufs.get(0) != Some(&0xFF) {
return Err(MspErr::DataErr(format!(
"Packet response excepted start with: 0xFF, but got: 0x{:02X}",
bufs[0]
)));
}
let server_info = bufs_to_utf16_str(&bufs[3..])?;
if !server_info.starts_with("§1") {
return Err(MspErr::DataErr(
"Server info excepted start with: §1.".into(),
));
}
Ok(build_legacy_server(
server_info.split("\0").skip(1).collect::<Vec<_>>(),
)?)
}