1use crate::types::Chat;
2use crate::uuid::UUID4;
3use crate::{
4 Deserialize as McDeserialize, DeserializeErr, DeserializeResult, Serialize as McSerialize,
5 SerializeErr, SerializeResult,
6};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use alloc::{string::String, fmt, vec::Vec, borrow::ToOwned};
9use alloc::format;
10
11#[cfg(all(test, feature = "std"))]
12use crate::protocol::TestRandom;
13
14#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
15pub struct StatusSpec {
16 pub version: Option<StatusVersionSpec>,
17 pub players: StatusPlayersSpec,
18 pub description: Chat,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub favicon: Option<StatusFaviconSpec>,
21}
22
23impl McSerialize for StatusSpec {
24 fn mc_serialize<S: crate::Serializer>(&self, to: &mut S) -> SerializeResult {
25 serde_json::to_string(self)
26 .map_err(move |err| {
27 SerializeErr::FailedJsonEncode(format!("failed to serialize json status {}", err))
28 })?
29 .mc_serialize(to)
30 }
31}
32
33impl McDeserialize for StatusSpec {
34 fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
35 String::mc_deserialize(data)?.try_map(move |v| {
36 serde_json::from_str(v.as_str()).map_err(move |err| {
37 DeserializeErr::CannotUnderstandValue(format!(
38 "failed to deserialize json status {}",
39 err
40 ))
41 })
42 })
43 }
44}
45
46#[cfg(all(test, feature = "std"))]
47impl TestRandom for StatusSpec {
48 fn test_gen_random() -> Self {
49 Self {
50 version: Some(StatusVersionSpec {
51 protocol: rand::random(),
52 name: String::test_gen_random(),
53 }),
54 players: StatusPlayersSpec {
55 sample: Vec::default(),
56 max: rand::random(),
57 online: rand::random(),
58 },
59 favicon: None,
60 description: Chat::test_gen_random(),
61 }
62 }
63}
64
65#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
66pub struct StatusVersionSpec {
67 pub name: String,
68 pub protocol: i32,
69}
70
71#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
72pub struct StatusPlayersSpec {
73 pub max: i32,
74 pub online: i32,
75 #[serde(skip_serializing_if = "Vec::is_empty")]
76 #[serde(default = "Vec::default")]
77 pub sample: Vec<StatusPlayerSampleSpec>,
78}
79
80#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
81pub struct StatusPlayerSampleSpec {
82 pub name: String,
83 pub id: UUID4,
84}
85
86#[derive(Clone, Debug, PartialEq)]
87pub struct StatusFaviconSpec {
88 pub content_type: String,
89 pub data: Vec<u8>,
90}
91
92impl Serialize for StatusFaviconSpec {
93 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
94 where
95 S: Serializer,
96 {
97 let data_base64 = base64::encode(self.data.as_slice());
98 let content = alloc::format!("data:{};base64,{}", self.content_type, data_base64);
99 serializer.serialize_str(content.as_str())
100 }
101}
102
103impl<'de> Deserialize<'de> for StatusFaviconSpec {
104 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
105 where
106 D: Deserializer<'de>,
107 {
108 struct Visitor;
109 impl serde::de::Visitor<'_> for Visitor {
110 type Value = StatusFaviconSpec;
111
112 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(formatter, "a string with base64 data for favicon")
114 }
115
116 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
117 let v = str_tag(v, "data:", &self)?;
119 let (content_type, v) = str_until_pat(v, ";", &self)?;
120 let rest = str_tag(v, "base64,", &self)?;
121 match base64::decode(rest.replace('\n', "")) {
122 Ok(data) => {
123 Ok(StatusFaviconSpec{
124 data,
125 content_type: content_type.to_owned(),
126 })
127 },
128 Err(err) => {
129 Err(E::custom(format_args!("failed base64 decode {:?}", err)))
130 }
131 }
132 }
133 }
134
135 deserializer.deserialize_str(Visitor {})
136 }
137}
138
139fn str_tag<'a, E, V>(
140 target: &'a str,
141 expected: &str,
142 v: &V,
143) -> Result<&'a str, E> where
144 E: serde::de::Error,
145 V: serde::de::Visitor<'a>
146{
147 let (front, back) = str_take(target, expected.len(), v)?;
148 if front != expected {
149 Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
150 } else {
151 Ok(back)
152 }
153}
154
155fn str_until_pat<'a, E, V>(
156 target: &'a str,
157 pat: &str,
158 v: &V,
159) -> Result<(&'a str, &'a str), E> where
160 E: serde::de::Error,
161 V: serde::de::Visitor<'a>
162{
163 let n_pat = pat.len();
164 if target.len() < n_pat {
165 return Err(E::invalid_value(serde::de::Unexpected::Str(target), v));
166 }
167
168 for i in 0..=(target.len()-n_pat) {
169 let v = &target[i..i+n_pat];
170 if v == pat {
171 return Ok((&target[..i], &target[i+1..]));
172 }
173 }
174
175 Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
176}
177
178fn str_take<'a, E, V>(
179 target: &'a str,
180 n: usize,
181 v: &V,
182) -> Result<(&'a str, &'a str), E> where
183 E: serde::de::Error,
184 V: serde::de::Visitor<'a>
185{
186 if target.len() < n {
187 Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
188 } else {
189 Ok(target.split_at(n))
190 }
191}