use std::fs;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::exit::{CtlError, CtlResult};
const DEFAULT_SERVER: &str = "http://127.0.0.1:8080";
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
pub server_url: Option<String>,
pub api_token: Option<String>,
}
impl Config {
pub fn effective_server(&self) -> String {
self.server_url
.clone()
.or_else(|| std::env::var("CELLCTL_SERVER").ok())
.unwrap_or_else(|| DEFAULT_SERVER.to_string())
}
pub fn effective_token(&self) -> Option<String> {
self.api_token
.clone()
.or_else(|| std::env::var("CELLCTL_TOKEN").ok())
}
}
pub fn config_path() -> CtlResult<PathBuf> {
if let Ok(explicit) = std::env::var("CELLCTL_CONFIG") {
return Ok(PathBuf::from(explicit));
}
let home =
home::home_dir().ok_or_else(|| CtlError::usage("cannot determine home directory"))?;
Ok(home.join(".cellctl").join("config"))
}
pub fn load() -> CtlResult<Config> {
let path = config_path()?;
if !path.exists() {
return Ok(Config::default());
}
let raw = fs::read_to_string(&path)
.map_err(|e| CtlError::usage(format!("read {}: {e}", path.display())))?;
let cfg: Config = toml::from_str(&raw)
.map_err(|e| CtlError::usage(format!("parse {}: {e}", path.display())))?;
Ok(cfg)
}
pub fn save(cfg: &Config) -> CtlResult<()> {
let path = config_path()?;
if let Some(parent) = path.parent() {
ensure_dir(parent)?;
}
let raw = toml::to_string_pretty(cfg)
.map_err(|e| CtlError::usage(format!("serialize config: {e}")))?;
fs::write(&path, raw).map_err(|e| CtlError::usage(format!("write {}: {e}", path.display())))?;
Ok(())
}
fn ensure_dir(p: &Path) -> CtlResult<()> {
fs::create_dir_all(p).map_err(|e| CtlError::usage(format!("mkdir {}: {e}", p.display())))
}