diff options
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/file.rs | 26 | ||||
| -rw-r--r-- | src/config/loader.rs | 129 | ||||
| -rw-r--r-- | src/config/mod.rs | 17 | ||||
| -rw-r--r-- | src/config/runtime.rs | 95 |
4 files changed, 206 insertions, 61 deletions
diff --git a/src/config/file.rs b/src/config/file.rs new file mode 100644 index 0000000..17f2cb2 --- /dev/null +++ b/src/config/file.rs | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | use std::path::PathBuf; | ||
| 2 | |||
| 3 | use serde::Deserialize; | ||
| 4 | |||
| 5 | use crate::minecraft::launcher::JavaRuntime; | ||
| 6 | |||
| 7 | #[derive(Debug, Deserialize)] | ||
| 8 | pub struct FileConfig { | ||
| 9 | pub username: String, | ||
| 10 | pub uuid: String, | ||
| 11 | pub version: String, | ||
| 12 | pub max_memory_mb: u32, | ||
| 13 | |||
| 14 | #[serde(default)] | ||
| 15 | pub jvm_args: Vec<String>, | ||
| 16 | |||
| 17 | #[serde(default)] | ||
| 18 | pub runtimes: Vec<JavaRuntime>, | ||
| 19 | |||
| 20 | #[serde(default)] | ||
| 21 | pub java_path: String, | ||
| 22 | |||
| 23 | pub data_dir: PathBuf, | ||
| 24 | // pub cache_dir: PathBuf, | ||
| 25 | // pub config_dir: PathBuf, | ||
| 26 | } | ||
diff --git a/src/config/loader.rs b/src/config/loader.rs index d4b142e..47514e5 100644 --- a/src/config/loader.rs +++ b/src/config/loader.rs | |||
| @@ -1,65 +1,90 @@ | |||
| 1 | use std::{env::var, fs::read_to_string, path::PathBuf}; | 1 | use std::{env, fs::read_to_string, path::PathBuf}; |
| 2 | |||
| 3 | use directories::ProjectDirs; | 2 | use directories::ProjectDirs; |
| 4 | use serde::Deserialize; | 3 | use uuid::Uuid; |
| 5 | 4 | ||
| 5 | use super::{file::FileConfig, runtime::RuntimeConfig}; | ||
| 6 | use crate::{constants::*, errors::McError}; | 6 | use crate::{constants::*, errors::McError}; |
| 7 | #[allow(dead_code)] | 7 | |
| 8 | #[derive(Debug, Deserialize)] | 8 | pub struct ConfigLoader; |
| 9 | pub struct Config { | 9 | |
| 10 | pub username: String, | 10 | impl ConfigLoader { |
| 11 | pub uuid: String, | 11 | pub fn load(cfg_file: Option<&PathBuf>) -> Result<RuntimeConfig, McError> { |
| 12 | pub version: String, | 12 | let path = match cfg_file { |
| 13 | pub java_path: String, | 13 | | Some(p) => p.clone(), |
| 14 | pub max_memory_mb: u32, | 14 | | None => Self::default_config_path()?, |
| 15 | pub data_dir: PathBuf, | 15 | }; |
| 16 | pub cache_dir: PathBuf, | 16 | |
| 17 | pub config_dir: PathBuf, | 17 | let mut file_cfg = if path.exists() { |
| 18 | #[serde(default)] | 18 | Self::read_file(&path)? |
| 19 | pub jvm_args: Vec<String>, | ||
| 20 | } | ||
| 21 | impl Config { | ||
| 22 | pub fn load() -> Result<Self, McError> { | ||
| 23 | let cfg_path = default_config_path()?; | ||
| 24 | let mut cfg: Config = if cfg_path.exists() { | ||
| 25 | let txt = read_to_string(&cfg_path)?; | ||
| 26 | toml::from_str(&txt).map_err(|e| McError::Config(e.to_string()))? | ||
| 27 | } else { | 19 | } else { |
| 28 | Self::default() | 20 | Self::default_file_config()? |
| 29 | }; | 21 | }; |
| 30 | if let Ok(v) = var("MC_USERNAME") { | 22 | |
| 31 | cfg.username = v; | 23 | Self::apply_env_overrides(&mut file_cfg); |
| 32 | } | 24 | |
| 33 | if let Ok(v) = var("MC_VERSION") { | 25 | Ok(RuntimeConfig::from_file(file_cfg)) |
| 34 | cfg.version = v; | 26 | } |
| 35 | } | 27 | |
| 36 | if let Ok(v) = var("MC_JAVA_PATH") { | 28 | fn read_file(path: &PathBuf) -> Result<FileConfig, McError> { |
| 37 | cfg.java_path = v; | 29 | let content = read_to_string(path).map_err(|e| { |
| 38 | } | 30 | McError::Config(format!( |
| 39 | if let Ok(v) = var("MC_MAX_MEMORY_MB") { | 31 | "Failed to read config file {}: {}", |
| 40 | cfg.max_memory_mb = v.parse().unwrap_or(cfg.max_memory_mb); | 32 | path.display(), |
| 41 | } | 33 | e |
| 42 | Ok(cfg) | 34 | )) |
| 35 | })?; | ||
| 36 | |||
| 37 | toml::from_str(&content).map_err(|e| { | ||
| 38 | McError::Config(format!("Failed to parse config file: {}", e)) | ||
| 39 | }) | ||
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | fn default() -> Self { | 42 | fn apply_env_overrides(cfg: &mut FileConfig) { |
| 46 | let base = | 43 | cfg.username = env::var(ENV_USERNAME) |
| 47 | ProjectDirs::from("com", "example", "dml").expect("platform dirs"); | 44 | .unwrap_or_else(|_| DEFAULT_USERNAME.to_string()); |
| 48 | Self { | 45 | |
| 49 | username: "Player".into(), | 46 | cfg.version = env::var(ENV_VERSION) |
| 50 | uuid: uuid::Uuid::new_v4().to_string(), | 47 | .unwrap_or_else(|_| DEFAULT_VERSION.to_string()); |
| 48 | |||
| 49 | cfg.java_path = env::var(ENV_JAVA_PATH) | ||
| 50 | .unwrap_or_else(|_| DEFAULT_JAVA_PATH.to_string()); | ||
| 51 | |||
| 52 | cfg.max_memory_mb = env::var(ENV_MAX_MEMORY_MB) | ||
| 53 | .ok() | ||
| 54 | .and_then(|v| v.parse().ok()) | ||
| 55 | .unwrap_or(DEFAULT_MAX_MEMORY_MB); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn default_config_path() -> Result<PathBuf, McError> { | ||
| 59 | let base = ProjectDirs::from( | ||
| 60 | DEFAULT_COMPANY, | ||
| 61 | DEFAULT_PROJECT_GROUP, | ||
| 62 | DEFAULT_PROJECT_NAME, | ||
| 63 | ) | ||
| 64 | .ok_or_else(|| McError::Config(DEFAULT_ERR_PLATFORM_DIR.into()))?; | ||
| 65 | |||
| 66 | Ok(base.config_dir().join(DEFAULT_CONFIG_FILENAME)) | ||
| 67 | } | ||
| 68 | |||
| 69 | fn default_file_config() -> Result<FileConfig, McError> { | ||
| 70 | let base = ProjectDirs::from( | ||
| 71 | DEFAULT_COMPANY, | ||
| 72 | DEFAULT_PROJECT_GROUP, | ||
| 73 | DEFAULT_PROJECT_NAME, | ||
| 74 | ) | ||
| 75 | .ok_or_else(|| McError::Config(DEFAULT_ERR_PLATFORM_DIR.into()))?; | ||
| 76 | |||
| 77 | Ok(FileConfig { | ||
| 78 | username: DEFAULT_USERNAME.into(), | ||
| 79 | uuid: Uuid::new_v4().to_string(), | ||
| 51 | version: DEFAULT_VERSION.into(), | 80 | version: DEFAULT_VERSION.into(), |
| 52 | java_path: DEFAULT_JAVA_PATH.into(), | ||
| 53 | max_memory_mb: DEFAULT_MAX_MEMORY_MB, | 81 | max_memory_mb: DEFAULT_MAX_MEMORY_MB, |
| 82 | java_path: DEFAULT_JAVA_PATH.into(), | ||
| 54 | data_dir: base.data_dir().into(), | 83 | data_dir: base.data_dir().into(), |
| 55 | cache_dir: base.cache_dir().into(), | 84 | // cache_dir: base.cache_dir().into(), |
| 56 | config_dir: base.config_dir().into(), | 85 | // config_dir: base.config_dir().into(), |
| 57 | jvm_args: vec![], | 86 | jvm_args: vec![], |
| 58 | } | 87 | runtimes: vec![], |
| 88 | }) | ||
| 59 | } | 89 | } |
| 60 | } | 90 | } |
| 61 | fn default_config_path() -> Result<PathBuf, McError> { | ||
| 62 | let base = ProjectDirs::from("com", "example", "dml") | ||
| 63 | .ok_or_else(|| McError::Config("cannot determine config dir".into()))?; | ||
| 64 | Ok(base.config_dir().join("config.toml")) | ||
| 65 | } | ||
diff --git a/src/config/mod.rs b/src/config/mod.rs index 066154a..a375dda 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | //! Configuration module for the DML launcher. | 1 | //! Configuration module for the DML launcher. |
| 2 | //! | ||
| 3 | //! This module contains submodules and helpers for loading, parsing, and | ||
| 4 | //! managing configuration files and settings. It abstracts the details | ||
| 5 | //! of where configuration is stored and how it is represented in memory. | ||
| 6 | //! | ||
| 7 | //! # Submodules | ||
| 8 | //! - `loader`: Functions to load and parse configuration from disk or | ||
| 9 | //! environment variables. | ||
| 10 | 2 | ||
| 3 | pub mod file; | ||
| 11 | pub mod loader; | 4 | pub mod loader; |
| 12 | pub use loader::Config; | 5 | pub mod runtime; |
| 6 | |||
| 7 | pub use loader::ConfigLoader; | ||
| 8 | pub use runtime::RuntimeConfig; | ||
| 9 | |||
| 10 | /// Backwards-compatibility alias so existing code can keep using `Config` | ||
| 11 | pub type Config = RuntimeConfig; | ||
diff --git a/src/config/runtime.rs b/src/config/runtime.rs new file mode 100644 index 0000000..46857f0 --- /dev/null +++ b/src/config/runtime.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | use std::path::PathBuf; | ||
| 2 | |||
| 3 | use super::file::FileConfig; | ||
| 4 | use crate::{constants::*, minecraft::launcher::JavaRuntime}; | ||
| 5 | |||
| 6 | /// Configuration for the runtime environment used to launch Minecraft. | ||
| 7 | /// | ||
| 8 | /// The `RuntimeConfig` struct holds the configuration settings required to | ||
| 9 | /// launch Minecraft with a specific Java runtime. This includes details about | ||
| 10 | /// the user, the Minecraft version, the available Java runtimes, and JVM options. | ||
| 11 | /// | ||
| 12 | /// The `RuntimeConfig` struct is typically used by the launcher to store and | ||
| 13 | /// manage the necessary settings for running the game. It also supports | ||
| 14 | /// dynamic configuration by allowing the addition of Java runtimes and the | ||
| 15 | /// specification of system paths and arguments. | ||
| 16 | #[derive(Debug)] | ||
| 17 | #[derive(Default)] | ||
| 18 | pub struct RuntimeConfig { | ||
| 19 | /// The username of the player running Minecraft. | ||
| 20 | pub username: String, | ||
| 21 | |||
| 22 | /// The UUID (unique identifier) of the user. | ||
| 23 | pub uuid: String, | ||
| 24 | |||
| 25 | /// The version of Minecraft that the user is running. | ||
| 26 | pub version: String, | ||
| 27 | |||
| 28 | /// The maximum amount of memory (in megabytes) allocated to the Java process. | ||
| 29 | /// This setting determines how much memory the Minecraft instance can use. | ||
| 30 | pub max_memory_mb: u32, | ||
| 31 | |||
| 32 | /// A list of arguments to pass to the JVM when launching Minecraft. | ||
| 33 | /// These arguments can be used to customize the JVM's behavior, such as | ||
| 34 | /// memory settings, garbage collection options, etc. | ||
| 35 | pub jvm_args: Vec<String>, | ||
| 36 | |||
| 37 | /// A list of Java runtime environments available for Minecraft. | ||
| 38 | /// If no specific Java runtime is provided, the default one is used. | ||
| 39 | pub runtimes: Vec<JavaRuntime>, | ||
| 40 | |||
| 41 | /// The directory where Minecraft data (e.g., worlds, logs, configs) is stored. | ||
| 42 | /// This path is critical for loading and saving game data. | ||
| 43 | pub data_dir: PathBuf, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl RuntimeConfig { | ||
| 47 | /// Creates a new `RuntimeConfig` instance from a `FileConfig`. | ||
| 48 | /// | ||
| 49 | /// This method takes a `FileConfig` object (typically loaded from a configuration file) | ||
| 50 | /// and constructs a `RuntimeConfig` instance. It ensures that if no runtimes are defined | ||
| 51 | /// but a Java path is provided, a default Java runtime is created based on the specified path. | ||
| 52 | /// | ||
| 53 | /// # Parameters | ||
| 54 | /// - `file`: A `FileConfig` instance containing initial configuration values for the | ||
| 55 | /// Minecraft runtime. This includes user details, Minecraft version, JVM arguments, | ||
| 56 | /// and the path to Java (if specified). | ||
| 57 | /// | ||
| 58 | /// # Returns | ||
| 59 | /// - A `RuntimeConfig` instance initialized with the values from `file`. If no runtimes | ||
| 60 | /// were provided in `file` but a Java path was given, the method will add a default Java runtime. | ||
| 61 | /// | ||
| 62 | /// # Example | ||
| 63 | /// ```rust | ||
| 64 | /// let file_config = FileConfig { | ||
| 65 | /// username: "Player1".into(), | ||
| 66 | /// uuid: "1234-5678-9101".into(), | ||
| 67 | /// version: "1.18.2".into(), | ||
| 68 | /// max_memory_mb: 2048, | ||
| 69 | /// jvm_args: vec!["-Xmx2G".into()], | ||
| 70 | /// runtimes: Vec::new(), | ||
| 71 | /// java_path: "/path/to/java".into(), | ||
| 72 | /// data_dir: "/path/to/minecraft/data".into(), | ||
| 73 | /// }; | ||
| 74 | /// | ||
| 75 | /// let runtime_config = RuntimeConfig::from_file(file_config); | ||
| 76 | /// ``` | ||
| 77 | pub fn from_file(mut file: FileConfig) -> Self { | ||
| 78 | if file.runtimes.is_empty() && !file.java_path.is_empty() { | ||
| 79 | file.runtimes.push(JavaRuntime { | ||
| 80 | major: DEFAULT_JAVA_MAJOR, | ||
| 81 | path: PathBuf::from(&file.java_path), | ||
| 82 | }); | ||
| 83 | } | ||
| 84 | |||
| 85 | Self { | ||
| 86 | username: file.username, | ||
| 87 | uuid: file.uuid, | ||
| 88 | version: file.version, | ||
| 89 | max_memory_mb: file.max_memory_mb, | ||
| 90 | jvm_args: file.jvm_args, | ||
| 91 | runtimes: file.runtimes, | ||
| 92 | data_dir: file.data_dir, | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
