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 backup: BackupConfig,
12    #[serde(default)]
13    pub notification: NotificationConfig,
14}
15
16#[derive(Debug, Deserialize, Clone)]
17pub struct RconConfig {
18    #[serde(default = "default_rcon_host")]
19    pub host: String,
20    #[serde(default = "default_rcon_port")]
21    pub port: u16,
22    pub password: String,
23}
24
25fn default_rcon_host() -> String { "127.0.0.1".to_string() }
26fn default_rcon_port() -> u16 { 25575 }
27
28#[derive(Debug, Deserialize, Clone)]
29pub struct AiConfig {
30    pub api_url: String,
31    pub api_key: String,
32    #[serde(default = "default_model")]
33    pub model: String,
34    #[serde(default = "default_trigger")]
35    pub trigger: String,
36    #[serde(default = "default_max_tokens")]
37    pub max_tokens: u32,
38    #[serde(default = "default_temperature")]
39    pub temperature: f32,
40}
41
42fn default_model() -> String { "gpt-3.5-turbo".to_string() }
43fn default_trigger() -> String { "!".to_string() }
44fn default_max_tokens() -> u32 { 150 }
45fn default_temperature() -> f32 { 0.7 }
46
47#[derive(Debug, Deserialize, Clone)]
48pub struct OllamaConfig {
49    #[serde(default = "default_ollama_enabled")]
50    pub enabled: bool,
51    #[serde(default = "default_ollama_url")]
52    pub url: String,
53    #[serde(default = "default_ollama_model")]
54    pub model: String,
55}
56
57fn default_ollama_enabled() -> bool { false }
58fn default_ollama_url() -> String { "http://localhost:11434/api/generate".to_string() }
59fn default_ollama_model() -> String { "qwen:0.5b".to_string() }
60
61#[derive(Debug, Deserialize, Clone)]
62pub struct BackupConfig {
63    #[serde(default = "default_world_dir")]
64    pub world_dir: String,
65    #[serde(default = "default_backup_dest")]
66    pub backup_dest: String,
67    #[serde(default = "default_retain_days")]
68    pub retain_days: u32,
69}
70
71fn default_world_dir() -> String { "world".to_string() }
72fn default_backup_dest() -> String { "../backups".to_string() }
73fn default_retain_days() -> u32 { 7 }
74
75impl Default for BackupConfig {
76    fn default() -> Self {
77        Self {
78            world_dir: default_world_dir(),
79            backup_dest: default_backup_dest(),
80            retain_days: default_retain_days(),
81        }
82    }
83}
84
85#[derive(Debug, Deserialize, Clone)]
86pub struct NotificationConfig {
87    #[serde(default)]
88    pub telegram_bot_token: String,
89    #[serde(default)]
90    pub telegram_chat_id: String,
91    #[serde(default = "default_termux_notify")]
92    pub termux_notify: bool,
93}
94
95fn default_termux_notify() -> bool { true }
96
97impl Default for NotificationConfig {
98    fn default() -> Self {
99        Self {
100            telegram_bot_token: String::new(),
101            telegram_chat_id: String::new(),
102            termux_notify: default_termux_notify(),
103        }
104    }
105}
106
107impl Config {
108    pub fn load(path: &PathBuf) -> Result<Self> {
109        let content = std::fs::read_to_string(path)
110            .with_context(|| format!("Failed to read config file: {:?}", path))?;
111        
112        let mut config: Config = toml::from_str(&content)
113            .with_context(|| "Failed to parse config file")?;
114        
115        if let Some(ref ai) = config.ai {
116            if ai.api_key.is_empty() || ai.api_url.is_empty() {
117                config.ai = None;
118            }
119        }
120        
121        Ok(config)
122    }
123
124    pub fn load_from_str(content: &str) -> Result<Self> {
125        let mut config: Config = toml::from_str(content)
126            .with_context(|| "Failed to parse config content")?;
127        
128        if let Some(ref ai) = config.ai {
129            if ai.api_key.is_empty() || ai.api_url.is_empty() {
130                config.ai = None;
131            }
132        }
133        
134        Ok(config)
135    }
136}