1use crate::api::error::ApiError;
8use dirs::home_dir;
9use serde::{Deserialize, Serialize};
10use std::fs;
11use std::path::PathBuf;
12
13const CONFIG_DIR: &str = ".config/moltbook";
15const CONFIG_FILE: &str = "credentials.json";
17
18#[derive(Serialize, Deserialize, Debug)]
20pub struct Config {
21 pub api_key: String,
23 pub agent_name: String,
25}
26
27impl Config {
28 pub fn load() -> Result<Self, ApiError> {
36 let config_path = Self::get_config_path()?;
37
38 if !config_path.exists() {
39 return Err(ApiError::ConfigError(format!(
40 "Config file not found at: {}\nPlease create it with your API key.",
41 config_path.display()
42 )));
43 }
44
45 let content = fs::read_to_string(&config_path)
46 .map_err(|e| ApiError::ConfigError(format!("Failed to read config: {}", e)))?;
47
48 let config: Config = serde_json::from_str(&content)
49 .map_err(|e| ApiError::ConfigError(format!("Failed to parse config: {}", e)))?;
50
51 Ok(config)
52 }
53
54 fn get_config_path() -> Result<PathBuf, ApiError> {
60 if let Ok(config_dir) = std::env::var("MOLTBOOK_CONFIG_DIR") {
61 return Ok(PathBuf::from(config_dir).join(CONFIG_FILE));
62 }
63
64 let home = home_dir().ok_or_else(|| {
65 ApiError::ConfigError("Could not determine home directory".to_string())
66 })?;
67
68 Ok(home.join(CONFIG_DIR).join(CONFIG_FILE))
69 }
70
71 pub fn save(&self) -> Result<(), ApiError> {
76 let config_path = Self::get_config_path()?;
77 let config_dir = config_path.parent().unwrap();
78
79 if !config_dir.exists() {
80 fs::create_dir_all(config_dir).map_err(|e| {
81 ApiError::ConfigError(format!("Failed to create config dir: {}", e))
82 })?;
83 }
84
85 let content = serde_json::to_string_pretty(self)
86 .map_err(|e| ApiError::ConfigError(format!("Failed to serialize config: {}", e)))?;
87
88 fs::write(&config_path, content)
89 .map_err(|e| ApiError::ConfigError(format!("Failed to write config: {}", e)))?;
90
91 #[cfg(unix)]
92 {
93 use std::os::unix::fs::PermissionsExt;
94 let mut perms = fs::metadata(&config_path)
95 .map_err(|e| ApiError::ConfigError(format!("Failed to get metadata: {}", e)))?
96 .permissions();
97 perms.set_mode(0o600);
98 fs::set_permissions(&config_path, perms)
99 .map_err(|e| ApiError::ConfigError(format!("Failed to set permissions: {}", e)))?;
100 }
101
102 Ok(())
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_config_deserialization() {
112 let json = r#"{"api_key": "test_key", "agent_name": "test_agent"}"#;
113 let config: Config = serde_json::from_str(json).unwrap();
114 assert_eq!(config.api_key, "test_key");
115 assert_eq!(config.agent_name, "test_agent");
116 }
117
118 #[test]
119 fn test_missing_fields() {
120 let json = r#"{"api_key": "test_key"}"#;
121 let result: Result<Config, _> = serde_json::from_str(json);
122 assert!(result.is_err());
123 }
124}