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

@@ -3,6 +3,7 @@ use anyhow::Error;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use reqwest_dav::list_cmd::{ListEntity, ListFile};
use smartstring::alias::String;
use std::{
collections::HashMap,
env::{consts::OS, temp_dir},
@@ -123,8 +124,11 @@ impl WebDavClient {
}))
.build()?,
)
.set_host(config.url)
.set_auth(reqwest_dav::Auth::Basic(config.username, config.password))
.set_host(config.url.into())
.set_auth(reqwest_dav::Auth::Basic(
config.username.into(),
config.password.into(),
))
.build()?;
// 尝试检查目录是否存在,如果不存在尝试创建
@@ -163,7 +167,7 @@ impl WebDavClient {
pub async fn upload(&self, file_path: PathBuf, file_name: String) -> Result<(), Error> {
let client = self.get_client(Operation::Upload).await?;
let webdav_path: String = format!("{}/{}", dirs::BACKUP_DIR, file_name);
let webdav_path: String = format!("{}/{}", dirs::BACKUP_DIR, file_name).into();
// 读取文件并上传,如果失败尝试一次重试
let file_content = fs::read(&file_path)?;
@@ -248,8 +252,8 @@ impl WebDavClient {
pub fn create_backup() -> Result<(String, PathBuf), Error> {
let now = chrono::Local::now().format("%Y-%m-%d_%H-%M-%S").to_string();
let zip_file_name = format!("{OS}-backup-{now}.zip");
let zip_path = temp_dir().join(&zip_file_name);
let zip_file_name: String = format!("{OS}-backup-{now}.zip").into();
let zip_path = temp_dir().join(zip_file_name.as_str());
let file = fs::File::create(&zip_path)?;
let mut zip = zip::ZipWriter::new(file);

View File

@@ -8,6 +8,7 @@ use crate::config::{Config, IVerge};
use crate::core::{async_proxy_query::AsyncProxyQuery, handle};
use crate::process::AsyncHandler;
use once_cell::sync::Lazy;
use smartstring::alias::String;
use sysproxy::{Autoproxy, Sysproxy};
#[derive(Debug, Clone)]
@@ -426,13 +427,15 @@ impl EventDrivenProxyManager {
};
let port = verge_mixed_port.unwrap_or(default_port);
let host = proxy_host.unwrap_or_else(|| network::DEFAULT_PROXY_HOST.into());
let host = proxy_host
.unwrap_or_else(|| network::DEFAULT_PROXY_HOST.into())
.into();
Sysproxy {
enable: true,
host,
port,
bypass: Self::get_bypass_config().await,
bypass: Self::get_bypass_config().await.into(),
}
}
@@ -445,9 +448,9 @@ impl EventDrivenProxyManager {
let custom = verge.system_proxy_bypass.as_deref().unwrap_or("");
match (use_default, custom.is_empty()) {
(_, true) => bypass::DEFAULT.to_string(),
(true, false) => format!("{},{}", bypass::DEFAULT, custom),
(false, false) => custom.to_string(),
(_, true) => bypass::DEFAULT.into(),
(true, false) => format!("{},{}", bypass::DEFAULT, custom).into(),
(false, false) => custom.into(),
}
}

View File

@@ -1,5 +1,6 @@
use crate::{APP_HANDLE, constants::timing, singleton};
use parking_lot::RwLock;
use smartstring::alias::String;
use std::{sync::Arc, thread};
use tauri::{AppHandle, Manager, WebviewWindow};
use tauri_plugin_mihomo::{Mihomo, MihomoExt};
@@ -199,7 +200,7 @@ impl Handle {
pub fn set_activation_policy(&self, policy: tauri::ActivationPolicy) -> Result<(), String> {
Self::app_handle()
.set_activation_policy(policy)
.map_err(|e| e.to_string())
.map_err(|e| e.to_string().into())
}
pub fn set_activation_policy_regular(&self) {

View File

@@ -6,6 +6,7 @@ use crate::{
};
use anyhow::{Result, bail};
use parking_lot::Mutex;
use smartstring::alias::String;
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
use tauri::{AppHandle, Manager};
use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, ShortcutState};

View File

@@ -7,6 +7,7 @@ use crate::{
utils::{dirs, help, logging::Type},
};
use anyhow::{Result, anyhow};
use smartstring::alias::String;
use std::{path::PathBuf, time::Instant};
use tauri_plugin_mihomo::Error as MihomoError;
use tokio::time::sleep;

View File

@@ -8,6 +8,7 @@ use crate::{
utils::logging::Type,
};
use anyhow::Result;
use smartstring::alias::String;
impl CoreManager {
pub async fn start_core(&self) -> Result<()> {
@@ -48,7 +49,7 @@ impl CoreManager {
.ok_or_else(|| "Clash core cannot be None".to_string())?;
if !IVerge::VALID_CLASH_CORES.contains(&core.as_str()) {
return Err(format!("Invalid clash core: {}", core));
return Err(format!("Invalid clash core: {}", core).into());
}
Config::verge().await.draft_mut().clash_core = clash_core;
@@ -61,7 +62,9 @@ impl CoreManager {
.await
.map_err(|e| e.to_string())?;
self.apply_config(run_path).await.map_err(|e| e.to_string())
self.apply_config(run_path)
.await
.map_err(|e| e.to_string().into())
}
async fn prepare_startup(&self) -> Result<()> {

View File

@@ -37,7 +37,7 @@ impl CoreManager {
let (mut rx, child) = app_handle
.shell()
.sidecar(&clash_core)?
.sidecar(clash_core.as_str())?
.args([
"-d",
dirs::path_to_str(&config_dir)?,

View File

@@ -4,6 +4,7 @@ use crate::{
utils::logging::Type,
};
use parking_lot::RwLock;
use smartstring::alias::String;
use std::{
sync::{
atomic::{AtomicU64, Ordering},

View File

@@ -7,6 +7,7 @@ use crate::{
utils::logging::Type,
};
use anyhow::Result;
use smartstring::alias::String;
use std::sync::Arc;
#[cfg(not(target_os = "windows"))]
use sysproxy::{Autoproxy, Sysproxy};
@@ -45,7 +46,7 @@ async fn get_bypass() -> String {
if custom_bypass.is_empty() {
DEFAULT_BYPASS.into()
} else if use_default {
format!("{DEFAULT_BYPASS},{custom_bypass}")
format!("{DEFAULT_BYPASS},{custom_bypass}").into()
} else {
custom_bypass
}
@@ -53,7 +54,7 @@ async fn get_bypass() -> String {
// Uses tokio Command with CREATE_NO_WINDOW flag to avoid DLL initialization issues during shutdown
#[cfg(target_os = "windows")]
async fn execute_sysproxy_command(args: Vec<String>) -> Result<()> {
async fn execute_sysproxy_command(args: Vec<std::string::String>) -> Result<()> {
use crate::utils::dirs;
use anyhow::bail;
#[allow(unused_imports)] // Required for .creation_flags() method
@@ -68,7 +69,7 @@ async fn execute_sysproxy_command(args: Vec<String>) -> Result<()> {
}
let output = Command::new(sysproxy_exe)
.args(&args)
.args(args)
.creation_flags(0x08000000) // CREATE_NO_WINDOW - 隐藏窗口
.output()
.await?;
@@ -132,9 +133,9 @@ impl Sysopt {
{
let mut sys = Sysproxy {
enable: false,
host: proxy_host.clone(),
host: proxy_host.clone().into(),
port,
bypass: get_bypass().await,
bypass: get_bypass().await.into(),
};
let mut auto = Autoproxy {
enable: false,
@@ -178,13 +179,13 @@ impl Sysopt {
return result;
}
let args = if pac_enable {
let args: Vec<std::string::String> = if pac_enable {
let address = format!("http://{proxy_host}:{pac_port}/commands/pac");
vec!["pac".into(), address]
} else {
let address = format!("{proxy_host}:{port}");
let bypass = get_bypass().await;
vec!["global".into(), address, bypass]
vec!["global".into(), address, bypass.into()]
};
execute_sysproxy_command(args).await?;

View File

@@ -2,6 +2,7 @@ use crate::{config::Config, feat, logging, logging_error, singleton, utils::logg
use anyhow::{Context, Result};
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
use parking_lot::RwLock;
use smartstring::alias::String;
use std::{
collections::HashMap,
pin::Pin,

View File

@@ -19,6 +19,7 @@ use super::handle;
use anyhow::Result;
use futures::future::join_all;
use parking_lot::Mutex;
use smartstring::alias::String;
use std::collections::HashMap;
use std::{
fs,
@@ -218,7 +219,7 @@ impl Tray {
let app_handle = handle::Handle::app_handle();
let tray_event = { Config::verge().await.latest_ref().tray_event.clone() };
let tray_event: String = tray_event.unwrap_or("main_window".into());
let tray_event = tray_event.unwrap_or("main_window".into());
let tray = app_handle
.tray_by_id("main")
.ok_or_else(|| anyhow::anyhow!("Failed to get main tray"))?;
@@ -625,7 +626,7 @@ async fn create_tray_menu(
.iter()
.filter_map(|group| group.get("name"))
.filter_map(|name| name.as_str())
.map(|name| name.to_string())
.map(|name| name.into())
.collect::<Vec<String>>()
})
.unwrap_or_default()
@@ -671,7 +672,7 @@ async fn create_tray_menu(
let is_current_profile = Config::profiles()
.await
.data_mut()
.is_current_profile_index(profile_uid.to_string());
.is_current_profile_index(profile_uid.clone());
CheckMenuItem::with_id(
&app_handle,
format!("profiles_{profile_uid}"),
@@ -780,7 +781,7 @@ async fn create_tray_menu(
&group_items_refs,
) {
let insertion_index = submenus.len();
submenus.push((group_name.to_string(), insertion_index, submenu));
submenus.push((group_name.into(), insertion_index, submenu));
} else {
log::warn!(target: "app", "创建代理组子菜单失败: {}", group_name);
}

View File

@@ -1,4 +1,5 @@
use anyhow::Result;
use smartstring::alias::String;
use std::path::Path;
use std::sync::Arc;
use tauri_plugin_shell::ShellExt;
@@ -124,7 +125,7 @@ impl CoreConfigValidator {
let content = match std::fs::read_to_string(config_path) {
Ok(content) => content,
Err(err) => {
let error_msg = format!("Failed to read file: {err}");
let error_msg = format!("Failed to read file: {err}").into();
logging!(error, Type::Validate, "无法读取文件: {}", error_msg);
return Ok((false, error_msg));
}
@@ -138,7 +139,7 @@ impl CoreConfigValidator {
}
Err(err) => {
// 使用标准化的前缀,以便错误处理函数能正确识别
let error_msg = format!("YAML syntax error: {err}");
let error_msg = format!("YAML syntax error: {err}").into();
logging!(error, Type::Validate, "YAML语法错误: {}", error_msg);
Ok((false, error_msg))
}
@@ -151,7 +152,7 @@ impl CoreConfigValidator {
let content = match std::fs::read_to_string(path) {
Ok(content) => content,
Err(err) => {
let error_msg = format!("Failed to read script file: {err}");
let error_msg = format!("Failed to read script file: {err}").into();
logging!(warn, Type::Validate, "脚本语法错误: {}", err);
//handle::Handle::notice_message("config_validate::script_syntax_error", &error_msg);
return Ok((false, error_msg));
@@ -184,7 +185,7 @@ impl CoreConfigValidator {
Ok((true, String::new()))
}
Err(err) => {
let error_msg = format!("Script syntax error: {err}");
let error_msg = format!("Script syntax error: {err}").into();
logging!(warn, Type::Validate, "脚本语法错误: {}", err);
//handle::Handle::notice_message("config_validate::script_syntax_error", &error_msg);
Ok((false, error_msg))
@@ -205,7 +206,7 @@ impl CoreConfigValidator {
// 检查文件是否存在
if !std::path::Path::new(config_path).exists() {
let error_msg = format!("File not found: {config_path}");
let error_msg = format!("File not found: {config_path}").into();
//handle::Handle::notice_message("config_validate::file_not_found", &error_msg);
return Ok((false, error_msg));
}
@@ -282,13 +283,13 @@ impl CoreConfigValidator {
// 使用子进程运行clash验证配置
let output = app_handle
.shell()
.sidecar(clash_core)?
.sidecar(clash_core.as_str())?
.args(["-t", "-d", app_dir_str, "-f", config_path])
.output()
.await?;
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = std::string::String::from_utf8_lossy(&output.stderr);
let stdout = std::string::String::from_utf8_lossy(&output.stdout);
// 检查进程退出状态和错误输出
let error_keywords = ["FATA", "fatal", "Parse config error", "level=fatal"];
@@ -314,7 +315,7 @@ impl CoreConfigValidator {
};
logging!(info, Type::Validate, "-------- 验证结束 --------");
Ok((false, error_msg)) // 返回错误消息给调用者处理
Ok((false, error_msg.into())) // 返回错误消息给调用者处理
} else {
logging!(info, Type::Validate, "验证成功");
logging!(info, Type::Validate, "-------- 验证结束 --------");