mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-25 13:45:03 +08:00
6098fa7536
* feat: WebDAV backup/restore - Add WebDAV test/backup/restore commands and settings\n- Fix ja i18n missing keys; decode PROPFIND href as UTF-8\n- Stabilize Windows prompt auto-import tests via CC_SWITCH_TEST_HOME * chore: format and minor cleanups * fix: update build config * feat(webdav): unify sync UX and hardening fixes * fix(webdav): harden sync flow and stabilize sync UX/tests * fix(webdav): add resource limits to skills.zip extraction Prevent zip bomb / resource exhaustion by enforcing: - MAX_EXTRACT_ENTRIES (10,000 files) - MAX_EXTRACT_BYTES (512 MB cumulative) * refactor(webdav): drop deviceId and display deviceName only --------- Co-authored-by: small-lovely-cat <77799160+small-lovely-cat@users.noreply.github.com> Co-authored-by: saladday <1203511142@qq.com>
174 lines
5.3 KiB
Rust
174 lines
5.3 KiB
Rust
#![allow(non_snake_case)]
|
|
|
|
use tauri::AppHandle;
|
|
|
|
fn merge_settings_for_save(
|
|
mut incoming: crate::settings::AppSettings,
|
|
existing: &crate::settings::AppSettings,
|
|
) -> crate::settings::AppSettings {
|
|
if incoming.webdav_sync.is_none() {
|
|
incoming.webdav_sync = existing.webdav_sync.clone();
|
|
}
|
|
incoming
|
|
}
|
|
|
|
/// 获取设置
|
|
#[tauri::command]
|
|
pub async fn get_settings() -> Result<crate::settings::AppSettings, String> {
|
|
Ok(crate::settings::get_settings_for_frontend())
|
|
}
|
|
|
|
/// 保存设置
|
|
#[tauri::command]
|
|
pub async fn save_settings(settings: crate::settings::AppSettings) -> Result<bool, String> {
|
|
let existing = crate::settings::get_settings();
|
|
let merged = merge_settings_for_save(settings, &existing);
|
|
crate::settings::update_settings(merged).map_err(|e| e.to_string())?;
|
|
Ok(true)
|
|
}
|
|
|
|
/// 重启应用程序(当 app_config_dir 变更后使用)
|
|
#[tauri::command]
|
|
pub async fn restart_app(app: AppHandle) -> Result<bool, String> {
|
|
// 在后台延迟重启,让函数有时间返回响应
|
|
tauri::async_runtime::spawn(async move {
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
app.restart();
|
|
});
|
|
Ok(true)
|
|
}
|
|
|
|
/// 获取 app_config_dir 覆盖配置 (从 Store)
|
|
#[tauri::command]
|
|
pub async fn get_app_config_dir_override(app: AppHandle) -> Result<Option<String>, String> {
|
|
Ok(crate::app_store::refresh_app_config_dir_override(&app)
|
|
.map(|p| p.to_string_lossy().to_string()))
|
|
}
|
|
|
|
/// 设置 app_config_dir 覆盖配置 (到 Store)
|
|
#[tauri::command]
|
|
pub async fn set_app_config_dir_override(
|
|
app: AppHandle,
|
|
path: Option<String>,
|
|
) -> Result<bool, String> {
|
|
crate::app_store::set_app_config_dir_to_store(&app, path.as_deref())?;
|
|
Ok(true)
|
|
}
|
|
|
|
/// 设置开机自启
|
|
#[tauri::command]
|
|
pub async fn set_auto_launch(enabled: bool) -> Result<bool, String> {
|
|
if enabled {
|
|
crate::auto_launch::enable_auto_launch().map_err(|e| format!("启用开机自启失败: {e}"))?;
|
|
} else {
|
|
crate::auto_launch::disable_auto_launch().map_err(|e| format!("禁用开机自启失败: {e}"))?;
|
|
}
|
|
Ok(true)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::merge_settings_for_save;
|
|
use crate::settings::{AppSettings, WebDavSyncSettings};
|
|
|
|
#[test]
|
|
fn save_settings_should_preserve_existing_webdav_when_payload_omits_it() {
|
|
let mut existing = AppSettings::default();
|
|
existing.webdav_sync = Some(WebDavSyncSettings {
|
|
base_url: "https://dav.example.com".to_string(),
|
|
username: "alice".to_string(),
|
|
password: "secret".to_string(),
|
|
..WebDavSyncSettings::default()
|
|
});
|
|
|
|
let incoming = AppSettings::default();
|
|
let merged = merge_settings_for_save(incoming, &existing);
|
|
|
|
assert!(merged.webdav_sync.is_some());
|
|
assert_eq!(
|
|
merged.webdav_sync.as_ref().map(|v| v.base_url.as_str()),
|
|
Some("https://dav.example.com")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn save_settings_should_keep_incoming_webdav_when_present() {
|
|
let mut existing = AppSettings::default();
|
|
existing.webdav_sync = Some(WebDavSyncSettings {
|
|
base_url: "https://dav.old.example.com".to_string(),
|
|
username: "old".to_string(),
|
|
password: "old-pass".to_string(),
|
|
..WebDavSyncSettings::default()
|
|
});
|
|
|
|
let mut incoming = AppSettings::default();
|
|
incoming.webdav_sync = Some(WebDavSyncSettings {
|
|
base_url: "https://dav.new.example.com".to_string(),
|
|
username: "new".to_string(),
|
|
password: "new-pass".to_string(),
|
|
..WebDavSyncSettings::default()
|
|
});
|
|
|
|
let merged = merge_settings_for_save(incoming, &existing);
|
|
|
|
assert_eq!(
|
|
merged.webdav_sync.as_ref().map(|v| v.base_url.as_str()),
|
|
Some("https://dav.new.example.com")
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 获取开机自启状态
|
|
#[tauri::command]
|
|
pub async fn get_auto_launch_status() -> Result<bool, String> {
|
|
crate::auto_launch::is_auto_launch_enabled().map_err(|e| format!("获取开机自启状态失败: {e}"))
|
|
}
|
|
|
|
/// 获取整流器配置
|
|
#[tauri::command]
|
|
pub async fn get_rectifier_config(
|
|
state: tauri::State<'_, crate::AppState>,
|
|
) -> Result<crate::proxy::types::RectifierConfig, String> {
|
|
state.db.get_rectifier_config().map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// 设置整流器配置
|
|
#[tauri::command]
|
|
pub async fn set_rectifier_config(
|
|
state: tauri::State<'_, crate::AppState>,
|
|
config: crate::proxy::types::RectifierConfig,
|
|
) -> Result<bool, String> {
|
|
state
|
|
.db
|
|
.set_rectifier_config(&config)
|
|
.map_err(|e| e.to_string())?;
|
|
Ok(true)
|
|
}
|
|
|
|
/// 获取日志配置
|
|
#[tauri::command]
|
|
pub async fn get_log_config(
|
|
state: tauri::State<'_, crate::AppState>,
|
|
) -> Result<crate::proxy::types::LogConfig, String> {
|
|
state.db.get_log_config().map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// 设置日志配置
|
|
#[tauri::command]
|
|
pub async fn set_log_config(
|
|
state: tauri::State<'_, crate::AppState>,
|
|
config: crate::proxy::types::LogConfig,
|
|
) -> Result<bool, String> {
|
|
state
|
|
.db
|
|
.set_log_config(&config)
|
|
.map_err(|e| e.to_string())?;
|
|
log::set_max_level(config.to_level_filter());
|
|
log::info!(
|
|
"日志配置已更新: enabled={}, level={}",
|
|
config.enabled,
|
|
config.level
|
|
);
|
|
Ok(true)
|
|
}
|