use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use std::convert::TryFrom;
use crate::Error;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)]
pub(crate) struct RawLatest {
pub version: Version,
pub players: Players,
pub description: Option<serde_json::Value>,
pub favicon: Option<String>,
#[serde(rename = "enforcesSecureChat")]
pub enforces_secure_chat: Option<bool>,
#[serde(rename = "previewsChat")]
pub previews_chat: Option<bool>,
#[serde(rename = "modinfo")]
pub mod_info: Option<ModInfo>,
#[serde(rename = "forgeData")]
pub forge_data: Option<ForgeData>,
#[serde(skip)]
pub raw_json: Vec<u8>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[non_exhaustive]
pub struct Response {
pub version: String,
pub protocol: i32,
pub enforces_secure_chat: Option<bool>,
pub previews_chat: Option<bool>,
pub max_players: usize,
pub online_players: usize,
pub sample: Option<Vec<Player>>,
pub description: Option<serde_json::Value>,
pub favicon: Option<Vec<u8>>,
pub mod_info: Option<ModInfo>,
pub forge_data: Option<ForgeData>,
#[serde(skip)]
pub(crate) raw: Vec<u8>,
}
impl Response {
pub fn raw(&self) -> &[u8] {
&self.raw
}
}
impl TryFrom<RawLatest> for Response {
type Error = Error;
fn try_from(raw: RawLatest) -> Result<Self, Self::Error> {
let favicon = if let Some(favicon) = raw.favicon {
let slice = favicon.get(22..).ok_or(Error::UnsupportedProtocol)?;
Some(
STANDARD
.decode(slice)
.map_err(|_| Error::UnsupportedProtocol)?,
)
} else {
None
};
Ok(Self {
version: raw.version.name,
protocol: raw.version.protocol,
enforces_secure_chat: raw.enforces_secure_chat,
previews_chat: raw.previews_chat,
max_players: raw.players.max,
online_players: raw.players.online,
sample: raw.players.sample,
description: raw.description,
favicon,
mod_info: raw.mod_info,
forge_data: raw.forge_data,
raw: raw.raw_json,
})
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub(crate) struct Version {
pub name: String,
pub protocol: i32,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub(crate) struct Players {
pub max: usize,
pub online: usize,
pub sample: Option<Vec<Player>>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Player {
pub name: String,
pub id: String,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ModInfo {
#[serde(rename = "type")]
pub mod_type: String,
#[serde(rename = "modList")]
pub mod_list: Vec<ModInfoItem>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ModInfoItem {
#[serde(rename = "modid")]
pub mod_id: String,
pub version: String,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ForgeData {
pub channels: Vec<ForgeChannel>,
pub mods: Vec<ForgeMod>,
#[serde(rename = "fmlNetworkVersion")]
pub fml_network_version: i32,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ForgeChannel {
pub res: String,
pub version: String,
pub required: bool,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ForgeMod {
#[serde(rename = "modId")]
pub mod_id: String,
#[serde(rename = "modmarker")]
pub mod_marker: String,
}