Improve configuration file parsing, add log_level to config, log server version, and move mctypes into crate::net
This commit is contained in:
parent
4d928973a6
commit
4849a7903d
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -117,6 +117,7 @@ dependencies = [
|
|||||||
"radix64",
|
"radix64",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"substring",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -539,6 +540,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "substring"
|
||||||
|
version = "1.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.91"
|
version = "1.0.91"
|
||||||
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "composition"
|
name = "composition"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1.48"
|
async-trait = "0.1.48"
|
||||||
@ -21,6 +22,7 @@ serde_json = "1.0.59"
|
|||||||
tokio = {version = "1", features = ["full"]}
|
tokio = {version = "1", features = ["full"]}
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
uuid = "0.8.2"
|
uuid = "0.8.2"
|
||||||
|
substring = "1.4.5"
|
||||||
|
|
||||||
# colorful = "0.2.1"
|
# colorful = "0.2.1"
|
||||||
# ozelot = "0.9.0" # Ozelot 0.9.0 supports protocol version 578 (1.15.2)
|
# ozelot = "0.9.0" # Ozelot 0.9.0 supports protocol version 578 (1.15.2)
|
||||||
|
9
build.rs
Normal file
9
build.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
fn main() {
|
||||||
|
if let Ok(output) = Command::new("git").args(&["rev-parse", "HEAD"]).output() {
|
||||||
|
let git_hash = String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
|
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||||
|
} else {
|
||||||
|
println!("cargo:rustc-env=GIT_HASH=00000000");
|
||||||
|
}
|
||||||
|
}
|
@ -2,3 +2,4 @@ favicon = "server-icon.png"
|
|||||||
max_players = 20
|
max_players = 20
|
||||||
motd = "Hello world!"
|
motd = "Hello world!"
|
||||||
port = 25565
|
port = 25565
|
||||||
|
log_level = "debug"
|
138
src/config.rs
Normal file
138
src/config.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub port: u16,
|
||||||
|
pub max_players: usize,
|
||||||
|
pub motd: String,
|
||||||
|
pub favicon: String,
|
||||||
|
pub server_string: String,
|
||||||
|
pub log_level: log::LevelFilter,
|
||||||
|
pub server_version: String,
|
||||||
|
}
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
let server_version = format!(
|
||||||
|
"composition/{} ({})",
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
env!("GIT_HASH").substring(0, 8)
|
||||||
|
);
|
||||||
|
Config {
|
||||||
|
port: 25565,
|
||||||
|
max_players: 20,
|
||||||
|
motd: "Hello world!".to_owned(),
|
||||||
|
favicon: "server-icon.png".to_owned(),
|
||||||
|
server_string: server_version.clone(),
|
||||||
|
log_level: if cfg!(debug_assertions) {
|
||||||
|
log::LevelFilter::Debug
|
||||||
|
} else {
|
||||||
|
log::LevelFilter::Info
|
||||||
|
},
|
||||||
|
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 {
|
||||||
|
let mut config = Config::default();
|
||||||
|
|
||||||
|
let get_string = |cfg: &toml::Value, field: &str, default: &str, error: &str| -> String {
|
||||||
|
if let Some(s) = cfg.get(field) {
|
||||||
|
if let Some(s) = s.as_str() {
|
||||||
|
return s.to_owned();
|
||||||
|
} else {
|
||||||
|
warn!("{}", error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("{}", error);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
config.port = port as u16;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"Config port must be an integer in the range of {}-{}, using default port: {}",
|
||||||
|
u16::MIN,
|
||||||
|
u16::MAX,
|
||||||
|
config.port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(&toml::Value::Integer(max_players)) = cfg.get("max_players") {
|
||||||
|
if max_players < 0 {
|
||||||
|
warn!("Config max_players must be an integer in the range of {}-{}, using default max_players: {}", usize::MIN, usize::MAX, config.max_players);
|
||||||
|
} else {
|
||||||
|
config.max_players = max_players as usize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Config max_players must be an integer in the range of {}-{}, using default max_players: {}", usize::MIN, usize::MAX, config.max_players);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.motd = get_string(
|
||||||
|
&cfg,
|
||||||
|
"motd",
|
||||||
|
&config.motd,
|
||||||
|
&format!(
|
||||||
|
"Config motd must be a string, using default motd: \"{}\"",
|
||||||
|
config.motd
|
||||||
|
),
|
||||||
|
);
|
||||||
|
config.favicon = get_string(
|
||||||
|
&cfg,
|
||||||
|
"favicon",
|
||||||
|
&config.favicon,
|
||||||
|
&format!(
|
||||||
|
"Config favicon must be a string, using default favicon: \"{}\"",
|
||||||
|
config.favicon
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let default_log_level = format!("{}", config.log_level).to_ascii_lowercase();
|
||||||
|
config.log_level = match &get_string(
|
||||||
|
&cfg,
|
||||||
|
"log_level",
|
||||||
|
&default_log_level,
|
||||||
|
&format!(
|
||||||
|
"Config log_level must be a string, using default log_level: {}",
|
||||||
|
default_log_level
|
||||||
|
),
|
||||||
|
)[..]
|
||||||
|
{
|
||||||
|
"off" => log::LevelFilter::Off,
|
||||||
|
"error" => log::LevelFilter::Error,
|
||||||
|
"warn" => log::LevelFilter::Warn,
|
||||||
|
"info" => log::LevelFilter::Info,
|
||||||
|
"debug" => log::LevelFilter::Debug,
|
||||||
|
"trace" => log::LevelFilter::Trace,
|
||||||
|
_ => {
|
||||||
|
warn!("Config log_level must be one of the predefined levels: off, error, warn, info, debug, trace");
|
||||||
|
config.log_level
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
config
|
||||||
|
} else {
|
||||||
|
warn!("Could not parse configuration file, using default");
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/lib.rs
48
src/lib.rs
@ -1,50 +1,16 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
pub mod mctypes;
|
pub mod config;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::sync::mpsc::{self, Receiver};
|
use std::sync::mpsc::{self, Receiver};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Config {
|
|
||||||
pub port: u16,
|
|
||||||
pub max_players: usize,
|
|
||||||
pub motd: String,
|
|
||||||
pub favicon: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static PROTOCOL_VERSION: i32 = 757;
|
pub static PROTOCOL_VERSION: i32 = 757;
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CONFIG: Config = {
|
pub static ref CONFIG: Config = Config::from_file("composition.toml");
|
||||||
let config_from_file = || -> std::io::Result<Config> {
|
|
||||||
use std::{fs::File, io::prelude::*};
|
|
||||||
let mut data = String::new();
|
|
||||||
let mut file = File::open("composition.toml")?;
|
|
||||||
file.read_to_string(&mut data)?;
|
|
||||||
if let Ok(c) = toml::from_str::<Config>(&data) {
|
|
||||||
Ok(c)
|
|
||||||
} else {
|
|
||||||
Err(std::io::Error::new(
|
|
||||||
std::io::ErrorKind::Other,
|
|
||||||
"Could not parse toml",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Ok(c) = config_from_file() {
|
|
||||||
c
|
|
||||||
} else {
|
|
||||||
warn!("Could not load config from file, using default");
|
|
||||||
Config {
|
|
||||||
port: 25565,
|
|
||||||
max_players: 20,
|
|
||||||
motd: "Hello world!".to_owned(),
|
|
||||||
favicon: "server-icon.png".to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub static ref FAVICON: std::io::Result<Vec<u8>> = {
|
pub static ref FAVICON: std::io::Result<Vec<u8>> = {
|
||||||
use std::{fs::File, io::prelude::*};
|
use std::{fs::File, io::prelude::*};
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
@ -70,15 +36,12 @@ pub fn init() -> Receiver<()> {
|
|||||||
message = message,
|
message = message,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.level(if cfg!(debug_assertions) {
|
.level(log::LevelFilter::Trace)
|
||||||
log::LevelFilter::Debug
|
|
||||||
} else {
|
|
||||||
log::LevelFilter::Info
|
|
||||||
})
|
|
||||||
.chain(std::io::stdout())
|
.chain(std::io::stdout())
|
||||||
.chain(fern::log_file("output.log").unwrap())
|
.chain(fern::log_file("output.log").unwrap())
|
||||||
.apply()
|
.apply()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
log::set_max_level(CONFIG.log_level);
|
||||||
// Set up the ctrl-c handler.
|
// Set up the ctrl-c handler.
|
||||||
let (ctrlc_tx, ctrlc_rx) = mpsc::channel();
|
let (ctrlc_tx, ctrlc_rx) = mpsc::channel();
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
@ -94,7 +57,7 @@ pub async fn start_server() -> server::Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{mctypes::*, CONFIG, FAVICON, PROTOCOL_VERSION, START_TIME};
|
pub use crate::{config::Config, CONFIG, FAVICON, PROTOCOL_VERSION, START_TIME};
|
||||||
pub use log::*;
|
pub use log::*;
|
||||||
pub use serde::{Deserialize, Serialize};
|
pub use serde::{Deserialize, Serialize};
|
||||||
pub use serde_json::json;
|
pub use serde_json::json;
|
||||||
@ -102,6 +65,7 @@ pub mod prelude {
|
|||||||
pub type JSON = serde_json::Value;
|
pub type JSON = serde_json::Value;
|
||||||
pub type NBT = fastnbt::Value;
|
pub type NBT = fastnbt::Value;
|
||||||
pub use std::collections::VecDeque;
|
pub use std::collections::VecDeque;
|
||||||
|
pub use substring::Substring;
|
||||||
pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
pub use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
|
@ -5,7 +5,7 @@ use std::time::Duration;
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
let ctrlc_rx = composition::init();
|
let ctrlc_rx = composition::init();
|
||||||
info!("Starting server...");
|
info!("Starting {}", composition::CONFIG.server_version);
|
||||||
let mut server = composition::start_server().await;
|
let mut server = composition::start_server().await;
|
||||||
info!("Done! Start took {:?}", composition::START_TIME.elapsed());
|
info!("Done! Start took {:?}", composition::START_TIME.elapsed());
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
pub mod mctypes;
|
||||||
pub mod packets;
|
pub mod packets;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use mctypes::*;
|
||||||
pub use packets::Packet;
|
pub use packets::Packet;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::NetworkClientState;
|
use super::{mctypes::*, NetworkClientState};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user