-
Notifications
You must be signed in to change notification settings - Fork 144
Expand file tree
/
Copy pathconfig.rs
More file actions
179 lines (156 loc) · 4.78 KB
/
Copy pathconfig.rs
File metadata and controls
179 lines (156 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! Loads an `Options` from a TOML config.
use std::{fs, net::IpAddr, path::Path, str::FromStr, time::Duration};
use anyhow::Context;
use indexmap::IndexMap;
use libcraft::Gamemode;
use quill::world::WorldSaveStrategy;
use serde::{Deserialize, Deserializer};
use crate::{favicon::Favicon, Options};
const DEFAULT_CONFIG: &str = include_str!("../config.toml");
/// Loads the config, creating a default config if needed.
pub fn load(path: &str) -> anyhow::Result<ConfigContainer> {
let path = Path::new(path);
let default_config = DEFAULT_CONFIG;
let mut is_created = false;
if !path.exists() {
log::info!("Creating default config");
fs::write(path, default_config)?;
is_created = true;
}
let config_string = fs::read_to_string(path)?;
let config: Config = toml::from_str(&config_string).context("invalid config.toml file")?;
Ok(ConfigContainer {
config,
was_config_created: is_created,
})
}
/// A wrapper for the result returned by [load].
pub struct ConfigContainer {
pub config: Config,
pub was_config_created: bool,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Config {
pub network: Network,
pub server: ServerConfig,
pub log: Log,
pub worlds: IndexMap<String, World>,
pub proxy: Proxy,
}
impl Config {
pub fn to_options(&self) -> Options {
Options {
port: self.network.port,
bind_address: self.network.address.to_string(),
favicon: Favicon::load_default(),
motd: self.server.motd.clone(),
online_mode: if self.proxy.proxy_mode != ProxyMode::None {
false
} else {
self.server.online_mode
},
compression_threshold: if self.network.compression_threshold <= 0 {
None
} else {
Some(self.network.compression_threshold as usize)
},
view_distance: self.server.view_distance,
max_players: self.server.max_players,
default_gamemode: self.server.default_gamemode,
proxy_mode: match self.proxy.proxy_mode {
ProxyMode::None => None,
ProxyMode::Bungee => Some(crate::options::ProxyMode::Bungeecord),
ProxyMode::Velocity => Some(crate::options::ProxyMode::Velocity),
},
velocity_secret: self.proxy.velocity_secret.clone(),
}
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct Network {
pub address: IpAddr,
pub port: u16,
pub compression_threshold: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct ServerConfig {
pub online_mode: bool,
pub motd: String,
pub max_players: u32,
pub default_gamemode: Gamemode,
pub view_distance: u32,
pub default_world: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Log {
#[serde(deserialize_with = "deserialize_log_level")]
pub level: log::LevelFilter,
}
#[derive(Debug, Deserialize, Clone)]
pub struct World {
pub save_strategy: SaveStrategy,
pub dimension_type: String,
pub source: WorldSourceSpec,
#[serde(default)]
pub flat: bool,
}
#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum SaveStrategy {
SaveIncrementally {
#[serde(with = "humantime_serde")]
interval: Duration,
},
DropChanges,
KeepLoaded,
}
impl From<SaveStrategy> for WorldSaveStrategy {
fn from(s: SaveStrategy) -> Self {
match s {
SaveStrategy::SaveIncrementally { interval } => WorldSaveStrategy::SaveIncrementally {
save_interval: interval,
},
SaveStrategy::DropChanges => WorldSaveStrategy::DropChanges,
SaveStrategy::KeepLoaded => WorldSaveStrategy::KeepLoaded,
}
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct WorldSourceSpec {
#[serde(rename = "type")]
pub typ: String,
#[serde(flatten)]
pub params: toml::value::Table,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Proxy {
pub proxy_mode: ProxyMode,
pub velocity_secret: String,
}
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ProxyMode {
None,
Bungee,
Velocity,
}
fn deserialize_log_level<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<log::LevelFilter, D::Error> {
let string: String = String::deserialize(deserializer)?;
let level = log::LevelFilter::from_str(&string).map_err(|_| {
serde::de::Error::custom(
"invalid log level: valid options are trace, debug, info, warn, error",
)
})?;
Ok(level)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_config_is_valid() {
let _config: Config = toml::from_str(DEFAULT_CONFIG).unwrap();
}
}