use crate::{
share::{create_tcp_socket, get_server_current_time},
varint::{decode_varint_from_socket, encode_varint},
Conf, MspErr,
};
use serde::{Deserialize, Serialize};
use std::{
io::{Read, Write},
net::TcpStream,
};
const DEFAULT_SERVER_PORT: u16 = 25565;
#[derive(Serialize, Deserialize, Debug)]
pub struct Server {
pub version: Version,
pub players: Players,
pub description: Description,
pub favicon: String,
#[serde(
alias = "forgeData",
rename = "forgeData",
skip_serializing_if = "Option::is_none"
)]
pub forge_data: Option<ForgeData>,
#[serde(
alias = "enforcesSecureChat",
rename = "enforcesSecureChat",
default = "enforces_secure_chat_default"
)]
pub enforces_secure_chat: bool,
#[serde(default = "ping_default")]
pub ping: u64,
}
impl std::fmt::Display for Server {
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, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Version {
pub name: String,
pub protocol: i32,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields, default)]
pub struct Players {
pub max: i32,
pub online: i32,
pub sample: Vec<Player>,
}
impl Default for Players {
fn default() -> Self {
Players {
max: 0,
online: 0,
sample: vec![],
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Player {
pub name: String,
pub id: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields, default)]
pub struct Description {
pub extra: Vec<DescriptionExtra>,
pub text: String,
}
impl Default for Description {
fn default() -> Self {
Description {
extra: vec![],
text: "".into(),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields, default)]
pub struct DescriptionExtra {
pub color: String,
pub bold: bool,
pub italic: bool,
pub underlined: bool,
pub strikethrough: bool,
pub obfuscated: bool,
pub text: String,
pub extra: Vec<DescriptionExtra>,
}
impl Default for DescriptionExtra {
fn default() -> Self {
Self {
color: "".into(),
bold: false,
italic: false,
underlined: false,
strikethrough: false,
obfuscated: false,
text: "".into(),
extra: Vec::new(),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ForgeData {
pub mods: Vec<ForgeMod>,
pub channels: Vec<ForgeChannel>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct ForgeMod {
#[serde(alias = "modId", rename = "modId")]
pub mod_id: String,
pub modmarker: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct ForgeChannel {
pub res: String,
pub version: String,
pub required: bool,
}
pub fn get_server_status(conf: &Conf) -> Result<Server, MspErr> {
let mut socket = create_tcp_socket(conf)?;
let hand_shake_packet = build_handshake_packet(&conf);
let status_request_packet = build_status_request_packet();
socket.write(&hand_shake_packet)?;
socket.write(&status_request_packet)?;
let (_p_buf_len, _p_size) = decode_varint_from_socket(&mut socket)?;
let (_id_buf_len, _id) = decode_varint_from_socket(&mut socket)?;
let (_d_buf_len, d_size) = decode_varint_from_socket(&mut socket)?;
let mut data_buffer = Vec::new();
Read::by_ref(&mut socket)
.take(d_size as u64)
.read_to_end(&mut data_buffer)?;
match std::str::from_utf8(&data_buffer) {
Ok(str) => match serde_json::from_str::<Server>(str) {
Ok(mut server) => {
let ping = get_server_ping(&mut socket)?;
server.ping = ping;
Ok(server)
}
Err(err) => Err(MspErr::DataErr(err.to_string())),
},
Err(err) => {
return Err(MspErr::InternalErr(err.to_string()));
}
}
}
fn build_handshake_packet(conf: &Conf) -> Vec<u8> {
let mut packet = Vec::<u8>::new();
let mut packet_data = Vec::<u8>::new();
let mut server_addr_bytes = conf.host.as_bytes().to_vec();
packet_data.append(&mut encode_varint(-1));
packet_data.append(&mut encode_varint(server_addr_bytes.len() as i32));
packet_data.append(&mut server_addr_bytes);
packet_data.append(&mut DEFAULT_SERVER_PORT.to_be_bytes().to_vec());
packet_data.append(&mut encode_varint(1));
packet.append(&mut encode_varint(1 + packet_data.len() as i32));
packet.append(&mut encode_varint(0x00));
packet.append(&mut packet_data);
packet
}
fn build_status_request_packet() -> Vec<u8> {
let mut packet = Vec::<u8>::new();
packet.append(&mut encode_varint(1));
packet.append(&mut encode_varint(0x00));
packet
}
fn build_ping_request_packet() -> Result<(u64, Vec<u8>), MspErr> {
let mut packet = Vec::<u8>::new();
let now_millis = get_server_current_time()?;
packet.append(&mut encode_varint(9));
packet.push(0x01);
packet.append(&mut now_millis.to_be_bytes().to_vec());
Ok((now_millis, packet))
}
fn get_server_ping(socket: &mut TcpStream) -> Result<u64, MspErr> {
let (req_t, ping_request_packet) = build_ping_request_packet()?;
let mut time_bytes = [0u8; 8];
socket.write(&ping_request_packet)?;
decode_varint_from_socket(socket)?;
decode_varint_from_socket(socket)?;
Read::by_ref(socket).take(8).read(&mut time_bytes)?;
let receive_t = u64::from_be_bytes(time_bytes);
if receive_t == req_t {
let res_t = get_server_current_time()?;
return Ok(res_t - req_t);
}
Err(MspErr::DataErr(format!("Server's response time does not match the sending time(send: {}, receive: {}), indicating that the latency is not reliable.", req_t, receive_t)))
}
fn enforces_secure_chat_default() -> bool {
false
}
fn ping_default() -> u64 {
0
}