Move more things into Config
This commit is contained in:
parent
b4ed1572e9
commit
182bf76835
@ -1,5 +1,6 @@
|
||||
favicon = "server-icon.png"
|
||||
log_level = "debug"
|
||||
max_players = 20
|
||||
motd = "Hello world!"
|
||||
ping_game_version = "1.18.1"
|
||||
port = 25565
|
||||
log_level = "debug"
|
||||
server_icon = "server-icon.png"
|
||||
|
162
src/config.rs
162
src/config.rs
@ -1,12 +1,23 @@
|
||||
use crate::prelude::*;
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
fn read_file(path: &Path) -> std::io::Result<Vec<u8>> {
|
||||
let mut data = vec![];
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_end(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub port: u16,
|
||||
pub max_players: usize,
|
||||
pub motd: String,
|
||||
pub favicon: String,
|
||||
pub server_icon: String,
|
||||
pub server_icon_bytes: Vec<u8>,
|
||||
pub server_string: String,
|
||||
pub log_level: log::LevelFilter,
|
||||
pub protocol_version: i32,
|
||||
pub game_version: String,
|
||||
pub server_version: String,
|
||||
}
|
||||
impl Default for Config {
|
||||
@ -20,33 +31,22 @@ impl Default for Config {
|
||||
port: 25565,
|
||||
max_players: 20,
|
||||
motd: "Hello world!".to_owned(),
|
||||
favicon: "server-icon.png".to_owned(),
|
||||
server_icon: "server-icon.png".to_owned(),
|
||||
server_icon_bytes: include_bytes!("../server-icon.png").to_vec(),
|
||||
server_string: server_version.clone(),
|
||||
log_level: if cfg!(debug_assertions) {
|
||||
log::LevelFilter::Debug
|
||||
} else {
|
||||
log::LevelFilter::Info
|
||||
},
|
||||
protocol_version: 756,
|
||||
game_version: "1.18.1".to_owned(),
|
||||
server_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Config {
|
||||
pub fn from_file(filename: &str) -> Config {
|
||||
let read_file = |filename: &str| -> std::io::Result<String> {
|
||||
use std::{fs::File, io::prelude::*};
|
||||
let mut data = String::new();
|
||||
let mut file = File::open(filename)?;
|
||||
file.read_to_string(&mut data)?;
|
||||
Ok(data)
|
||||
};
|
||||
if let Ok(config) = read_file(filename) {
|
||||
Config::parse(&config)
|
||||
} else {
|
||||
Config::default()
|
||||
}
|
||||
}
|
||||
pub fn parse(data: &str) -> Config {
|
||||
pub fn from_toml(cfg: toml::Value) -> Config {
|
||||
let mut config = Config::default();
|
||||
|
||||
let get_string = |cfg: &toml::Value, field: &str, default: &str, error: &str| -> String {
|
||||
@ -62,10 +62,14 @@ impl Config {
|
||||
default.to_owned()
|
||||
};
|
||||
|
||||
if let Ok(cfg) = data.parse::<toml::Value>() {
|
||||
if let Some(&toml::Value::Integer(port)) = cfg.get("port") {
|
||||
if port < u16::MIN as i64 || port > u16::MAX as i64 {
|
||||
warn!("Config port must be an integer in the range of {}-{}, using default port: {}", u16::MIN, u16::MAX, config.port);
|
||||
warn!(
|
||||
"Config port must be an integer in the range of {}-{}, using default port: {}",
|
||||
u16::MIN,
|
||||
u16::MAX,
|
||||
config.port
|
||||
);
|
||||
} else {
|
||||
config.port = port as u16;
|
||||
}
|
||||
@ -97,13 +101,22 @@ impl Config {
|
||||
config.motd
|
||||
),
|
||||
);
|
||||
config.favicon = get_string(
|
||||
config.game_version = get_string(
|
||||
&cfg,
|
||||
"favicon",
|
||||
&config.favicon,
|
||||
"ping_game_version",
|
||||
&config.game_version,
|
||||
&format!(
|
||||
"Config favicon must be a string, using default favicon: \"{}\"",
|
||||
config.favicon
|
||||
"Config ping_game_version must be a string, using default ping_game_version: \"{}\"",
|
||||
config.game_version
|
||||
),
|
||||
);
|
||||
config.server_icon = get_string(
|
||||
&cfg,
|
||||
"server_icon",
|
||||
&config.server_icon,
|
||||
&format!(
|
||||
"Config server_icon must be a string, using default server_icon: \"{}\"",
|
||||
config.server_icon
|
||||
),
|
||||
);
|
||||
let default_log_level = format!("{}", config.log_level).to_ascii_lowercase();
|
||||
@ -128,11 +141,106 @@ impl Config {
|
||||
config.log_level
|
||||
}
|
||||
};
|
||||
config
|
||||
}
|
||||
pub fn load() -> Config {
|
||||
let mut config = Config::default();
|
||||
|
||||
// Load the config
|
||||
let config_path = Path::new("composition.toml");
|
||||
if config_path.exists() {
|
||||
if let Ok(cfg) = read_file(config_path) {
|
||||
let cfg = String::from_utf8_lossy(&cfg);
|
||||
if let Ok(cfg) = cfg.parse::<toml::Value>() {
|
||||
config = Config::from_toml(cfg);
|
||||
} else {
|
||||
error!("Could not parse configuration file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Could not read configuration file, creating {}",
|
||||
config_path.to_str().unwrap_or("")
|
||||
);
|
||||
if config.write(config_path).is_err() {
|
||||
error!("Could not write configuration file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Configuration file does not exist, creating {}",
|
||||
config_path.to_str().unwrap_or("")
|
||||
);
|
||||
if config.write(config_path).is_err() {
|
||||
error!("Could not write configuration file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the server icon
|
||||
let server_icon_path = Path::new(&config.server_icon);
|
||||
if server_icon_path.exists() {
|
||||
if let Ok(server_icon_bytes) = read_file(server_icon_path) {
|
||||
config.server_icon_bytes = server_icon_bytes;
|
||||
} else {
|
||||
warn!(
|
||||
"Could not read server icon file, creating {}",
|
||||
server_icon_path.to_str().unwrap_or("")
|
||||
);
|
||||
if config.write_server_icon(server_icon_path).is_err() {
|
||||
error!("Could not write server icon file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Server icon file does not exist, creating {}",
|
||||
server_icon_path.to_str().unwrap_or("")
|
||||
);
|
||||
if config.write_server_icon(server_icon_path).is_err() {
|
||||
error!("Could not write server icon file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
} else {
|
||||
warn!("Could not parse configuration file, using default");
|
||||
config
|
||||
}
|
||||
pub fn write(&self, path: &Path) -> std::io::Result<()> {
|
||||
use toml::{map::Map, Value};
|
||||
|
||||
let config = Value::Table({
|
||||
let mut m = Map::new();
|
||||
m.insert(
|
||||
"server_icon".to_owned(),
|
||||
Value::String(self.server_icon.clone()),
|
||||
);
|
||||
m.insert(
|
||||
"log_level".to_owned(),
|
||||
Value::String(format!("{}", self.log_level).to_ascii_lowercase()),
|
||||
);
|
||||
m.insert("max_players".to_owned(), Value::Integer(20));
|
||||
m.insert("motd".to_owned(), Value::String(self.motd.clone()));
|
||||
m.insert(
|
||||
"ping_game_version".to_owned(),
|
||||
Value::String(self.game_version.clone()),
|
||||
);
|
||||
m.insert("port".to_owned(), Value::Integer(25565));
|
||||
m
|
||||
});
|
||||
if path.exists() {
|
||||
std::fs::remove_file(path)?;
|
||||
}
|
||||
let mut file = File::create(path)?;
|
||||
file.write_all(&toml::ser::to_vec(&config).unwrap())?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_server_icon(&self, path: &Path) -> std::io::Result<()> {
|
||||
if path.exists() {
|
||||
std::fs::remove_file(path)?;
|
||||
}
|
||||
let mut file = File::create(path)?;
|
||||
file.write_all(&self.server_icon_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
16
src/lib.rs
16
src/lib.rs
@ -8,22 +8,13 @@ pub mod server;
|
||||
use crate::prelude::*;
|
||||
use std::sync::mpsc::{self, Receiver};
|
||||
|
||||
pub static PROTOCOL_VERSION: i32 = 757;
|
||||
lazy_static! {
|
||||
pub static ref CONFIG: Config = Config::from_file("composition.toml");
|
||||
pub static ref FAVICON: std::io::Result<Vec<u8>> = {
|
||||
use std::{fs::File, io::prelude::*};
|
||||
let mut data = vec![];
|
||||
let mut file = File::open(CONFIG.favicon.clone())?;
|
||||
file.read_to_end(&mut data)?;
|
||||
Ok(data)
|
||||
};
|
||||
pub static ref CONFIG: Config = Config::load();
|
||||
pub static ref START_TIME: std::time::Instant = std::time::Instant::now();
|
||||
}
|
||||
|
||||
/// Set up logging, read the config file, etc.
|
||||
pub fn init() -> Receiver<()> {
|
||||
// Load the START_TIME static - lazy_static lazy loads the value when first needed.
|
||||
let _ = START_TIME.elapsed();
|
||||
// Set up fern logging.
|
||||
fern::Dispatch::new()
|
||||
@ -57,7 +48,7 @@ pub async fn start_server() -> server::Server {
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::{config::Config, CONFIG, FAVICON, PROTOCOL_VERSION, START_TIME};
|
||||
pub use crate::{config::Config, CONFIG, START_TIME};
|
||||
pub use log::*;
|
||||
pub use serde::{Deserialize, Serialize};
|
||||
pub use serde_json::json;
|
||||
@ -65,8 +56,9 @@ pub mod prelude {
|
||||
pub type JSON = serde_json::Value;
|
||||
pub type NBT = quartz_nbt::NbtCompound;
|
||||
pub use std::collections::VecDeque;
|
||||
pub use std::io::{Read, Write};
|
||||
pub use substring::Substring;
|
||||
pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
pub use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ParseError {
|
||||
NotEnoughData,
|
||||
|
@ -222,8 +222,7 @@ impl Packet {
|
||||
"online": current_players,
|
||||
},
|
||||
"description": description,
|
||||
// TODO: Add base64 favicon
|
||||
"favicon": format!("data:image/png;base64,{}", radix64::STD_NO_PAD.encode(FAVICON.as_ref().unwrap())),
|
||||
"favicon": format!("data:image/png;base64,{}", radix64::STD_NO_PAD.encode(&CONFIG.server_icon_bytes)),
|
||||
})),
|
||||
),
|
||||
CS01Pong { payload } => (0x01, serialize_long(*payload).to_vec()),
|
||||
|
@ -108,10 +108,12 @@ impl Server {
|
||||
server_port: _,
|
||||
next_state,
|
||||
} => {
|
||||
if protocol_version != PROTOCOL_VERSION {
|
||||
if protocol_version != CONFIG.protocol_version
|
||||
&& next_state == NetworkClientState::Login
|
||||
{
|
||||
debug!(
|
||||
"Disconnecting client {} for mismatched protocols: {} (expected {})",
|
||||
client.id, protocol_version, PROTOCOL_VERSION
|
||||
client.id, protocol_version, CONFIG.protocol_version
|
||||
);
|
||||
client.disconnect(None).await;
|
||||
return Err(());
|
||||
@ -121,8 +123,8 @@ impl Server {
|
||||
SS00Request => {
|
||||
let _ = client
|
||||
.send_packet(CS00Response {
|
||||
version_name: "1.18.1".to_owned(),
|
||||
protocol_version: PROTOCOL_VERSION,
|
||||
version_name: CONFIG.game_version.clone(),
|
||||
protocol_version: CONFIG.protocol_version,
|
||||
max_players: CONFIG.max_players,
|
||||
current_players,
|
||||
description: json!({
|
||||
|
Loading…
x
Reference in New Issue
Block a user