diff --git a/Cargo.lock b/Cargo.lock index d3c385f..0468a05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,7 @@ dependencies = [ "async-trait", "base64", "clap", + "const_format", "nom", "once_cell", "serde", @@ -188,6 +189,26 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -782,6 +803,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "utf8parse" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 4c6aaff..c6cdab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ tracing = { version = "0.1.37", features = ["log"] } tracing-subscriber = { version = "0.3.17", features = ["tracing-log"] } tracing-appender = "0.2.2" nom = "7.1.3" +const_format = "0.2.33" diff --git a/src/config.rs b/src/config.rs index 815fabd..21c4948 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,6 @@ use clap::Arg; -use once_cell::sync::{Lazy, OnceCell}; +use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; -use std::ffi::OsStr; use std::io::{Read, Write}; use std::{fs::File, path::Path, path::PathBuf}; use tracing::{error, trace, warn}; @@ -18,7 +17,8 @@ pub static CONFIG: OnceCell = OnceCell::new(); /// The globablly-accessible static instance of Args. /// On program startup, Args::load() should be called to initialize it. pub static ARGS: OnceCell = OnceCell::new(); -static DEFAULT_ARGS: Lazy = Lazy::new(Args::default); +const DEFAULT_CONFIG_FILE: &str = "composition.toml"; +const DEFAULT_LOG_DIR: &str = "logs"; /// Helper function to read a file from a `Path` /// and return its bytes as a `Vec`. @@ -140,8 +140,8 @@ impl Default for GlobalConfig { fn default() -> Self { GlobalConfig { version: Config::get_formatted_version(Subcommand::None), - protocol_version: 762, - game_version: "1.19.4".to_owned(), + protocol_version: crate::PROTOCOL_VERSION, + game_version: crate::GAME_VERSION.to_owned(), threads: None, } } @@ -179,9 +179,9 @@ pub struct Args { impl Default for Args { fn default() -> Self { Args { - config_file: PathBuf::from("composition.toml"), + config_file: PathBuf::from(DEFAULT_CONFIG_FILE), log_level: None, - log_dir: PathBuf::from("logs"), + log_dir: PathBuf::from(DEFAULT_LOG_DIR), subcommand: Subcommand::None, #[cfg(feature = "server")] server: None, @@ -229,7 +229,7 @@ impl Args { .help("Configuration file path") .global(true) .value_hint(clap::ValueHint::FilePath) - .default_value(OsStr::new(&DEFAULT_ARGS.config_file)), + .default_value(DEFAULT_CONFIG_FILE), ) .arg( Arg::new("log-level") @@ -248,7 +248,7 @@ impl Args { .global(true) .value_name("dir") .value_hint(clap::ValueHint::DirPath) - .default_value(OsStr::new(&DEFAULT_ARGS.log_dir)), + .default_value(DEFAULT_LOG_DIR), ); #[cfg(feature = "server")] { diff --git a/src/lib.rs b/src/lib.rs index 88ae50d..f32d383 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,9 @@ use config::Subcommand; use once_cell::sync::OnceCell; use std::time::Instant; +pub const PROTOCOL_VERSION: i32 = 762; +pub const GAME_VERSION: &str = "1.19.4"; + /// A globally accessible instant of the composition's start time. /// /// This should be set immediately on startup. diff --git a/src/proxy/config.rs b/src/proxy/config.rs index 1d5f9cf..13a66c7 100644 --- a/src/proxy/config.rs +++ b/src/proxy/config.rs @@ -1,10 +1,10 @@ use crate::config::{Args, Config}; use clap::Arg; -use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use std::ffi::OsStr; -pub static DEFAULT_PROXY_ARGS: Lazy = Lazy::new(ProxyArgs::default); +const DEFAULT_PORT: u16 = 25566; +const DEFAULT_UPSTREAM_HOST: &str = "127.0.0.1"; +const DEFAULT_UPSTREAM_PORT: u16 = 25565; /// The main server configuration struct. #[derive(Debug, Deserialize, Serialize)] @@ -14,14 +14,16 @@ pub struct ProxyConfig { #[serde(rename = "version-string")] pub version: String, pub port: u16, - pub upstream: String, + pub upstream_host: String, + pub upstream_port: u16, } impl Default for ProxyConfig { fn default() -> Self { ProxyConfig { version: Config::get_formatted_version(crate::config::Subcommand::Proxy), - port: 25565, - upstream: String::new(), + port: DEFAULT_PORT, + upstream_host: DEFAULT_UPSTREAM_HOST.to_owned(), + upstream_port: DEFAULT_UPSTREAM_PORT, } } } @@ -30,16 +32,27 @@ impl ProxyConfig { &Config::instance().proxy } pub fn load_args(&mut self) { - self.upstream = ProxyArgs::instance() + self.upstream_host = ProxyArgs::instance() .as_ref() - .map(|p| p.upstream.clone()) - .unwrap_or(DEFAULT_PROXY_ARGS.upstream.clone()); + .map(|p| p.upstream_host.clone()) + .unwrap_or(DEFAULT_UPSTREAM_HOST.to_owned()); } } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ProxyArgs { - upstream: String, + port: u16, + upstream_host: String, + upstream_port: u16, +} +impl Default for ProxyArgs { + fn default() -> Self { + ProxyArgs { + port: DEFAULT_PORT, + upstream_host: DEFAULT_UPSTREAM_HOST.to_owned(), + upstream_port: DEFAULT_UPSTREAM_PORT, + } + } } impl ProxyArgs { pub fn instance() -> Option<&'static Self> { @@ -49,20 +62,40 @@ impl ProxyArgs { clap::Command::new("proxy") .about("Run composition in proxy mode") .arg( - Arg::new("upstream") - .short('u') - .long("upstream") + Arg::new("port") + .short('p') + .long("port") + .help("Proxy listening port") + .value_hint(clap::ValueHint::Other) + .default_value(const_format::formatcp!("{}", DEFAULT_PORT)), + ) + .arg( + Arg::new("upstream-host") + .short('U') + .long("upstream-host") .help("Upstream server address") .value_hint(clap::ValueHint::Hostname) - .default_value(OsStr::new(&DEFAULT_PROXY_ARGS.upstream)), + .default_value(const_format::formatcp!("{}", DEFAULT_UPSTREAM_HOST)), + ) + .arg( + Arg::new("upstream-port") + .short('P') + .long("upstream-port") + .help("Upstream server port") + .value_hint(clap::ValueHint::Other) + .default_value(const_format::formatcp!("{}", DEFAULT_UPSTREAM_PORT)), ) } pub fn parse(m: clap::ArgMatches) -> Self { let mut proxy_args = ProxyArgs::default(); - proxy_args.upstream = m - .get_one::("upstream") - .unwrap_or(&proxy_args.upstream) + proxy_args.port = *m.get_one::("port").unwrap_or(&proxy_args.port); + proxy_args.upstream_host = m + .get_one::("upstream-host") + .unwrap_or(&proxy_args.upstream_host) .clone(); + proxy_args.upstream_port = *m + .get_one::("upstream-port") + .unwrap_or(&proxy_args.upstream_port); proxy_args } } diff --git a/src/proxy/mod.rs b/src/proxy/mod.rs index 27123e3..cda73e7 100644 --- a/src/proxy/mod.rs +++ b/src/proxy/mod.rs @@ -23,7 +23,10 @@ impl Proxy { "Done! Start took {:?}", crate::START_TIME.get().unwrap().elapsed() ); - info!("Upstream server: {}", config.proxy.upstream); + info!( + "Upstream server: {}:{}", + config.proxy.upstream_host, config.proxy.upstream_port + ); // Spawn the ctrl-c task. let r = running.clone(); diff --git a/src/server/config.rs b/src/server/config.rs index ab2aa21..bef738b 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -1,13 +1,11 @@ use crate::config::{read_file, Args, Config}; use clap::Arg; -use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; -use std::ffi::OsStr; use std::io::Write; use std::{fs::File, path::Path, path::PathBuf}; use tracing::{error, trace, warn}; -pub static DEFAULT_SERVER_ARGS: Lazy = Lazy::new(ServerArgs::default); +const DEFAULT_SERVER_ICON: &str = "server-icon.png"; /// The main server configuration struct. #[derive(Debug, Deserialize, Serialize)] @@ -30,7 +28,7 @@ impl Default for ServerConfig { port: 25565, max_players: 20, motd: "Hello world!".to_owned(), - server_icon: PathBuf::from("server-icon.png"), + server_icon: PathBuf::from(DEFAULT_SERVER_ICON), server_icon_bytes: include_bytes!("../server-icon.png").to_vec(), } } @@ -43,7 +41,7 @@ impl ServerConfig { self.server_icon = ServerArgs::instance() .as_ref() .map(|s| s.server_icon.clone()) - .unwrap_or(DEFAULT_SERVER_ARGS.server_icon.clone()); + .unwrap_or(PathBuf::from(DEFAULT_SERVER_ICON)); self.load_icon(); } /// Load the server icon. @@ -87,9 +85,8 @@ pub struct ServerArgs { } impl Default for ServerArgs { fn default() -> Self { - let config = Config::default(); ServerArgs { - server_icon: config.server.server_icon, + server_icon: PathBuf::from(DEFAULT_SERVER_ICON), } } } @@ -105,7 +102,7 @@ impl ServerArgs { .long("server-icon") .help("Server icon file path") .value_hint(clap::ValueHint::FilePath) - .default_value(OsStr::new(&DEFAULT_SERVER_ARGS.server_icon)), + .default_value(DEFAULT_SERVER_ICON), ) } pub fn parse(m: clap::ArgMatches) -> Self {