1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Config {
6 pub api_key: String,
7 pub model_id: String,
8}
9
10impl Config {
11 pub fn load_from_path(path: &std::path::Path) -> Result<Self, ConfigError> {
12 let content = std::fs::read_to_string(path)?;
13 let config: Config =
14 serde_json::from_str(&content).map_err(|_| ConfigError::MalformedJson)?;
15 Ok(config)
16 }
17
18 pub fn save(&self, path: &std::path::Path) -> Result<(), ConfigError> {
19 let tmp_path = path.with_extension("json.tmp");
20 {
21 let mut file = std::fs::File::create(&tmp_path)?;
22 serde_json::to_writer_pretty(&mut file, self)?;
23 }
24
25 #[cfg(unix)]
26 {
27 use std::os::unix::fs::PermissionsExt;
28 let mut perms = std::fs::metadata(&tmp_path)?.permissions();
29 perms.set_mode(0o600);
30 std::fs::set_permissions(&tmp_path, perms)?;
31 }
32
33 std::fs::rename(&tmp_path, path)?;
34
35 Ok(())
36 }
37}
38
39#[derive(Debug)]
40pub enum ConfigError {
41 IoError(std::io::Error),
42 MalformedJson,
43 ApiError(String),
44 HomeNotFound,
45}
46
47impl fmt::Display for ConfigError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 ConfigError::IoError(e) => write!(f, "IO error: {}", e),
51 ConfigError::MalformedJson => write!(f, "Malformed JSON"),
52 ConfigError::ApiError(msg) => write!(f, "API error: {}", msg),
53 ConfigError::HomeNotFound => write!(f, "Cannot find home directory"),
54 }
55 }
56}
57
58impl From<std::io::Error> for ConfigError {
59 fn from(e: std::io::Error) -> Self {
60 ConfigError::IoError(e)
61 }
62}
63
64impl From<serde_json::Error> for ConfigError {
65 fn from(_: serde_json::Error) -> Self {
66 ConfigError::MalformedJson
67 }
68}
69
70pub fn home_config_path() -> Result<std::path::PathBuf, ConfigError> {
71 let home = home::home_dir().ok_or(ConfigError::HomeNotFound)?;
72 Ok(home.join(".comma.json"))
73}