Move more things into Config

This commit is contained in:
Garen Tyler 2022-04-21 09:14:55 -06:00
parent b4ed1572e9
commit 182bf76835
No known key found for this signature in database
GPG Key ID: E3BF83D66394FD92
5 changed files with 197 additions and 95 deletions

View File

@ -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"

View File

@ -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(())
}
}

View File

@ -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,

View File

@ -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()),

View File

@ -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!({