use anyhow::Context;
use serde::Deserialize;
use std::path::{Path, PathBuf};
fn default_pi_path() -> String {
"pi".to_string()
}
fn default_brain_addr() -> String {
"127.0.0.1:15000".to_string()
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Settings {
pub username: String,
pub password: String,
pub service_url: String,
pub cwd: PathBuf,
#[serde(default = "default_pi_path")]
pub pi_path: String,
#[serde(default = "default_brain_addr")]
pub brain_addr: String,
#[serde(default)]
pub data_dir: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct AccountConfig {
pub username: String,
pub password: String,
}
impl Settings {
pub fn load() -> anyhow::Result<Self> {
let path = settings_path()?;
let content = std::fs::read_to_string(&path)
.with_context(|| format!("读取配置失败: {}", path.display()))?;
let mut settings: Self = serde_json::from_str(&content)
.with_context(|| format!("配置格式错误: {}", path.display()))?;
if settings.username.trim().is_empty() || settings.password.len() < 6 {
anyhow::bail!("账户配置无效: 用户名不能为空,密码至少 6 个字符");
}
if settings.service_url.trim().is_empty() {
anyhow::bail!("配置项 serviceUrl 不能为空");
}
settings.cwd = settings
.cwd
.canonicalize()
.with_context(|| format!("工作目录不存在: {}", settings.cwd.display()))?;
if !settings.cwd.is_dir() {
anyhow::bail!("cwd 不是目录: {}", settings.cwd.display());
}
settings
.data_dir
.get_or_insert(data_home()?.join("sessions"));
Ok(settings)
}
pub fn data_dir(&self) -> &Path {
self.data_dir.as_deref().expect("dataDir initialized")
}
pub fn account(&self) -> AccountConfig {
AccountConfig {
username: self.username.clone(),
password: self.password.clone(),
}
}
}
pub fn data_home() -> anyhow::Result<PathBuf> {
let home = std::env::var_os("HOME").context("HOME 环境变量未设置")?;
Ok(PathBuf::from(home).join(".xagent"))
}
pub fn settings_path() -> anyhow::Result<PathBuf> {
Ok(data_home()?.join("setting.json"))
}
pub fn pid_path() -> anyhow::Result<PathBuf> {
Ok(data_home()?.join("xagent-pi.pid"))
}
pub fn log_path() -> anyhow::Result<PathBuf> {
Ok(data_home()?.join("xagent-pi.log"))
}