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
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(¤t)?;
|
|
|
|
let Value::Object(map) = current else {
|
|
return Ok(BTreeMap::new());
|
|
};
|
|
|
|
Ok(map.into_iter().collect())
|
|
}
|