You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.0 KiB
Rust

use std::{
collections::BTreeMap,
env,
fs,
path::{Path, PathBuf},
};
use serde_json::{Map, Value};
const APP_NAME: &str = "com.ziyun.callclient";
const CONFIG_FILE_NAME: &str = "config.json";
fn get_home_dir() -> PathBuf {
if let Ok(value) = env::var("HOME") {
return PathBuf::from(value);
}
if let Ok(value) = env::var("USERPROFILE") {
return PathBuf::from(value);
}
PathBuf::from(".")
}
fn get_config_dir() -> PathBuf {
if cfg!(target_os = "linux") {
if let Ok(value) = env::var("XDG_CONFIG_HOME") {
return PathBuf::from(value).join(APP_NAME);
}
return get_home_dir().join(".config").join(APP_NAME);
}
if let Ok(value) = env::var("APPDATA") {
return PathBuf::from(value).join(APP_NAME);
}
get_home_dir().join(".").join(APP_NAME)
}
fn get_config_file_path() -> PathBuf {
get_config_dir().join(CONFIG_FILE_NAME)
}
fn ensure_parent_dir(path: &Path) -> Result<(), String> {
let Some(parent) = path.parent() else {
return Ok(());
};
fs::create_dir_all(parent).map_err(|error| format!("创建配置目录失败: {error}"))
}
fn read_config() -> Result<Value, String> {
let path = get_config_file_path();
if !path.exists() {
return Ok(Value::Object(Map::new()));
}
let content = fs::read_to_string(&path).map_err(|error| format!("读取配置文件失败: {error}"))?;
if content.trim().is_empty() {
return Ok(Value::Object(Map::new()));
}
serde_json::from_str::<Value>(&content).map_err(|error| format!("解析配置文件失败: {error}"))
}
fn write_config(value: &Value) -> Result<(), String> {
let path = get_config_file_path();
ensure_parent_dir(&path)?;
let content = serde_json::to_string_pretty(value).map_err(|error| format!("序列化配置失败: {error}"))?;
fs::write(path, content).map_err(|error| format!("写入配置文件失败: {error}"))
}
fn merge_value(target: &mut Value, patch: Value) {
match (target, patch) {
(Value::Object(target_map), Value::Object(patch_map)) => {
for (key, value) in patch_map {
if let Some(existing) = target_map.get_mut(&key) {
merge_value(existing, value);
} else {
target_map.insert(key, value);
}
}
}
(target_value, patch_value) => {
*target_value = patch_value;
}
}
}
#[tauri::command]
pub fn config_get_all() -> Result<BTreeMap<String, Value>, String> {
let value = read_config()?;
let Value::Object(map) = value else {
return Ok(BTreeMap::new());
};
Ok(map.into_iter().collect())
}
#[tauri::command]
pub fn config_merge(partial: Value) -> Result<BTreeMap<String, Value>, String> {
let mut current = read_config()?;
merge_value(&mut current, partial);
write_config(&current)?;
let Value::Object(map) = current else {
return Ok(BTreeMap::new());
};
Ok(map.into_iter().collect())
}