veloren_server/settings/
server_description.rs1use super::{MIGRATION_UPGRADE_GUARANTEE, SERVER_DESCRIPTION_FILENAME as FILENAME};
6use crate::settings::editable::{EditableSetting, Version};
7use core::convert::{Infallible, TryFrom, TryInto};
8use serde::{Deserialize, Serialize};
9
10pub use self::v2::*;
16
17#[derive(Deserialize, Serialize)]
20pub enum ServerDescriptionRaw {
21 V0(v0::ServerDescription),
22 V1(v1::ServerDescription),
23 V2(ServerDescriptions),
24}
25
26impl From<ServerDescriptions> for ServerDescriptionRaw {
27 fn from(value: ServerDescriptions) -> Self {
28 Self::V2(value)
30 }
31}
32
33#[expect(clippy::infallible_try_from)] impl TryFrom<ServerDescriptionRaw> for (Version, ServerDescriptions) {
35 type Error = <ServerDescriptions as EditableSetting>::Error;
36
37 fn try_from(
38 value: ServerDescriptionRaw,
39 ) -> Result<Self, <ServerDescriptions as EditableSetting>::Error> {
40 use ServerDescriptionRaw::*;
41 Ok(match value {
42 V0(value) => (Version::Old, value.try_into()?),
44 V1(value) => (Version::Old, value.try_into()?),
45 V2(mut value) => (value.validate()?, value),
48 })
49 }
50}
51
52type Final = ServerDescriptions;
53
54impl EditableSetting for ServerDescriptions {
55 type Error = Infallible;
56 type Legacy = legacy::ServerDescription;
57 type Setting = ServerDescriptionRaw;
58
59 const FILENAME: &'static str = FILENAME;
60}
61
62mod legacy {
63 use super::{Final, MIGRATION_UPGRADE_GUARANTEE, v0 as next};
64 use core::convert::TryInto;
65 use serde::{Deserialize, Serialize};
66
67 #[derive(Deserialize, Serialize)]
68 #[serde(transparent)]
69 pub struct ServerDescription(pub(super) String);
70
71 impl From<ServerDescription> for Final {
72 fn from(value: ServerDescription) -> Self {
79 next::ServerDescription::migrate(value)
80 .try_into()
81 .expect(MIGRATION_UPGRADE_GUARANTEE)
82 }
83 }
84}
85
86mod v0 {
91 use super::{Final, MIGRATION_UPGRADE_GUARANTEE, legacy as prev, v1 as next};
92 use crate::settings::editable::{EditableSetting, Version};
93 use core::convert::{TryFrom, TryInto};
94 use serde::{Deserialize, Serialize};
95
96 #[derive(Clone, Deserialize, Serialize)]
97 #[serde(transparent)]
98 pub struct ServerDescription(pub(super) String);
99
100 impl ServerDescription {
101 pub(super) fn migrate(prev: prev::ServerDescription) -> Self { ServerDescription(prev.0) }
105
106 pub(super) fn validate(&mut self) -> Result<Version, <Final as EditableSetting>::Error> {
113 Ok(Version::Latest)
114 }
115 }
116
117 #[expect(clippy::infallible_try_from)] impl TryFrom<ServerDescription> for Final {
121 type Error = <Final as EditableSetting>::Error;
122
123 fn try_from(mut value: ServerDescription) -> Result<Final, Self::Error> {
124 value.validate()?;
125 Ok(next::ServerDescription::migrate(value)
126 .try_into()
127 .expect(MIGRATION_UPGRADE_GUARANTEE))
128 }
129 }
130}
131
132mod v1 {
133 use super::{Final, v0 as prev};
134 use crate::settings::editable::{EditableSetting, Version};
135 use core::ops::{Deref, DerefMut};
136 use serde::{Deserialize, Serialize};
137
138 #[derive(Clone, Deserialize, Serialize)]
139 #[serde(transparent)]
140 pub struct ServerDescription(pub(super) String);
141
142 impl Default for ServerDescription {
143 fn default() -> Self { Self("This is the best Veloren server".into()) }
144 }
145
146 impl Deref for ServerDescription {
147 type Target = String;
148
149 fn deref(&self) -> &Self::Target { &self.0 }
150 }
151
152 impl DerefMut for ServerDescription {
153 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
154 }
155
156 impl ServerDescription {
157 pub(super) fn migrate(prev: prev::ServerDescription) -> Self { ServerDescription(prev.0) }
161
162 pub(super) fn validate(&mut self) -> Result<Version, <Final as EditableSetting>::Error> {
169 Ok(Version::Latest)
170 }
171 }
172
173 use super::v2 as next;
174 #[expect(clippy::infallible_try_from)] impl TryFrom<ServerDescription> for Final {
176 type Error = <Final as EditableSetting>::Error;
177
178 fn try_from(mut value: ServerDescription) -> Result<Final, Self::Error> {
179 value.validate()?;
180 Ok(next::ServerDescriptions::migrate(value))
181 }
182 }
183}
184
185mod v2 {
186 use std::collections::HashMap;
187
188 use super::{Final, v1 as prev};
189 use crate::settings::editable::{EditableSetting, Version};
190 use serde::{Deserialize, Serialize};
191
192 #[derive(Clone, Deserialize, Serialize)]
194 pub struct ServerDescriptions {
195 pub default_locale: String,
196 pub descriptions: HashMap<String, ServerDescription>,
197 }
198
199 #[derive(Clone, Deserialize, Serialize)]
200 pub struct ServerDescription {
201 pub motd: String,
202 pub rules: Option<String>,
203 }
204
205 impl Default for ServerDescriptions {
206 fn default() -> Self {
207 Self {
208 default_locale: "en".to_string(),
209 descriptions: HashMap::from([("en".to_string(), ServerDescription::default())]),
210 }
211 }
212 }
213
214 impl Default for ServerDescription {
215 fn default() -> Self {
216 Self {
217 motd: "This is the best Veloren server".into(),
218 rules: None,
219 }
220 }
221 }
222
223 impl ServerDescriptions {
224 fn unwrap_locale_or_default<'a, 'b: 'a>(&'b self, locale: Option<&'a str>) -> &'a str {
225 locale.map_or(&self.default_locale, |locale| {
226 if self.descriptions.contains_key(locale) {
227 locale
228 } else {
229 &self.default_locale
230 }
231 })
232 }
233
234 pub fn get(&self, locale: Option<&str>) -> Option<&ServerDescription> {
235 self.descriptions.get(self.unwrap_locale_or_default(locale))
236 }
237
238 pub fn get_rules(&self, locale: Option<&str>) -> Option<&str> {
241 self.descriptions
242 .get(self.unwrap_locale_or_default(locale))
243 .and_then(|d| d.rules.as_deref())
244 .or_else(|| {
245 self.descriptions
246 .get(&self.default_locale)?
247 .rules
248 .as_deref()
249 })
250 }
251 }
252
253 impl ServerDescriptions {
254 pub(super) fn migrate(prev: prev::ServerDescription) -> Self {
258 Self {
259 default_locale: "en".to_string(),
260 descriptions: HashMap::from([("en".to_string(), ServerDescription {
261 motd: prev.0,
262 rules: None,
263 })]),
264 }
265 }
266
267 pub(super) fn validate(&mut self) -> Result<Version, <Final as EditableSetting>::Error> {
274 if self.descriptions.is_empty() {
275 *self = Self::default();
276 Ok(Version::Old)
277 } else if !self.descriptions.contains_key(&self.default_locale) {
278 self.default_locale = self
281 .descriptions
282 .keys()
283 .next()
284 .expect("We know descriptions isn't empty")
285 .to_string();
286 Ok(Version::Old)
287 } else {
288 Ok(Version::Latest)
289 }
290 }
291 }
292
293 }