perf: utilize smartstring for string handling (#5149)
* perf: utilize smartstring for string handling - Updated various modules to replace standard String with smartstring::alias::String for improved performance and memory efficiency. - Adjusted string manipulations and conversions throughout the codebase to ensure compatibility with the new smartstring type. - Enhanced readability and maintainability by using `.into()` for conversions where applicable. - Ensured that all instances of string handling in configuration, logging, and network management leverage the benefits of smartstring. * fix: replace wrap_err with stringify_err for better error handling in UWP tool invocation * refactor: update import path for StringifyErr and adjust string handling in sysopt * fix: correct import path for CmdResult in UWP module * fix: update argument type for execute_sysproxy_command to use std::string::String * fix: add missing CmdResult import in UWP platform module * fix: improve string handling and error messaging across multiple files * style: format code for improved readability and consistency across multiple files * fix: remove unused file
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
use super::CmdResult;
|
||||
use crate::core::sysopt::Sysopt;
|
||||
use crate::{
|
||||
cmd::StringifyErr,
|
||||
feat, logging,
|
||||
utils::{
|
||||
dirs::{self, PathBufExec},
|
||||
logging::Type,
|
||||
},
|
||||
wrap_err,
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
use std::path::Path;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::fs;
|
||||
@@ -14,29 +16,29 @@ use tokio::fs;
|
||||
/// 打开应用程序所在目录
|
||||
#[tauri::command]
|
||||
pub async fn open_app_dir() -> CmdResult<()> {
|
||||
let app_dir = wrap_err!(dirs::app_home_dir())?;
|
||||
wrap_err!(open::that(app_dir))
|
||||
let app_dir = dirs::app_home_dir().stringify_err()?;
|
||||
open::that(app_dir).stringify_err()
|
||||
}
|
||||
|
||||
/// 打开核心所在目录
|
||||
#[tauri::command]
|
||||
pub async fn open_core_dir() -> CmdResult<()> {
|
||||
let core_dir = wrap_err!(tauri::utils::platform::current_exe())?;
|
||||
let core_dir = tauri::utils::platform::current_exe().stringify_err()?;
|
||||
let core_dir = core_dir.parent().ok_or("failed to get core dir")?;
|
||||
wrap_err!(open::that(core_dir))
|
||||
open::that(core_dir).stringify_err()
|
||||
}
|
||||
|
||||
/// 打开日志目录
|
||||
#[tauri::command]
|
||||
pub async fn open_logs_dir() -> CmdResult<()> {
|
||||
let log_dir = wrap_err!(dirs::app_logs_dir())?;
|
||||
wrap_err!(open::that(log_dir))
|
||||
let log_dir = dirs::app_logs_dir().stringify_err()?;
|
||||
open::that(log_dir).stringify_err()
|
||||
}
|
||||
|
||||
/// 打开网页链接
|
||||
#[tauri::command]
|
||||
pub fn open_web_url(url: String) -> CmdResult<()> {
|
||||
wrap_err!(open::that(url))
|
||||
open::that(url.as_str()).stringify_err()
|
||||
}
|
||||
|
||||
/// 打开/关闭开发者工具
|
||||
@@ -73,22 +75,27 @@ pub fn get_portable_flag() -> CmdResult<bool> {
|
||||
/// 获取应用目录
|
||||
#[tauri::command]
|
||||
pub fn get_app_dir() -> CmdResult<String> {
|
||||
let app_home_dir = wrap_err!(dirs::app_home_dir())?.to_string_lossy().into();
|
||||
let app_home_dir = dirs::app_home_dir()
|
||||
.stringify_err()?
|
||||
.to_string_lossy()
|
||||
.into();
|
||||
Ok(app_home_dir)
|
||||
}
|
||||
|
||||
/// 获取当前自启动状态
|
||||
#[tauri::command]
|
||||
pub fn get_auto_launch_status() -> CmdResult<bool> {
|
||||
use crate::core::sysopt::Sysopt;
|
||||
wrap_err!(Sysopt::global().get_launch_status())
|
||||
Sysopt::global().get_launch_status().stringify_err()
|
||||
}
|
||||
|
||||
/// 下载图标缓存
|
||||
#[tauri::command]
|
||||
pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String> {
|
||||
let icon_cache_dir = wrap_err!(dirs::app_home_dir())?.join("icons").join("cache");
|
||||
let icon_path = icon_cache_dir.join(&name);
|
||||
let icon_cache_dir = dirs::app_home_dir()
|
||||
.stringify_err()?
|
||||
.join("icons")
|
||||
.join("cache");
|
||||
let icon_path = icon_cache_dir.join(name.as_str());
|
||||
|
||||
if icon_path.exists() {
|
||||
return Ok(icon_path.to_string_lossy().into());
|
||||
@@ -98,9 +105,9 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String>
|
||||
let _ = std::fs::create_dir_all(&icon_cache_dir);
|
||||
}
|
||||
|
||||
let temp_path = icon_cache_dir.join(format!("{}.downloading", &name));
|
||||
let temp_path = icon_cache_dir.join(format!("{}.downloading", name.as_str()));
|
||||
|
||||
let response = wrap_err!(reqwest::get(&url).await)?;
|
||||
let response = reqwest::get(url.as_str()).await.stringify_err()?;
|
||||
|
||||
let content_type = response
|
||||
.headers()
|
||||
@@ -110,7 +117,7 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String>
|
||||
|
||||
let is_image = content_type.starts_with("image/");
|
||||
|
||||
let content = wrap_err!(response.bytes().await)?;
|
||||
let content = response.bytes().await.stringify_err()?;
|
||||
|
||||
let is_html = content.len() > 15
|
||||
&& (content.starts_with(b"<!DOCTYPE html")
|
||||
@@ -129,7 +136,7 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String>
|
||||
}
|
||||
};
|
||||
|
||||
wrap_err!(std::io::copy(&mut content.as_ref(), &mut file))?;
|
||||
std::io::copy(&mut content.as_ref(), &mut file).stringify_err()?;
|
||||
}
|
||||
|
||||
if !icon_path.exists() {
|
||||
@@ -149,7 +156,7 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String>
|
||||
Ok(icon_path.to_string_lossy().into())
|
||||
} else {
|
||||
let _ = temp_path.remove_if_exists().await;
|
||||
Err(format!("下载的内容不是有效图片: {url}"))
|
||||
Err(format!("下载的内容不是有效图片: {}", url.as_str()).into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +170,9 @@ pub struct IconInfo {
|
||||
/// 复制图标文件
|
||||
#[tauri::command]
|
||||
pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<String> {
|
||||
let file_path = Path::new(&path);
|
||||
let file_path = Path::new(path.as_str());
|
||||
|
||||
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
|
||||
let icon_dir = dirs::app_home_dir().stringify_err()?.join("icons");
|
||||
if !icon_dir.exists() {
|
||||
let _ = fs::create_dir_all(&icon_dir).await;
|
||||
}
|
||||
@@ -176,17 +183,26 @@ pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<Stri
|
||||
|
||||
let dest_path = icon_dir.join(format!(
|
||||
"{0}-{1}.{ext}",
|
||||
icon_info.name, icon_info.current_t
|
||||
icon_info.name.as_str(),
|
||||
icon_info.current_t.as_str()
|
||||
));
|
||||
if file_path.exists() {
|
||||
if icon_info.previous_t.trim() != "" {
|
||||
icon_dir
|
||||
.join(format!("{0}-{1}.png", icon_info.name, icon_info.previous_t))
|
||||
.join(format!(
|
||||
"{0}-{1}.png",
|
||||
icon_info.name.as_str(),
|
||||
icon_info.previous_t.as_str()
|
||||
))
|
||||
.remove_if_exists()
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
icon_dir
|
||||
.join(format!("{0}-{1}.ico", icon_info.name, icon_info.previous_t))
|
||||
.join(format!(
|
||||
"{0}-{1}.ico",
|
||||
icon_info.name.as_str(),
|
||||
icon_info.previous_t.as_str()
|
||||
))
|
||||
.remove_if_exists()
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
@@ -200,7 +216,7 @@ pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<Stri
|
||||
);
|
||||
match fs::copy(file_path, &dest_path).await {
|
||||
Ok(_) => Ok(dest_path.to_string_lossy().into()),
|
||||
Err(err) => Err(err.to_string()),
|
||||
Err(err) => Err(err.to_string().into()),
|
||||
}
|
||||
} else {
|
||||
Err("file not found".into())
|
||||
@@ -218,7 +234,7 @@ pub fn notify_ui_ready() -> CmdResult<()> {
|
||||
/// UI加载阶段
|
||||
#[tauri::command]
|
||||
pub fn update_ui_stage(stage: String) -> CmdResult<()> {
|
||||
log::info!(target: "app", "UI加载阶段更新: {stage}");
|
||||
log::info!(target: "app", "UI加载阶段更新: {}", stage.as_str());
|
||||
|
||||
use crate::utils::resolve::ui::UiReadyStage;
|
||||
|
||||
@@ -229,8 +245,8 @@ pub fn update_ui_stage(stage: String) -> CmdResult<()> {
|
||||
"ResourcesLoaded" => UiReadyStage::ResourcesLoaded,
|
||||
"Ready" => UiReadyStage::Ready,
|
||||
_ => {
|
||||
log::warn!(target: "app", "未知的UI加载阶段: {stage}");
|
||||
return Err(format!("未知的UI加载阶段: {stage}"));
|
||||
log::warn!(target: "app", "未知的UI加载阶段: {}", stage.as_str());
|
||||
return Err(format!("未知的UI加载阶段: {}", stage.as_str()).into());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
use super::CmdResult;
|
||||
use crate::{feat, wrap_err};
|
||||
use crate::{cmd::StringifyErr, feat};
|
||||
use feat::LocalBackupFile;
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// Create a local backup
|
||||
#[tauri::command]
|
||||
pub async fn create_local_backup() -> CmdResult<()> {
|
||||
wrap_err!(feat::create_local_backup().await)
|
||||
feat::create_local_backup().await.stringify_err()
|
||||
}
|
||||
|
||||
/// List local backups
|
||||
#[tauri::command]
|
||||
pub fn list_local_backup() -> CmdResult<Vec<LocalBackupFile>> {
|
||||
wrap_err!(feat::list_local_backup())
|
||||
feat::list_local_backup().stringify_err()
|
||||
}
|
||||
|
||||
/// Delete local backup
|
||||
#[tauri::command]
|
||||
pub async fn delete_local_backup(filename: String) -> CmdResult<()> {
|
||||
wrap_err!(feat::delete_local_backup(filename).await)
|
||||
feat::delete_local_backup(filename).await.stringify_err()
|
||||
}
|
||||
|
||||
/// Restore local backup
|
||||
#[tauri::command]
|
||||
pub async fn restore_local_backup(filename: String) -> CmdResult<()> {
|
||||
wrap_err!(feat::restore_local_backup(filename).await)
|
||||
feat::restore_local_backup(filename).await.stringify_err()
|
||||
}
|
||||
|
||||
/// Export local backup to a user selected destination
|
||||
#[tauri::command]
|
||||
pub fn export_local_backup(filename: String, destination: String) -> CmdResult<()> {
|
||||
wrap_err!(feat::export_local_backup(filename, destination))
|
||||
feat::export_local_backup(filename, destination).stringify_err()
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ use crate::{
|
||||
config::Config,
|
||||
core::{CoreManager, handle, validate::CoreConfigValidator},
|
||||
};
|
||||
use crate::{config::*, feat, logging, utils::logging::Type, wrap_err};
|
||||
use crate::{config::*, feat, logging, utils::logging::Type};
|
||||
use compact_str::CompactString;
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// 复制Clash环境变量
|
||||
#[tauri::command]
|
||||
@@ -26,7 +27,7 @@ pub async fn get_clash_info() -> CmdResult<ClashInfo> {
|
||||
/// 修改Clash配置
|
||||
#[tauri::command]
|
||||
pub async fn patch_clash_config(payload: Mapping) -> CmdResult {
|
||||
wrap_err!(feat::patch_clash(payload).await)
|
||||
feat::patch_clash(payload).await.stringify_err()
|
||||
}
|
||||
|
||||
/// 修改Clash模式
|
||||
@@ -54,22 +55,23 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult<Option<String>>
|
||||
Type::Core,
|
||||
"core changed and restarted to {clash_core}"
|
||||
);
|
||||
handle::Handle::notice_message("config_core::change_success", &clash_core);
|
||||
handle::Handle::notice_message("config_core::change_success", clash_core);
|
||||
handle::Handle::refresh_clash();
|
||||
Ok(None)
|
||||
}
|
||||
Err(err) => {
|
||||
let error_msg = format!("Core changed but failed to restart: {err}");
|
||||
let error_msg: String =
|
||||
format!("Core changed but failed to restart: {err}").into();
|
||||
handle::Handle::notice_message("config_core::change_error", error_msg.clone());
|
||||
logging!(error, Type::Core, "{error_msg}");
|
||||
handle::Handle::notice_message("config_core::change_error", &error_msg);
|
||||
Ok(Some(error_msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let error_msg = err;
|
||||
let error_msg: String = err;
|
||||
logging!(error, Type::Core, "failed to change core: {error_msg}");
|
||||
handle::Handle::notice_message("config_core::change_error", &error_msg);
|
||||
handle::Handle::notice_message("config_core::change_error", error_msg.clone());
|
||||
Ok(Some(error_msg))
|
||||
}
|
||||
}
|
||||
@@ -78,7 +80,7 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult<Option<String>>
|
||||
/// 启动核心
|
||||
#[tauri::command]
|
||||
pub async fn start_core() -> CmdResult {
|
||||
let result = wrap_err!(CoreManager::global().start_core().await);
|
||||
let result = CoreManager::global().start_core().await.stringify_err();
|
||||
if result.is_ok() {
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
@@ -88,7 +90,7 @@ pub async fn start_core() -> CmdResult {
|
||||
/// 关闭核心
|
||||
#[tauri::command]
|
||||
pub async fn stop_core() -> CmdResult {
|
||||
let result = wrap_err!(CoreManager::global().stop_core().await);
|
||||
let result = CoreManager::global().stop_core().await.stringify_err();
|
||||
if result.is_ok() {
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
@@ -98,7 +100,7 @@ pub async fn stop_core() -> CmdResult {
|
||||
/// 重启核心
|
||||
#[tauri::command]
|
||||
pub async fn restart_core() -> CmdResult {
|
||||
let result = wrap_err!(CoreManager::global().restart_core().await);
|
||||
let result = CoreManager::global().restart_core().await.stringify_err();
|
||||
if result.is_ok() {
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
@@ -250,7 +252,7 @@ pub async fn get_dns_config_content() -> CmdResult<String> {
|
||||
return Err("DNS config file not found".into());
|
||||
}
|
||||
|
||||
let content = fs::read_to_string(&dns_path).await.stringify_err()?;
|
||||
let content = fs::read_to_string(&dns_path).await.stringify_err()?.into();
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use smartstring::alias::String;
|
||||
|
||||
pub type CmdResult<T = ()> = Result<T, String>;
|
||||
|
||||
@@ -47,7 +48,7 @@ pub trait StringifyErr<T> {
|
||||
|
||||
impl<T, E: std::fmt::Display> StringifyErr<T> for Result<T, E> {
|
||||
fn stringify_err(self) -> CmdResult<T> {
|
||||
self.map_err(|e| e.to_string())
|
||||
self.map_err(|e| e.to_string().into())
|
||||
}
|
||||
|
||||
fn stringify_err_log<F>(self, log_fn: F) -> CmdResult<T>
|
||||
@@ -55,7 +56,7 @@ impl<T, E: std::fmt::Display> StringifyErr<T> for Result<T, E> {
|
||||
F: Fn(&str),
|
||||
{
|
||||
self.map_err(|e| {
|
||||
let msg = e.to_string();
|
||||
let msg = String::from(e.to_string());
|
||||
log_fn(&msg);
|
||||
msg
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::CmdResult;
|
||||
use crate::cmd::StringifyErr;
|
||||
use crate::core::{EventDrivenProxyManager, async_proxy_query::AsyncProxyQuery};
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::wrap_err;
|
||||
use network_interface::NetworkInterface;
|
||||
use serde_yaml_ng::Mapping;
|
||||
|
||||
@@ -82,7 +82,7 @@ pub fn get_network_interfaces_info() -> CmdResult<Vec<NetworkInterface>> {
|
||||
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
|
||||
|
||||
let names = get_network_interfaces();
|
||||
let interfaces = wrap_err!(NetworkInterface::show())?;
|
||||
let interfaces = NetworkInterface::show().stringify_err()?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::CmdResult;
|
||||
use super::StringifyErr;
|
||||
use crate::{
|
||||
cmd::StringifyErr,
|
||||
config::{
|
||||
Config, IProfiles, PrfItem, PrfOption,
|
||||
profiles::{
|
||||
@@ -14,8 +14,8 @@ use crate::{
|
||||
process::AsyncHandler,
|
||||
ret_err,
|
||||
utils::{dirs, help, logging::Type},
|
||||
wrap_err,
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -86,7 +86,7 @@ pub async fn enhance_profiles() -> CmdResult {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "{}", e);
|
||||
return Err(e.to_string());
|
||||
return Err(e.to_string().into());
|
||||
}
|
||||
}
|
||||
handle::Handle::refresh_clash();
|
||||
@@ -95,7 +95,7 @@ pub async fn enhance_profiles() -> CmdResult {
|
||||
|
||||
/// 导入配置文件
|
||||
#[tauri::command]
|
||||
pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
|
||||
pub async fn import_profile(url: std::string::String, option: Option<PrfOption>) -> CmdResult {
|
||||
logging!(info, Type::Cmd, "[导入订阅] 开始导入: {}", url);
|
||||
|
||||
// 直接依赖 PrfItem::from_url 自身的超时/重试逻辑,不再使用 tokio::time::timeout 包裹
|
||||
@@ -106,7 +106,7 @@ pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "[导入订阅] 下载失败: {}", e);
|
||||
return Err(format!("导入订阅失败: {}", e));
|
||||
return Err(format!("导入订阅失败: {}", e).into());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -121,7 +121,7 @@ pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult
|
||||
},
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "[导入订阅] 保存配置失败: {}", e);
|
||||
return Err(format!("导入订阅失败: {}", e));
|
||||
return Err(format!("导入订阅失败: {}", e).into());
|
||||
}
|
||||
}
|
||||
// 立即发送配置变更通知
|
||||
@@ -152,7 +152,7 @@ pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "重新排序配置文件失败: {}", err);
|
||||
Err(format!("重新排序配置文件失败: {}", err))
|
||||
Err(format!("重新排序配置文件失败: {}", err).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResu
|
||||
}
|
||||
Err(err) => match err.to_string().as_str() {
|
||||
"the file already exists" => Err("the file already exists".into()),
|
||||
_ => Err(format!("add profile error: {err}")),
|
||||
_ => Err(format!("add profile error: {err}").into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "{}", e);
|
||||
Err(e.to_string())
|
||||
Err(e.to_string().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,9 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
|
||||
pub async fn delete_profile(index: String) -> CmdResult {
|
||||
println!("delete_profile: {}", index);
|
||||
// 使用Send-safe helper函数
|
||||
let should_update = wrap_err!(profiles_delete_item_safe(index.clone()).await)?;
|
||||
let should_update = profiles_delete_item_safe(index.clone())
|
||||
.await
|
||||
.stringify_err()?;
|
||||
profiles_save_file_safe().await.stringify_err()?;
|
||||
|
||||
if should_update {
|
||||
@@ -207,7 +209,7 @@ pub async fn delete_profile(index: String) -> CmdResult {
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "{}", e);
|
||||
return Err(e.to_string());
|
||||
return Err(e.to_string().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +266,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
match profiles_data.get_item(new_profile) {
|
||||
Ok(item) => {
|
||||
if let Some(file) = &item.file {
|
||||
let path = dirs::app_profiles_dir().map(|dir| dir.join(file));
|
||||
let path = dirs::app_profiles_dir().map(|dir| dir.join(file.as_str()));
|
||||
path.ok()
|
||||
} else {
|
||||
None
|
||||
@@ -321,7 +323,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_syntax_error",
|
||||
&error_msg,
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -330,7 +332,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_parse_error",
|
||||
&error_msg,
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -339,7 +341,10 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
Ok(Err(err)) => {
|
||||
let error_msg = format!("无法读取目标配置文件: {err}");
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message("config_validate::file_read_error", &error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
Err(_) => {
|
||||
@@ -347,7 +352,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_timeout",
|
||||
&error_msg,
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -479,12 +484,11 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
items: None,
|
||||
};
|
||||
// 静默恢复,不触发验证
|
||||
wrap_err!({
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
})?;
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
|
||||
crate::process::AsyncHandler::spawn(|| async move {
|
||||
@@ -497,7 +501,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
}
|
||||
|
||||
// 发送验证错误通知
|
||||
handle::Handle::notice_message("config_validate::error", &error_msg);
|
||||
handle::Handle::notice_message("config_validate::error", error_msg.to_string());
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
@@ -539,12 +543,11 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
current: Some(prev_profile),
|
||||
items: None,
|
||||
};
|
||||
wrap_err!({
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
})?;
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
}
|
||||
|
||||
@@ -585,7 +588,9 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
||||
false
|
||||
};
|
||||
|
||||
wrap_err!(profiles_patch_item_safe(index.clone(), profile).await)?;
|
||||
profiles_patch_item_safe(index.clone(), profile)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
|
||||
// 如果更新间隔或允许自动更新变更,异步刷新定时器
|
||||
if should_refresh_timer {
|
||||
@@ -609,19 +614,21 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
||||
pub async fn view_profile(index: String) -> CmdResult {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles_ref = profiles.latest_ref();
|
||||
let file = {
|
||||
wrap_err!(profiles_ref.get_item(&index))?
|
||||
.file
|
||||
.clone()
|
||||
.ok_or("the file field is null")
|
||||
}?;
|
||||
let file = profiles_ref
|
||||
.get_item(&index)
|
||||
.stringify_err()?
|
||||
.file
|
||||
.clone()
|
||||
.ok_or("the file field is null")?;
|
||||
|
||||
let path = wrap_err!(dirs::app_profiles_dir())?.join(file);
|
||||
let path = dirs::app_profiles_dir()
|
||||
.stringify_err()?
|
||||
.join(file.as_str());
|
||||
if !path.exists() {
|
||||
ret_err!("the file not found");
|
||||
}
|
||||
|
||||
wrap_err!(help::open_file(path))
|
||||
help::open_file(path).stringify_err()
|
||||
}
|
||||
|
||||
/// 读取配置文件内容
|
||||
@@ -629,8 +636,8 @@ pub async fn view_profile(index: String) -> CmdResult {
|
||||
pub async fn read_profile_file(index: String) -> CmdResult<String> {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles_ref = profiles.latest_ref();
|
||||
let item = wrap_err!(profiles_ref.get_item(&index))?;
|
||||
let data = wrap_err!(item.read_file())?;
|
||||
let item = profiles_ref.get_item(&index).stringify_err()?;
|
||||
let data = item.read_file().stringify_err()?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ pub async fn sync_tray_proxy_selection() -> CmdResult<()> {
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "Failed to sync tray proxy selection: {e}");
|
||||
Err(e.to_string())
|
||||
Err(e.to_string().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::CmdResult;
|
||||
use crate::{config::*, core::CoreManager, log_err, wrap_err};
|
||||
use crate::{cmd::StringifyErr, config::*, core::CoreManager, log_err};
|
||||
use anyhow::Context;
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// 获取运行时配置
|
||||
@@ -17,12 +18,14 @@ pub async fn get_runtime_yaml() -> CmdResult<String> {
|
||||
let runtime = runtime.latest_ref();
|
||||
|
||||
let config = runtime.config.as_ref();
|
||||
wrap_err!(
|
||||
config
|
||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||
.and_then(|config| serde_yaml_ng::to_string(config)
|
||||
.context("failed to convert config to yaml"))
|
||||
)
|
||||
config
|
||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||
.and_then(|config| {
|
||||
serde_yaml_ng::to_string(config)
|
||||
.context("failed to convert config to yaml")
|
||||
.map(|s| s.into())
|
||||
})
|
||||
.stringify_err()
|
||||
}
|
||||
|
||||
/// 获取运行时存在的键
|
||||
@@ -42,12 +45,11 @@ pub async fn get_runtime_proxy_chain_config(proxy_chain_exit_node: String) -> Cm
|
||||
let runtime = Config::runtime().await;
|
||||
let runtime = runtime.latest_ref();
|
||||
|
||||
let config = wrap_err!(
|
||||
runtime
|
||||
.config
|
||||
.as_ref()
|
||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||
)?;
|
||||
let config = runtime
|
||||
.config
|
||||
.as_ref()
|
||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||
.stringify_err()?;
|
||||
|
||||
if let Some(serde_yaml_ng::Value::Sequence(proxies)) = config.get("proxies") {
|
||||
let mut proxy_name = Some(Some(proxy_chain_exit_node.as_str()));
|
||||
@@ -78,13 +80,14 @@ pub async fn get_runtime_proxy_chain_config(proxy_chain_exit_node: String) -> Cm
|
||||
|
||||
let mut config: HashMap<String, Vec<serde_yaml_ng::Value>> = HashMap::new();
|
||||
|
||||
config.insert("proxies".to_string(), proxies_chain);
|
||||
config.insert("proxies".into(), proxies_chain);
|
||||
|
||||
wrap_err!(serde_yaml_ng::to_string(&config).context("YAML generation failed"))
|
||||
serde_yaml_ng::to_string(&config)
|
||||
.context("YAML generation failed")
|
||||
.map(|s| s.into())
|
||||
.stringify_err()
|
||||
} else {
|
||||
wrap_err!(Err(anyhow::anyhow!(
|
||||
"failed to get proxies or proxy-groups".to_string()
|
||||
)))
|
||||
Err("failed to get proxies or proxy-groups".into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +105,9 @@ pub async fn update_proxy_chain_config_in_runtime(
|
||||
}
|
||||
|
||||
// 生成新的运行配置文件并通知 Clash 核心重新加载
|
||||
let run_path = wrap_err!(Config::generate_file(ConfigType::Run).await)?;
|
||||
let run_path = Config::generate_file(ConfigType::Run)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
log_err!(CoreManager::global().put_configs_force(run_path).await);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
cmd::StringifyErr,
|
||||
config::*,
|
||||
core::{validate::CoreConfigValidator, *},
|
||||
logging,
|
||||
utils::{dirs, logging::Type},
|
||||
wrap_err,
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
use tokio::fs;
|
||||
|
||||
/// 保存profiles的配置
|
||||
@@ -19,18 +20,18 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
let (file_path, original_content, is_merge_file) = {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles_guard = profiles.latest_ref();
|
||||
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
||||
let item = profiles_guard.get_item(&index).stringify_err()?;
|
||||
// 确定是否为merge类型文件
|
||||
let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge");
|
||||
let content = wrap_err!(item.read_file())?;
|
||||
let content = item.read_file().stringify_err()?;
|
||||
let path = item.file.clone().ok_or("file field is null")?;
|
||||
let profiles_dir = wrap_err!(dirs::app_profiles_dir())?;
|
||||
(profiles_dir.join(path), content, is_merge)
|
||||
let profiles_dir = dirs::app_profiles_dir().stringify_err()?;
|
||||
(profiles_dir.join(path.as_str()), content, is_merge)
|
||||
};
|
||||
|
||||
// 保存新的配置文件
|
||||
let file_data = file_data.ok_or("file_data is None")?;
|
||||
wrap_err!(fs::write(&file_path, &file_data).await)?;
|
||||
fs::write(&file_path, &file_data).await.stringify_err()?;
|
||||
|
||||
let file_path_str = file_path.to_string_lossy().to_string();
|
||||
logging!(
|
||||
@@ -76,7 +77,9 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
error_msg
|
||||
);
|
||||
// 恢复原始配置文件
|
||||
wrap_err!(fs::write(&file_path, original_content).await)?;
|
||||
fs::write(&file_path, original_content)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
// 发送合并文件专用错误通知
|
||||
let result = (false, error_msg.clone());
|
||||
crate::cmd::validate::handle_yaml_validation_notice(&result, "合并配置文件");
|
||||
@@ -85,8 +88,10 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
Err(e) => {
|
||||
logging!(error, Type::Config, "[cmd配置save] 验证过程发生错误: {}", e);
|
||||
// 恢复原始配置文件
|
||||
wrap_err!(fs::write(&file_path, original_content).await)?;
|
||||
return Err(e.to_string());
|
||||
fs::write(&file_path, original_content)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
return Err(e.to_string().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +105,9 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
Ok((false, error_msg)) => {
|
||||
logging!(warn, Type::Config, "[cmd配置save] 验证失败: {}", error_msg);
|
||||
// 恢复原始配置文件
|
||||
wrap_err!(fs::write(&file_path, original_content).await)?;
|
||||
fs::write(&file_path, original_content)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
|
||||
// 智能判断错误类型
|
||||
let is_script_error = file_path_str.ends_with(".js")
|
||||
@@ -136,7 +143,7 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
Type::Config,
|
||||
"[cmd配置save] 其他类型验证失败,发送一般通知"
|
||||
);
|
||||
handle::Handle::notice_message("config_validate::error", &error_msg);
|
||||
handle::Handle::notice_message("config_validate::error", error_msg.to_owned());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -144,8 +151,10 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
||||
Err(e) => {
|
||||
logging!(error, Type::Config, "[cmd配置save] 验证过程发生错误: {}", e);
|
||||
// 恢复原始配置文件
|
||||
wrap_err!(fs::write(&file_path, original_content).await)?;
|
||||
Err(e.to_string())
|
||||
fs::write(&file_path, original_content)
|
||||
.await
|
||||
.stringify_err()?;
|
||||
Err(e.to_string().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::CmdResult;
|
||||
use super::{CmdResult, StringifyErr};
|
||||
use crate::{
|
||||
core::service::{self, SERVICE_MANAGER, ServiceStatus},
|
||||
utils::i18n::t,
|
||||
@@ -12,7 +12,7 @@ async fn execute_service_operation_sync(status: ServiceStatus, op_type: &str) ->
|
||||
.await
|
||||
{
|
||||
let emsg = format!("{} Service failed: {}", op_type, e);
|
||||
return Err(t(emsg.as_str()).await);
|
||||
return Err(t(emsg.as_str()).await.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -39,8 +39,6 @@ pub async fn repair_service() -> CmdResult {
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn is_service_available() -> CmdResult<bool> {
|
||||
service::is_service_available()
|
||||
.await
|
||||
.map(|_| true)
|
||||
.map_err(|e| e.to_string())
|
||||
service::is_service_available().await.stringify_err()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use super::CmdResult;
|
||||
use crate::cmd::CmdResult;
|
||||
|
||||
/// Platform-specific implementation for UWP functionality
|
||||
#[cfg(windows)]
|
||||
mod platform {
|
||||
use super::CmdResult;
|
||||
use crate::{core::win_uwp, wrap_err};
|
||||
use crate::cmd::CmdResult;
|
||||
use crate::cmd::StringifyErr;
|
||||
use crate::core::win_uwp;
|
||||
|
||||
pub fn invoke_uwp_tool() -> CmdResult {
|
||||
wrap_err!(win_uwp::invoke_uwptools())
|
||||
win_uwp::invoke_uwptools().stringify_err()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ use crate::{
|
||||
logging,
|
||||
utils::logging::Type,
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// 发送脚本验证通知消息
|
||||
#[tauri::command]
|
||||
pub async fn script_validate_notice(status: String, msg: String) -> CmdResult {
|
||||
handle::Handle::notice_message(&status, &msg);
|
||||
handle::Handle::notice_message(status.as_str(), msg.as_str());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str)
|
||||
};
|
||||
|
||||
logging!(warn, Type::Config, "{} 验证失败: {}", file_type, error_msg);
|
||||
handle::Handle::notice_message(status, error_msg);
|
||||
handle::Handle::notice_message(status, error_msg.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +118,6 @@ pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) {
|
||||
status,
|
||||
error_msg
|
||||
);
|
||||
handle::Handle::notice_message(status, error_msg);
|
||||
handle::Handle::notice_message(status, error_msg.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::CmdResult;
|
||||
use crate::{config::*, feat, wrap_err};
|
||||
use crate::{cmd::StringifyErr, config::*, feat};
|
||||
|
||||
/// 获取Verge配置
|
||||
#[tauri::command]
|
||||
@@ -16,5 +16,5 @@ pub async fn get_verge_config() -> CmdResult<IVergeResponse> {
|
||||
/// 修改Verge配置
|
||||
#[tauri::command]
|
||||
pub async fn patch_verge_config(payload: IVerge) -> CmdResult {
|
||||
wrap_err!(feat::patch_verge(payload, false).await)
|
||||
feat::patch_verge(payload, false).await.stringify_err()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::CmdResult;
|
||||
use crate::{config::*, core, feat, wrap_err};
|
||||
use crate::{cmd::StringifyErr, config::*, core, feat};
|
||||
use reqwest_dav::list_cmd::ListFile;
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// 保存 WebDAV 配置
|
||||
#[tauri::command]
|
||||
@@ -30,23 +31,25 @@ pub async fn save_webdav_config(url: String, username: String, password: String)
|
||||
/// 创建 WebDAV 备份并上传
|
||||
#[tauri::command]
|
||||
pub async fn create_webdav_backup() -> CmdResult<()> {
|
||||
wrap_err!(feat::create_backup_and_upload_webdav().await)
|
||||
feat::create_backup_and_upload_webdav()
|
||||
.await
|
||||
.stringify_err()
|
||||
}
|
||||
|
||||
/// 列出 WebDAV 上的备份文件
|
||||
#[tauri::command]
|
||||
pub async fn list_webdav_backup() -> CmdResult<Vec<ListFile>> {
|
||||
wrap_err!(feat::list_wevdav_backup().await)
|
||||
feat::list_wevdav_backup().await.stringify_err()
|
||||
}
|
||||
|
||||
/// 删除 WebDAV 上的备份文件
|
||||
#[tauri::command]
|
||||
pub async fn delete_webdav_backup(filename: String) -> CmdResult<()> {
|
||||
wrap_err!(feat::delete_webdav_backup(filename).await)
|
||||
feat::delete_webdav_backup(filename).await.stringify_err()
|
||||
}
|
||||
|
||||
/// 从 WebDAV 恢复备份文件
|
||||
#[tauri::command]
|
||||
pub async fn restore_webdav_backup(filename: String) -> CmdResult<()> {
|
||||
wrap_err!(feat::restore_webdav_backup(filename).await)
|
||||
feat::restore_webdav_backup(filename).await.stringify_err()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user