Skip to main content

mc_minder/config/
mod.rs

1use serde::Deserialize;
2use std::path::PathBuf;
3use anyhow::{Result, Context};
4
5#[derive(Debug, Deserialize, Clone)]
6pub struct Config {
7    pub rcon: RconConfig,
8    pub ai: Option<AiConfig>,
9    pub ollama: Option<OllamaConfig>,
10    #[serde(default)]
11    pub server: ServerConfig,
12    #[serde(default)]
13    pub backup: BackupConfig,
14    #[serde(default)]
15    pub notification: NotificationConfig,
16    #[serde(default)]
17    #[allow(dead_code)]
18    pub jvm: JvmConfig,
19}
20
21#[derive(Debug, Deserialize, Clone)]
22pub struct RconConfig {
23    #[serde(default = "default_rcon_host")]
24    pub host: String,
25    #[serde(default = "default_rcon_port")]
26    pub port: u16,
27    pub password: String,
28}
29
30fn default_rcon_host() -> String { "127.0.0.1".to_string() }
31fn default_rcon_port() -> u16 { 25575 }
32
33#[derive(Debug, Deserialize, Clone)]
34pub struct ServerConfig {
35    #[serde(default = "default_jar")]
36    pub jar: String,
37    #[serde(default = "default_min_mem")]
38    pub min_mem: String,
39    #[serde(default = "default_max_mem")]
40    pub max_mem: String,
41    #[serde(default = "default_session_name")]
42    pub session_name: String,
43    #[serde(default = "default_log_file")]
44    pub log_file: String,
45}
46
47fn default_jar() -> String { "fabric-server.jar".to_string() }
48fn default_min_mem() -> String { "512M".to_string() }
49fn default_max_mem() -> String { "1G".to_string() }
50fn default_session_name() -> String { "mc_server".to_string() }
51fn default_log_file() -> String { "logs/latest.log".to_string() }
52
53impl Default for ServerConfig {
54    fn default() -> Self {
55        Self {
56            jar: default_jar(),
57            min_mem: default_min_mem(),
58            max_mem: default_max_mem(),
59            session_name: default_session_name(),
60            log_file: default_log_file(),
61        }
62    }
63}
64
65#[derive(Debug, Deserialize, Clone)]
66pub struct AiConfig {
67    pub api_url: String,
68    pub api_key: String,
69    #[serde(default = "default_model")]
70    pub model: String,
71    #[serde(default = "default_trigger")]
72    pub trigger: String,
73    #[serde(default = "default_max_tokens")]
74    pub max_tokens: u32,
75    #[serde(default = "default_temperature")]
76    pub temperature: f32,
77}
78
79fn default_model() -> String { "gpt-3.5-turbo".to_string() }
80fn default_trigger() -> String { "!".to_string() }
81fn default_max_tokens() -> u32 { 150 }
82fn default_temperature() -> f32 { 0.7 }
83
84#[derive(Debug, Deserialize, Clone)]
85pub struct OllamaConfig {
86    #[serde(default = "default_ollama_enabled")]
87    pub enabled: bool,
88    #[serde(default = "default_ollama_url")]
89    pub url: String,
90    #[serde(default = "default_ollama_model")]
91    pub model: String,
92}
93
94fn default_ollama_enabled() -> bool { false }
95fn default_ollama_url() -> String { "http://localhost:11434/api/generate".to_string() }
96fn default_ollama_model() -> String { "qwen:0.5b".to_string() }
97
98#[derive(Debug, Deserialize, Clone)]
99pub struct BackupConfig {
100    #[serde(default = "default_world_dir")]
101    pub world_dir: String,
102    #[serde(default = "default_backup_dest")]
103    pub backup_dest: String,
104    #[serde(default = "default_retain_days")]
105    pub retain_days: u32,
106}
107
108fn default_world_dir() -> String { "world".to_string() }
109fn default_backup_dest() -> String { "../backups".to_string() }
110fn default_retain_days() -> u32 { 7 }
111
112impl Default for BackupConfig {
113    fn default() -> Self {
114        Self {
115            world_dir: default_world_dir(),
116            backup_dest: default_backup_dest(),
117            retain_days: default_retain_days(),
118        }
119    }
120}
121
122#[derive(Debug, Deserialize, Clone)]
123#[allow(dead_code)]
124pub struct NotificationConfig {
125    #[serde(default)]
126    pub telegram_bot_token: String,
127    #[serde(default)]
128    pub telegram_chat_id: String,
129    #[serde(default = "default_termux_notify")]
130    pub termux_notify: bool,
131}
132
133fn default_termux_notify() -> bool { true }
134
135impl Default for NotificationConfig {
136    fn default() -> Self {
137        Self {
138            telegram_bot_token: String::new(),
139            telegram_chat_id: String::new(),
140            termux_notify: default_termux_notify(),
141        }
142    }
143}
144
145#[derive(Debug, Deserialize, Clone)]
146#[allow(dead_code)]
147pub struct JvmConfig {
148    #[serde(default = "default_gc")]
149    pub gc: String,
150    #[serde(default)]
151    pub extra_flags: String,
152    #[serde(default)]
153    pub xmx: Option<String>,
154    #[serde(default)]
155    pub xms: Option<String>,
156}
157
158fn default_gc() -> String { "G1GC".to_string() }
159
160impl Default for JvmConfig {
161    fn default() -> Self {
162        Self {
163            gc: default_gc(),
164            extra_flags: String::new(),
165            xmx: None,
166            xms: None,
167        }
168    }
169}
170
171impl Config {
172    pub fn load(path: &PathBuf) -> Result<Self> {
173        let content = std::fs::read_to_string(path)
174            .with_context(|| format!("Failed to read config file: {:?}", path))?;
175        
176        Self::load_from_str(&content)
177    }
178
179    pub fn load_from_str(content: &str) -> Result<Self> {
180        let mut config: Config = toml::from_str(content)
181            .with_context(|| "Failed to parse config file")?;
182        
183        if let Some(ref ai) = config.ai {
184            if ai.api_key.is_empty() || ai.api_url.is_empty() {
185                config.ai = None;
186            }
187        }
188        
189        Ok(config)
190    }
191
192    pub fn generate_template() -> String {
193        r#"# MC-Minder Configuration File
194# MC-Minder 配置文件
195
196# Server Configuration
197# 服务器配置
198[server]
199jar = "fabric-server.jar"
200min_mem = "512M"
201max_mem = "1G"
202session_name = "mc_server"
203log_file = "logs/latest.log"
204
205# RCON Configuration - Required for MC-Minder to communicate with Minecraft server
206# RCON 配置 - MC-Minder 与 Minecraft 服务器通信必需
207[rcon]
208host = "127.0.0.1"
209port = 25575
210password = "your_rcon_password"
211
212# AI Configuration - Leave empty or remove this section to disable AI features
213# AI 配置 - 留空或删除此部分可禁用 AI 功能
214[ai]
215api_url = ""
216api_key = ""
217model = "gpt-3.5-turbo"
218trigger = "!"
219max_tokens = 150
220temperature = 0.7
221
222# Ollama Configuration - Set enabled = true to use local AI
223# Ollama 配置 - 设置 enabled = true 使用本地 AI
224[ollama]
225enabled = false
226url = "http://localhost:11434/api/generate"
227model = "qwen:0.5b"
228
229# Backup Configuration
230# 备份配置
231[backup]
232world_dir = "world"
233backup_dest = "../backups"
234retain_days = 7
235
236# Notification Configuration - Leave empty to disable notifications
237# 通知配置 - 留空禁用通知功能
238[notification]
239telegram_bot_token = ""
240telegram_chat_id = ""
241termux_notify = true
242
243# JVM Configuration - Advanced JVM tuning options
244# JVM 配置 - 高级 JVM 调优选项
245[jvm]
246gc = "G1GC"
247extra_flags = ""
248# xmx = "2G"  # Uncomment to override server.max_mem
249# xms = "512M"  # Uncomment to override server.min_mem
250"#.to_string()
251    }
252}