mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
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:
13
src-tauri/Cargo.lock
generated
13
src-tauri/Cargo.lock
generated
@@ -1131,6 +1131,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_yaml_ng",
|
||||
"sha2 0.10.9",
|
||||
"smartstring",
|
||||
"sys-locale",
|
||||
"sysinfo",
|
||||
"sysproxy",
|
||||
@@ -6780,6 +6781,18 @@ version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "smartstring"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol"
|
||||
version = "1.3.0"
|
||||
|
||||
@@ -87,6 +87,7 @@ tauri-plugin-devtools = { version = "2.0.1" }
|
||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo" }
|
||||
clash_verge_logger = { version = "0.1.0", git = "https://github.com/clash-verge-rev/clash-verge-logger" }
|
||||
async-trait = "0.1.89"
|
||||
smartstring = { version = "1.0.1", features = ["serde"] }
|
||||
clash_verge_service_ipc = { version = "2.0.17", features = [
|
||||
"client",
|
||||
], git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::{Result, anyhow};
|
||||
use backoff::{Error as BackoffError, ExponentialBackoff};
|
||||
use smartstring::alias::String;
|
||||
use std::path::PathBuf;
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio::time::sleep;
|
||||
@@ -122,7 +123,7 @@ impl Config {
|
||||
|
||||
if let Some((msg_type, msg_content)) = validation_result {
|
||||
sleep(timing::STARTUP_ERROR_DELAY).await;
|
||||
handle::Handle::notice_message(msg_type, &msg_content);
|
||||
handle::Handle::notice_message(msg_type, msg_content);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::utils::{
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
use std::{fs, time::Duration};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||
@@ -179,8 +180,8 @@ impl PrfItem {
|
||||
file_data: Option<String>,
|
||||
option: Option<PrfOption>,
|
||||
) -> Result<PrfItem> {
|
||||
let uid = help::get_uid("L");
|
||||
let file = format!("{uid}.yaml");
|
||||
let uid = help::get_uid("L").into();
|
||||
let file = format!("{uid}.yaml").into();
|
||||
let opt_ref = option.as_ref();
|
||||
let update_interval = opt_ref.and_then(|o| o.update_interval);
|
||||
let mut merge = opt_ref.and_then(|o| o.merge.clone());
|
||||
@@ -352,9 +353,9 @@ impl PrfItem {
|
||||
None => None,
|
||||
};
|
||||
|
||||
let uid = help::get_uid("R");
|
||||
let file = format!("{uid}.yaml");
|
||||
let name = name.unwrap_or(filename.unwrap_or("Remote File".into()));
|
||||
let uid = help::get_uid("R").into();
|
||||
let file = format!("{uid}.yaml").into();
|
||||
let name = name.unwrap_or(filename.unwrap_or("Remote File".into()).into());
|
||||
let data = resp.text_with_charset()?;
|
||||
|
||||
// process the charset "UTF-8 with BOM"
|
||||
@@ -422,13 +423,13 @@ impl PrfItem {
|
||||
/// ## Merge type (enhance)
|
||||
/// create the enhanced item by using `merge` rule
|
||||
pub fn from_merge(uid: Option<String>) -> Result<PrfItem> {
|
||||
let mut id = help::get_uid("m");
|
||||
let mut id = help::get_uid("m").into();
|
||||
let mut template = tmpl::ITEM_MERGE_EMPTY.into();
|
||||
if let Some(uid) = uid {
|
||||
id = uid;
|
||||
template = tmpl::ITEM_MERGE.into();
|
||||
}
|
||||
let file = format!("{id}.yaml");
|
||||
let file = format!("{id}.yaml").into();
|
||||
|
||||
Ok(PrfItem {
|
||||
uid: Some(id),
|
||||
@@ -449,11 +450,11 @@ impl PrfItem {
|
||||
/// ## Script type (enhance)
|
||||
/// create the enhanced item by using javascript quick.js
|
||||
pub fn from_script(uid: Option<String>) -> Result<PrfItem> {
|
||||
let mut id = help::get_uid("s");
|
||||
let mut id = help::get_uid("s").into();
|
||||
if let Some(uid) = uid {
|
||||
id = uid;
|
||||
}
|
||||
let file = format!("{id}.js"); // js ext
|
||||
let file = format!("{id}.js").into(); // js ext
|
||||
|
||||
Ok(PrfItem {
|
||||
uid: Some(id),
|
||||
@@ -473,8 +474,8 @@ impl PrfItem {
|
||||
|
||||
/// ## Rules type (enhance)
|
||||
pub fn from_rules() -> Result<PrfItem> {
|
||||
let uid = help::get_uid("r");
|
||||
let file = format!("{uid}.yaml"); // yaml ext
|
||||
let uid = help::get_uid("r").into();
|
||||
let file = format!("{uid}.yaml").into(); // yaml ext
|
||||
|
||||
Ok(PrfItem {
|
||||
uid: Some(uid),
|
||||
@@ -494,8 +495,8 @@ impl PrfItem {
|
||||
|
||||
/// ## Proxies type (enhance)
|
||||
pub fn from_proxies() -> Result<PrfItem> {
|
||||
let uid = help::get_uid("p");
|
||||
let file = format!("{uid}.yaml"); // yaml ext
|
||||
let uid = help::get_uid("p").into();
|
||||
let file = format!("{uid}.yaml").into(); // yaml ext
|
||||
|
||||
Ok(PrfItem {
|
||||
uid: Some(uid),
|
||||
@@ -515,8 +516,8 @@ impl PrfItem {
|
||||
|
||||
/// ## Groups type (enhance)
|
||||
pub fn from_groups() -> Result<PrfItem> {
|
||||
let uid = help::get_uid("g");
|
||||
let file = format!("{uid}.yaml"); // yaml ext
|
||||
let uid = help::get_uid("g").into();
|
||||
let file = format!("{uid}.yaml").into(); // yaml ext
|
||||
|
||||
Ok(PrfItem {
|
||||
uid: Some(uid),
|
||||
@@ -540,8 +541,9 @@ impl PrfItem {
|
||||
.file
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow::anyhow!("could not find the file"))?;
|
||||
let path = dirs::app_profiles_dir()?.join(file);
|
||||
fs::read_to_string(path).context("failed to read the file")
|
||||
let path = dirs::app_profiles_dir()?.join(file.as_str());
|
||||
let content = fs::read_to_string(path).context("failed to read the file")?;
|
||||
Ok(content.into())
|
||||
}
|
||||
|
||||
/// save the file data
|
||||
@@ -550,7 +552,7 @@ impl PrfItem {
|
||||
.file
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow::anyhow!("could not find the file"))?;
|
||||
let path = dirs::app_profiles_dir()?.join(file);
|
||||
let path = dirs::app_profiles_dir()?.join(file.as_str());
|
||||
fs::write(path, data.as_bytes()).context("failed to save the file")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::utils::{
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
use std::collections::HashSet;
|
||||
use tokio::fs;
|
||||
|
||||
@@ -47,7 +48,7 @@ impl IProfiles {
|
||||
if let Some(items) = profiles.items.as_mut() {
|
||||
for item in items.iter_mut() {
|
||||
if item.uid.is_none() {
|
||||
item.uid = Some(help::get_uid("d"));
|
||||
item.uid = Some(help::get_uid("d").into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +143,7 @@ impl IProfiles {
|
||||
let file = item.file.clone().ok_or_else(|| {
|
||||
anyhow::anyhow!("file field is required when file_data is provided")
|
||||
})?;
|
||||
let path = dirs::app_profiles_dir()?.join(&file);
|
||||
let path = dirs::app_profiles_dir()?.join(file.as_str());
|
||||
|
||||
fs::write(&path, file_data.as_bytes())
|
||||
.await
|
||||
@@ -240,13 +241,13 @@ impl IProfiles {
|
||||
// move the field value after save
|
||||
if let Some(file_data) = item.file_data.take() {
|
||||
let file = each.file.take();
|
||||
let file =
|
||||
file.unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid)));
|
||||
let file = file
|
||||
.unwrap_or(item.file.take().unwrap_or(format!("{}.yaml", &uid).into()));
|
||||
|
||||
// the file must exists
|
||||
each.file = Some(file.clone());
|
||||
|
||||
let path = dirs::app_profiles_dir()?.join(&file);
|
||||
let path = dirs::app_profiles_dir()?.join(file.as_str());
|
||||
|
||||
fs::write(&path, file_data.as_bytes())
|
||||
.await
|
||||
@@ -291,7 +292,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -306,7 +307,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -321,7 +322,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -336,7 +337,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -351,7 +352,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -366,7 +367,7 @@ impl IProfiles {
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir()?
|
||||
.join(file)
|
||||
.join(file.as_str())
|
||||
.remove_if_exists()
|
||||
.await;
|
||||
}
|
||||
@@ -392,7 +393,7 @@ impl IProfiles {
|
||||
(Some(current), Some(items)) => {
|
||||
if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) {
|
||||
let file_path = match item.file.as_ref() {
|
||||
Some(file) => dirs::app_profiles_dir()?.join(file),
|
||||
Some(file) => dirs::app_profiles_dir()?.join(file.as_str()),
|
||||
None => bail!("failed to get the file field"),
|
||||
};
|
||||
return help::read_mapping(&file_path).await;
|
||||
@@ -544,7 +545,7 @@ impl IProfiles {
|
||||
log::info!(target: "app", "已清理冗余文件: {file_name}");
|
||||
}
|
||||
Err(e) => {
|
||||
failed_deletions.push(format!("{file_name}: {e}"));
|
||||
failed_deletions.push(format!("{file_name}: {e}").into());
|
||||
log::warn!(target: "app", "清理文件失败: {file_name} - {e}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::enhance::field::use_keys;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml_ng::{Mapping, Value};
|
||||
use smartstring::alias::String;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct IRuntime {
|
||||
pub config: Option<Mapping>,
|
||||
@@ -30,15 +32,15 @@ impl IRuntime {
|
||||
let patch_tun = patch.get("tun");
|
||||
if patch_tun.is_some() {
|
||||
let tun = config.get("tun");
|
||||
let mut tun = tun.map_or(Mapping::new(), |val| {
|
||||
let mut tun: Mapping = tun.map_or(Mapping::new(), |val| {
|
||||
val.as_mapping().cloned().unwrap_or(Mapping::new())
|
||||
});
|
||||
let patch_tun = patch_tun.map_or(Mapping::new(), |val| {
|
||||
val.as_mapping().cloned().unwrap_or(Mapping::new())
|
||||
});
|
||||
use_keys(&patch_tun).into_iter().for_each(|key| {
|
||||
if let Some(value) = patch_tun.get(&key).to_owned() {
|
||||
tun.insert(key.into(), value.clone());
|
||||
if let Some(value) = patch_tun.get(key.as_str()) {
|
||||
tun.insert(Value::from(key.as_str()), value.clone());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use log::LevelFilter;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// ### `verge.yaml` schema
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
@@ -322,7 +323,7 @@ impl IVerge {
|
||||
|
||||
fn get_system_language() -> String {
|
||||
let sys_lang = sys_locale::get_locale()
|
||||
.unwrap_or_else(|| String::from("en"))
|
||||
.unwrap_or_else(|| "en".into())
|
||||
.to_lowercase();
|
||||
|
||||
let lang_code = sys_lang.split(['_', '-']).next().unwrap_or("en");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<()> {
|
||||
|
||||
@@ -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)?,
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
utils::logging::Type,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use smartstring::alias::String;
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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, "-------- 验证结束 --------");
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
utils::{dirs, help},
|
||||
};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -73,7 +74,7 @@ impl AsyncChainItemFrom for Option<ChainItem> {
|
||||
let itype = item.itype.as_ref()?.as_str();
|
||||
let file = item.file.clone()?;
|
||||
let uid = item.uid.clone().unwrap_or("".into());
|
||||
let path = dirs::app_profiles_dir().ok()?.join(file);
|
||||
let path = dirs::app_profiles_dir().ok()?.join(file.as_str());
|
||||
|
||||
if !path.exists() {
|
||||
return None;
|
||||
@@ -82,7 +83,7 @@ impl AsyncChainItemFrom for Option<ChainItem> {
|
||||
match itype {
|
||||
"script" => Some(ChainItem {
|
||||
uid,
|
||||
data: ChainType::Script(fs::read_to_string(path).ok()?),
|
||||
data: ChainType::Script(fs::read_to_string(path).ok()?.into()),
|
||||
}),
|
||||
"merge" => Some(ChainItem {
|
||||
uid,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use serde_yaml_ng::{Mapping, Value};
|
||||
use smartstring::alias::String;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub const HANDLE_FIELDS: [&str; 12] = [
|
||||
@@ -31,7 +32,7 @@ pub fn use_lowercase(config: Mapping) -> Mapping {
|
||||
if let Some(key_str) = key.as_str() {
|
||||
let mut key_str = String::from(key_str);
|
||||
key_str.make_ascii_lowercase();
|
||||
ret.insert(Value::from(key_str), value);
|
||||
ret.insert(Value::from(key_str.as_str()), value);
|
||||
}
|
||||
}
|
||||
ret
|
||||
@@ -70,8 +71,8 @@ pub fn use_keys(config: &Mapping) -> Vec<String> {
|
||||
config
|
||||
.iter()
|
||||
.filter_map(|(key, _)| key.as_str())
|
||||
.map(|s| {
|
||||
let mut s = s.to_string();
|
||||
.map(|s: &str| {
|
||||
let mut s: String = s.into();
|
||||
s.make_ascii_lowercase();
|
||||
s
|
||||
})
|
||||
|
||||
@@ -8,6 +8,7 @@ mod tun;
|
||||
use self::{chain::*, field::*, merge::*, script::*, seq::*, tun::*};
|
||||
use crate::{config::Config, utils::tmpl};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
type ResultLog = Vec<(String, String)>;
|
||||
@@ -192,7 +193,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
let item = {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles = profiles.latest_ref();
|
||||
profiles.get_item(&"Merge".to_string()).ok().cloned()
|
||||
profiles.get_item(&"Merge".into()).ok().cloned()
|
||||
};
|
||||
if let Some(item) = item {
|
||||
<Option<ChainItem>>::from_async(&item).await
|
||||
@@ -209,7 +210,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
let item = {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles = profiles.latest_ref();
|
||||
profiles.get_item(&"Script".to_string()).ok().cloned()
|
||||
profiles.get_item(&"Script".into()).ok().cloned()
|
||||
};
|
||||
if let Some(item) = item {
|
||||
<Option<ChainItem>>::from_async(&item).await
|
||||
@@ -253,7 +254,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
config = res_config;
|
||||
logs.extend(res_logs);
|
||||
}
|
||||
Err(err) => logs.push(("exception".into(), err.to_string())),
|
||||
Err(err) => logs.push(("exception".into(), err.to_string().into())),
|
||||
}
|
||||
|
||||
result_map.insert(global_script.uid, logs);
|
||||
@@ -280,13 +281,13 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
if let ChainType::Script(script) = script_item.data {
|
||||
let mut logs = vec![];
|
||||
|
||||
match use_script(script, config.to_owned(), profile_name.to_owned()) {
|
||||
match use_script(script, config.to_owned(), profile_name) {
|
||||
Ok((res_config, res_logs)) => {
|
||||
exists_keys.extend(use_keys(&res_config));
|
||||
config = res_config;
|
||||
logs.extend(res_logs);
|
||||
}
|
||||
Err(err) => logs.push(("exception".into(), err.to_string())),
|
||||
Err(err) => logs.push(("exception".into(), err.to_string().into())),
|
||||
}
|
||||
|
||||
result_map.insert(script_item.uid, logs);
|
||||
@@ -361,7 +362,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
.for_each(|item| {
|
||||
log::debug!(target: "app", "run builtin script {}", item.uid);
|
||||
if let ChainType::Script(script) = item.data {
|
||||
match use_script(script, config.to_owned(), "".to_string()) {
|
||||
match use_script(script, config.to_owned(), "".into()) {
|
||||
Ok((res_config, _)) => {
|
||||
config = res_config;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::use_lowercase;
|
||||
use anyhow::{Error, Result};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use smartstring::alias::String;
|
||||
|
||||
pub fn use_script(
|
||||
script: String,
|
||||
@@ -44,7 +45,7 @@ pub fn use_script(
|
||||
)
|
||||
})?;
|
||||
let mut out = copy_outputs.borrow_mut();
|
||||
out.push((level, data));
|
||||
out.push((level.into(), data.into()));
|
||||
Ok(JsValue::undefined())
|
||||
},
|
||||
),
|
||||
@@ -94,7 +95,7 @@ pub fn use_script(
|
||||
match res {
|
||||
Ok(config) => Ok((use_lowercase(config), out.to_vec())),
|
||||
Err(err) => {
|
||||
out.push(("exception".into(), err.to_string()));
|
||||
out.push(("exception".into(), err.to_string().into()));
|
||||
Ok((config, out.to_vec()))
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,7 @@ fn strip_outer_quotes(s: &str) -> &str {
|
||||
|
||||
// 转义单引号和反斜杠,用于单引号包裹的JavaScript字符串
|
||||
fn escape_js_string_for_single_quote(s: &str) -> String {
|
||||
s.replace('\\', "\\\\").replace('\'', "\\'")
|
||||
s.replace('\\', "\\\\").replace('\'', "\\'").into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -150,7 +151,7 @@ fn test_script() {
|
||||
";
|
||||
|
||||
let config = serde_yaml_ng::from_str(config).expect("Failed to parse test config YAML");
|
||||
let (config, results) = use_script(script.into(), config, "".to_string())
|
||||
let (config, results) = use_script(script.into(), config, "".into())
|
||||
.expect("Script execution should succeed in test");
|
||||
|
||||
let _ = serde_yaml_ng::to_string(&config).expect("Failed to serialize config to YAML");
|
||||
|
||||
@@ -11,6 +11,7 @@ use anyhow::{Result, anyhow};
|
||||
use chrono::Utc;
|
||||
use reqwest_dav::list_cmd::ListFile;
|
||||
use serde::Serialize;
|
||||
use smartstring::alias::String;
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@@ -82,7 +83,7 @@ pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
||||
|
||||
let backup_storage_path = app_home_dir()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to get app home dir: {e}"))?
|
||||
.join(&filename);
|
||||
.join(filename.as_str());
|
||||
backup::WebDavClient::global()
|
||||
.download(filename, backup_storage_path.clone())
|
||||
.await
|
||||
@@ -128,7 +129,7 @@ pub async fn create_local_backup() -> Result<()> {
|
||||
})?;
|
||||
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let target_path = backup_dir.join(&file_name);
|
||||
let target_path = backup_dir.join(file_name.as_str());
|
||||
|
||||
if let Err(err) = move_file(temp_file_path.clone(), target_path.clone()) {
|
||||
logging!(
|
||||
@@ -196,9 +197,9 @@ pub fn list_local_backup() -> Result<Vec<LocalBackupFile>> {
|
||||
.map(|time| chrono::DateTime::<Utc>::from(time).to_rfc3339())
|
||||
.unwrap_or_default();
|
||||
backups.push(LocalBackupFile {
|
||||
filename: file_name.to_string(),
|
||||
path: path.to_string_lossy().to_string(),
|
||||
last_modified,
|
||||
filename: file_name.into(),
|
||||
path: path.to_string_lossy().into(),
|
||||
last_modified: last_modified.into(),
|
||||
content_length: metadata.len(),
|
||||
});
|
||||
}
|
||||
@@ -210,7 +211,7 @@ pub fn list_local_backup() -> Result<Vec<LocalBackupFile>> {
|
||||
/// Delete local backup
|
||||
pub async fn delete_local_backup(filename: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let target_path = backup_dir.join(&filename);
|
||||
let target_path = backup_dir.join(filename.as_str());
|
||||
if !target_path.exists() {
|
||||
logging!(
|
||||
warn,
|
||||
@@ -227,7 +228,7 @@ pub async fn delete_local_backup(filename: String) -> Result<()> {
|
||||
/// Restore local backup
|
||||
pub async fn restore_local_backup(filename: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let target_path = backup_dir.join(&filename);
|
||||
let target_path = backup_dir.join(filename.as_str());
|
||||
if !target_path.exists() {
|
||||
return Err(anyhow!("Backup file not found: {}", filename));
|
||||
}
|
||||
@@ -259,12 +260,12 @@ pub async fn restore_local_backup(filename: String) -> Result<()> {
|
||||
/// Export local backup file to user selected destination
|
||||
pub fn export_local_backup(filename: String, destination: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let source_path = backup_dir.join(&filename);
|
||||
let source_path = backup_dir.join(filename.as_str());
|
||||
if !source_path.exists() {
|
||||
return Err(anyhow!("Backup file not found: {}", filename));
|
||||
}
|
||||
|
||||
let dest_path = PathBuf::from(destination);
|
||||
let dest_path = PathBuf::from(destination.as_str());
|
||||
if let Some(parent) = dest_path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
utils::{self, logging::Type, resolve},
|
||||
};
|
||||
use serde_yaml_ng::{Mapping, Value};
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// Restart the Clash core
|
||||
pub async fn restart_clash_core() {
|
||||
@@ -58,7 +59,7 @@ fn after_change_clash_mode() {
|
||||
/// Change Clash mode (rule/global/direct/script)
|
||||
pub async fn change_clash_mode(mode: String) {
|
||||
let mut mapping = Mapping::new();
|
||||
mapping.insert(Value::from("mode"), mode.clone().into());
|
||||
mapping.insert(Value::from("mode"), Value::from(mode.as_str()));
|
||||
// Convert YAML mapping to JSON Value
|
||||
let json_value = serde_json::json!({
|
||||
"mode": mode
|
||||
@@ -112,7 +113,7 @@ pub async fn test_delay(url: String) -> anyhow::Result<u32> {
|
||||
ProxyType::None
|
||||
};
|
||||
|
||||
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".to_string());
|
||||
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".into());
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
utils::logging::Type,
|
||||
};
|
||||
use anyhow::{Result, bail};
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// Toggle proxy profile
|
||||
pub async fn toggle_proxy_profile(profile_index: String) {
|
||||
|
||||
@@ -66,7 +66,7 @@ pub async fn toggle_tun_mode(not_save_file: Option<bool>) {
|
||||
pub async fn copy_clash_env() {
|
||||
// 从环境变量获取IP地址,如果没有则从配置中获取 proxy_host,默认为 127.0.0.1
|
||||
let clash_verge_rev_ip = match env::var("CLASH_VERGE_REV_IP") {
|
||||
Ok(ip) => ip,
|
||||
Ok(ip) => ip.into(),
|
||||
Err(_) => Config::verge()
|
||||
.await
|
||||
.latest_ref()
|
||||
|
||||
@@ -86,7 +86,7 @@ mod app_init {
|
||||
let url = event.urls().first().map(|u| u.to_string());
|
||||
if let Some(url) = url {
|
||||
AsyncHandler::spawn(|| async {
|
||||
if let Err(e) = resolve::resolve_scheme(url).await {
|
||||
if let Err(e) = resolve::resolve_scheme(url.into()).await {
|
||||
logging!(error, Type::Setup, "Failed to resolve scheme: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -305,7 +305,7 @@ async fn setup_light_weight_timer() -> Result<()> {
|
||||
interval_minutes: once_by_minutes,
|
||||
last_run: chrono::Local::now().timestamp(),
|
||||
};
|
||||
timer_map.insert(LIGHT_WEIGHT_TASK_UID.to_string(), timer_task);
|
||||
timer_map.insert(LIGHT_WEIGHT_TASK_UID.into(), timer_task);
|
||||
}
|
||||
|
||||
logging!(
|
||||
|
||||
@@ -541,7 +541,7 @@ pub async fn startup_script() -> Result<()> {
|
||||
));
|
||||
};
|
||||
|
||||
let script_dir = PathBuf::from(&script_path);
|
||||
let script_dir = PathBuf::from(script_path.as_str());
|
||||
if !script_dir.exists() {
|
||||
return Err(anyhow::anyhow!("script not found: {}", script_path));
|
||||
}
|
||||
@@ -553,7 +553,7 @@ pub async fn startup_script() -> Result<()> {
|
||||
.shell()
|
||||
.command(shell_type)
|
||||
.current_dir(working_dir)
|
||||
.args(&[script_path])
|
||||
.args([script_path.as_str()])
|
||||
.output()
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -98,21 +98,10 @@ macro_rules! wrap_err {
|
||||
// Case 1: Future<Result<T, E>>
|
||||
($stat:expr, async) => {{
|
||||
match $stat.await {
|
||||
Ok(a) => Ok(a),
|
||||
Ok(a) => Ok::<_, ::anyhow::Error>(a),
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "{}", err);
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
// Case 2: Result<T, E>
|
||||
($stat:expr) => {{
|
||||
match $stat {
|
||||
Ok(a) => Ok(a),
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "{}", err);
|
||||
Err(err.to_string())
|
||||
Err(::anyhow::Error::msg(err.to_string()))
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::config::Config;
|
||||
use anyhow::Result;
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
use isahc::prelude::*;
|
||||
@@ -9,14 +10,13 @@ use isahc::{
|
||||
header::{HeaderMap, HeaderValue, USER_AGENT},
|
||||
},
|
||||
};
|
||||
use smartstring::alias::String;
|
||||
use std::time::{Duration, Instant};
|
||||
use sysproxy::Sysproxy;
|
||||
use tauri::Url;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::timeout;
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HttpResponse {
|
||||
status: StatusCode,
|
||||
@@ -80,7 +80,7 @@ impl NetworkManager {
|
||||
|
||||
async fn record_connection_error(&self, error: &str) {
|
||||
let mut last_error = self.last_connection_error.lock().await;
|
||||
*last_error = Some((Instant::now(), error.to_string()));
|
||||
*last_error = Some((Instant::now(), error.into()));
|
||||
|
||||
let mut count = self.connection_error_count.lock().await;
|
||||
*count += 1;
|
||||
@@ -181,8 +181,9 @@ impl NetworkManager {
|
||||
headers.insert(
|
||||
USER_AGENT,
|
||||
HeaderValue::from_str(
|
||||
&user_agent
|
||||
.unwrap_or_else(|| format!("clash-verge/v{}", env!("CARGO_PKG_VERSION"))),
|
||||
&user_agent.unwrap_or_else(|| {
|
||||
format!("clash-verge/v{}", env!("CARGO_PKG_VERSION")).into()
|
||||
}),
|
||||
)?,
|
||||
);
|
||||
|
||||
@@ -240,7 +241,7 @@ impl NetworkManager {
|
||||
let status = response.status();
|
||||
let headers = response.headers().clone();
|
||||
let body = response.text().await?;
|
||||
Ok::<_, anyhow::Error>(HttpResponse::new(status, headers, body))
|
||||
Ok::<_, anyhow::Error>(HttpResponse::new(status, headers, body.into()))
|
||||
})
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use smartstring::alias::String;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use anyhow::{Result, bail};
|
||||
use percent_encoding::percent_decode_str;
|
||||
use smartstring::alias::String;
|
||||
use tauri::Url;
|
||||
|
||||
use crate::{config::PrfItem, core::handle, logging, utils::logging::Type, wrap_err};
|
||||
use crate::{config::PrfItem, core::handle, logging, logging_error, utils::logging::Type};
|
||||
|
||||
pub(super) async fn resolve_scheme(param: String) -> Result<()> {
|
||||
log::info!(target:"app", "received deep link: {param}");
|
||||
@@ -27,7 +28,7 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> {
|
||||
let name = link_parsed
|
||||
.query_pairs()
|
||||
.find(|(key, _)| key == "name")
|
||||
.map(|(_, value)| value.into_owned());
|
||||
.map(|(_, value)| value.into());
|
||||
|
||||
let url_param = if let Some(query) = link_parsed.query() {
|
||||
let prefix = "url=";
|
||||
@@ -58,7 +59,11 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> {
|
||||
}
|
||||
};
|
||||
let result = crate::config::profiles::profiles_append_item_safe(item).await;
|
||||
let _ = wrap_err!(result);
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
"failed to import subscription url: {:?}",
|
||||
result
|
||||
);
|
||||
handle::Handle::notice_message("import_sub_url::ok", uid);
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -26,11 +26,11 @@ pub async fn build_new_window() -> Result<WebviewWindow, String> {
|
||||
.latest_ref()
|
||||
.start_page
|
||||
.clone()
|
||||
.unwrap_or("/".to_string());
|
||||
.unwrap_or("/".into());
|
||||
match tauri::WebviewWindowBuilder::new(
|
||||
app_handle,
|
||||
"main", /* the unique window label */
|
||||
tauri::WebviewUrl::App(start_page.into()),
|
||||
tauri::WebviewUrl::App(start_page.as_str().into()),
|
||||
)
|
||||
.title("Clash Verge")
|
||||
.center()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use super::resolve;
|
||||
use crate::{
|
||||
config::{Config, DEFAULT_PAC, IVerge},
|
||||
@@ -13,6 +11,8 @@ use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use port_scanner::local_port_available;
|
||||
use reqwest::ClientBuilder;
|
||||
use smartstring::alias::String;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::oneshot;
|
||||
use warp::Filter;
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn check_singleton() -> Result<()> {
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(Duration::from_millis(500))
|
||||
.build()?;
|
||||
let argvs: Vec<String> = std::env::args().collect();
|
||||
let argvs: Vec<std::string::String> = std::env::args().collect();
|
||||
if argvs.len() > 1 {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
@@ -75,8 +75,8 @@ pub fn embed_server() {
|
||||
} else {
|
||||
logging!(error, Type::Window, "轻量模式退出失败,无法恢复应用窗口");
|
||||
};
|
||||
Ok::<_, warp::Rejection>(warp::reply::with_status::<String>(
|
||||
"ok".into(),
|
||||
Ok::<_, warp::Rejection>(warp::reply::with_status::<std::string::String>(
|
||||
"ok".to_string(),
|
||||
warp::http::StatusCode::OK,
|
||||
))
|
||||
});
|
||||
@@ -111,7 +111,10 @@ pub fn embed_server() {
|
||||
tokio::task::spawn_local(async move {
|
||||
logging_error!(Type::Setup, resolve::resolve_scheme(param).await);
|
||||
});
|
||||
warp::reply::with_status::<String>("ok".into(), warp::http::StatusCode::OK)
|
||||
warp::reply::with_status::<std::string::String>(
|
||||
"ok".to_string(),
|
||||
warp::http::StatusCode::OK,
|
||||
)
|
||||
});
|
||||
|
||||
let commands = visible.or(scheme).or(pac);
|
||||
|
||||
Reference in New Issue
Block a user