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:
Tunglies
2025-10-22 16:25:44 +08:00
committed by GitHub
parent fe96a7030a
commit a05ea64bcd
50 changed files with 361 additions and 272 deletions

View File

@@ -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());
}
};

View File

@@ -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()
}

View File

@@ -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)
}

View File

@@ -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
})

View File

@@ -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();

View File

@@ -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)
}

View File

@@ -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())
}
}
}

View File

@@ -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(())

View File

@@ -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())
}
}
}

View File

@@ -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)
}

View File

@@ -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()
}
}

View File

@@ -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());
}
}

View File

@@ -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()
}

View File

@@ -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()
}