Revert "feat: update Cargo.toml for 2024 edition and optimize release profiles (#4681)"

This reverts commit 31e3104c7f.
This commit is contained in:
Tunglies
2025-09-08 21:48:09 +08:00
parent 31e3104c7f
commit 55b95a1985
51 changed files with 793 additions and 782 deletions

View File

@@ -6,7 +6,7 @@ authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
license = "GPL-3.0-only" license = "GPL-3.0-only"
repository = "https://github.com/clash-verge-rev/clash-verge-rev.git" repository = "https://github.com/clash-verge-rev/clash-verge-rev.git"
default-run = "clash-verge" default-run = "clash-verge"
edition = "2024" edition = "2021"
build = "build.rs" build = "build.rs"
[package.metadata.bundle] [package.metadata.bundle]
@@ -117,33 +117,27 @@ verge-dev = []
tokio-trace = ["console-subscriber"] tokio-trace = ["console-subscriber"]
[profile.release] [profile.release]
panic = "unwind" panic = "abort"
codegen-units = 16 codegen-units = 1
lto = true lto = true
opt-level = 3 opt-level = "s"
debug = false strip = true
strip = "none"
overflow-checks = false
rpath = false
[profile.dev] [profile.dev]
incremental = true incremental = true
codegen-units = 64 codegen-units = 256 # 增加编译单元,提升编译速度
opt-level = 0 opt-level = 0 # 禁用优化,进一步提升编译速度
debug = true debug = true # 保留调试信息
strip = "none" strip = false # 不剥离符号,保留调试信息
overflow-checks = true
lto = false
rpath = false
[profile.fast-release] [profile.fast-release]
inherits = "release" inherits = "release" # 继承 release 的配置
panic = "abort" panic = "abort" # 与 release 相同
codegen-units = 64 codegen-units = 256 # 增加编译单元,提升编译速度
lto = false lto = false # 禁用 LTO提升编译速度
opt-level = 0 opt-level = 0 # 禁用优化,大幅提升编译速度
debug = true debug = true # 保留调试信息
strip = false strip = false # 不剥离符号,保留调试信息
[lib] [lib]
name = "app_lib" name = "app_lib"

View File

@@ -1,4 +1,4 @@
use criterion::{Criterion, criterion_group, criterion_main}; use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box; use std::hint::black_box;
// 业务模型 & Draft // 业务模型 & Draft

View File

@@ -1,7 +1,7 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
config::Config, config::Config,
core::{CoreManager, handle}, core::{handle, CoreManager},
}; };
use crate::{ use crate::{
config::*, config::*,
@@ -166,7 +166,7 @@ pub async fn save_dns_config(dns_config: Mapping) -> CmdResult {
pub async fn apply_dns_config(apply: bool) -> CmdResult { pub async fn apply_dns_config(apply: bool) -> CmdResult {
use crate::{ use crate::{
config::Config, config::Config,
core::{CoreManager, handle}, core::{handle, CoreManager},
utils::dirs, utils::dirs,
}; };

View File

@@ -618,20 +618,20 @@ async fn check_netflix(client: &Client) -> UnlockItem {
{ {
Ok(response) => { Ok(response) => {
// 检查重定向位置 // 检查重定向位置
if let Some(location) = response.headers().get("location") if let Some(location) = response.headers().get("location") {
&& let Ok(location_str) = location.to_str() if let Ok(location_str) = location.to_str() {
{ // 解析位置获取区域
// 解析位置获取区域 let parts: Vec<&str> = location_str.split('/').collect();
let parts: Vec<&str> = location_str.split('/').collect(); if parts.len() >= 4 {
if parts.len() >= 4 { let region_code = parts[3].split('-').next().unwrap_or("unknown");
let region_code = parts[3].split('-').next().unwrap_or("unknown"); let emoji = country_code_to_emoji(region_code);
let emoji = country_code_to_emoji(region_code); return UnlockItem {
return UnlockItem { name: "Netflix".to_string(),
name: "Netflix".to_string(), status: "Yes".to_string(),
status: "Yes".to_string(), region: Some(format!("{emoji}{region_code}")),
region: Some(format!("{emoji}{region_code}")), check_time: Some(get_local_date_string()),
check_time: Some(get_local_date_string()), };
}; }
} }
} }
// 如果没有重定向,假设是美国 // 如果没有重定向,假设是美国
@@ -691,18 +691,22 @@ async fn check_netflix_cdn(client: &Client) -> UnlockItem {
match response.json::<serde_json::Value>().await { match response.json::<serde_json::Value>().await {
Ok(data) => { Ok(data) => {
// 尝试从数据中提取区域信息 // 尝试从数据中提取区域信息
if let Some(targets) = data.get("targets").and_then(|t| t.as_array()) if let Some(targets) = data.get("targets").and_then(|t| t.as_array()) {
&& !targets.is_empty() if !targets.is_empty() {
&& let Some(location) = targets[0].get("location") if let Some(location) = targets[0].get("location") {
&& let Some(country) = location.get("country").and_then(|c| c.as_str()) if let Some(country) =
{ location.get("country").and_then(|c| c.as_str())
let emoji = country_code_to_emoji(country); {
return UnlockItem { let emoji = country_code_to_emoji(country);
name: "Netflix".to_string(), return UnlockItem {
status: "Yes".to_string(), name: "Netflix".to_string(),
region: Some(format!("{emoji}{country}")), status: "Yes".to_string(),
check_time: Some(get_local_date_string()), region: Some(format!("{emoji}{country}")),
}; check_time: Some(get_local_date_string()),
};
}
}
}
} }
// 如果无法解析区域信息 // 如果无法解析区域信息

View File

@@ -1,5 +1,5 @@
use super::CmdResult; use super::CmdResult;
use crate::core::{EventDrivenProxyManager, async_proxy_query::AsyncProxyQuery}; use crate::core::{async_proxy_query::AsyncProxyQuery, EventDrivenProxyManager};
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::wrap_err; use crate::wrap_err;
use network_interface::NetworkInterface; use network_interface::NetworkInterface;

View File

@@ -1,14 +1,13 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
config::{ config::{
Config, IProfiles, PrfItem, PrfOption,
profiles::{ profiles::{
profiles_append_item_with_filedata_safe, profiles_delete_item_safe, profiles_append_item_with_filedata_safe, profiles_delete_item_safe,
profiles_patch_item_safe, profiles_reorder_safe, profiles_save_file_safe, profiles_patch_item_safe, profiles_reorder_safe, profiles_save_file_safe,
}, },
profiles_append_item_safe, profiles_append_item_safe, Config, IProfiles, PrfItem, PrfOption,
}, },
core::{CoreManager, handle, timer::Timer, tray::Tray}, core::{handle, timer::Timer, tray::Tray, CoreManager},
feat, logging, feat, logging,
process::AsyncHandler, process::AsyncHandler,
ret_err, ret_err,
@@ -291,107 +290,110 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile); logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
// 如果要切换配置,先检查目标配置文件是否有语法错误 // 如果要切换配置,先检查目标配置文件是否有语法错误
if let Some(new_profile) = profiles.current.as_ref() if let Some(new_profile) = profiles.current.as_ref() {
&& current_profile.as_ref() != Some(new_profile) if current_profile.as_ref() != Some(new_profile) {
{ logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
// 获取目标配置文件路径 // 获取目标配置文件路径
let config_file_result = { let config_file_result = {
let profiles_config = Config::profiles().await; let profiles_config = Config::profiles().await;
let profiles_data = profiles_config.latest_ref(); let profiles_data = profiles_config.latest_ref();
match profiles_data.get_item(new_profile) { match profiles_data.get_item(new_profile) {
Ok(item) => { Ok(item) => {
if let Some(file) = &item.file { 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));
path.ok() path.ok()
} else { } else {
None
}
}
Err(e) => {
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
None None
} }
} }
Err(e) => { };
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
None
}
}
};
// 如果获取到文件路径检查YAML语法 // 如果获取到文件路径检查YAML语法
if let Some(file_path) = config_file_result { if let Some(file_path) = config_file_result {
if !file_path.exists() { if !file_path.exists() {
logging!( logging!(
error, error,
Type::Cmd, Type::Cmd,
true, true,
"目标配置文件不存在: {}", "目标配置文件不存在: {}",
file_path.display() file_path.display()
); );
handle::Handle::notice_message(
"config_validate::file_not_found",
format!("{}", file_path.display()),
);
return Ok(false);
}
// 超时保护
let file_read_result = tokio::time::timeout(
Duration::from_secs(5),
tokio::fs::read_to_string(&file_path),
)
.await;
match file_read_result {
Ok(Ok(content)) => {
let yaml_parse_result = AsyncHandler::spawn_blocking(move || {
serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content)
})
.await;
match yaml_parse_result {
Ok(Ok(_)) => {
logging!(info, Type::Cmd, true, "目标配置文件语法正确");
}
Ok(Err(err)) => {
let error_msg = format!(" {err}");
logging!(
error,
Type::Cmd,
true,
"目标配置文件存在YAML语法错误:{}",
error_msg
);
handle::Handle::notice_message(
"config_validate::yaml_syntax_error",
&error_msg,
);
return Ok(false);
}
Err(join_err) => {
let error_msg = format!("YAML解析任务失败: {join_err}");
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::yaml_parse_error",
&error_msg,
);
return Ok(false);
}
}
}
Ok(Err(err)) => {
let error_msg = format!("无法读取目标配置文件: {err}");
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message("config_validate::file_read_error", &error_msg);
return Ok(false);
}
Err(_) => {
let error_msg = "读取配置文件超时(5秒)".to_string();
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message( handle::Handle::notice_message(
"config_validate::file_read_timeout", "config_validate::file_not_found",
&error_msg, format!("{}", file_path.display()),
); );
return Ok(false); return Ok(false);
} }
// 超时保护
let file_read_result = tokio::time::timeout(
Duration::from_secs(5),
tokio::fs::read_to_string(&file_path),
)
.await;
match file_read_result {
Ok(Ok(content)) => {
let yaml_parse_result = AsyncHandler::spawn_blocking(move || {
serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content)
})
.await;
match yaml_parse_result {
Ok(Ok(_)) => {
logging!(info, Type::Cmd, true, "目标配置文件语法正确");
}
Ok(Err(err)) => {
let error_msg = format!(" {err}");
logging!(
error,
Type::Cmd,
true,
"目标配置文件存在YAML语法错误:{}",
error_msg
);
handle::Handle::notice_message(
"config_validate::yaml_syntax_error",
&error_msg,
);
return Ok(false);
}
Err(join_err) => {
let error_msg = format!("YAML解析任务失败: {join_err}");
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::yaml_parse_error",
&error_msg,
);
return Ok(false);
}
}
}
Ok(Err(err)) => {
let error_msg = format!("无法读取目标配置文件: {err}");
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::file_read_error",
&error_msg,
);
return Ok(false);
}
Err(_) => {
let error_msg = "读取配置文件超时(5秒)".to_string();
logging!(error, Type::Cmd, true, "{}", error_msg);
handle::Handle::notice_message(
"config_validate::file_read_timeout",
&error_msg,
);
return Ok(false);
}
}
} }
} }
} }
@@ -661,9 +663,8 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
#[tauri::command] #[tauri::command]
pub async fn view_profile(index: String) -> CmdResult { pub async fn view_profile(index: String) -> CmdResult {
let profiles = Config::profiles().await; let profiles = Config::profiles().await;
let profiles_ref = profiles.latest_ref();
let file = { let file = {
wrap_err!(profiles_ref.get_item(&index))? wrap_err!(profiles.latest_ref().get_item(&index))?
.file .file
.clone() .clone()
.ok_or("the file field is null") .ok_or("the file field is null")

View File

@@ -16,12 +16,11 @@ pub async fn get_runtime_yaml() -> CmdResult<String> {
let runtime = Config::runtime().await; let runtime = Config::runtime().await;
let runtime = runtime.latest_ref(); let runtime = runtime.latest_ref();
let config = runtime.config.as_ref(); let config = runtime.config.as_ref();
wrap_err!( wrap_err!(config
config .ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
.ok_or(anyhow::anyhow!("failed to parse config to yaml file")) .and_then(
.and_then(|config| serde_yaml_ng::to_string(config) |config| serde_yaml_ng::to_string(config).context("failed to convert config to yaml")
.context("failed to convert config to yaml")) ))
)
} }
/// 获取运行时存在的键 /// 获取运行时存在的键

View File

@@ -1,6 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
core::{CoreManager, service}, core::{service, CoreManager},
utils::i18n::t, utils::i18n::t,
}; };
use anyhow::Result; use anyhow::Result;

View File

@@ -1,6 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
core::{CoreManager, handle}, core::{handle, CoreManager},
logging, logging,
module::sysinfo::PlatformSpecification, module::sysinfo::PlatformSpecification,
utils::logging::Type, utils::logging::Type,

View File

@@ -25,17 +25,17 @@ impl IClashTemp {
match map_result { match map_result {
Ok(mut map) => { Ok(mut map) => {
template.0.keys().for_each(|key| { template.0.keys().for_each(|key| {
if !map.contains_key(key) if !map.contains_key(key) {
&& let Some(value) = template.0.get(key) if let Some(value) = template.0.get(key) {
{ map.insert(key.clone(), value.clone());
map.insert(key.clone(), value.clone()); }
} }
}); });
// 确保 secret 字段存在且不为空 // 确保 secret 字段存在且不为空
if let Some(Value::String(s)) = map.get_mut("secret") if let Some(Value::String(s)) = map.get_mut("secret") {
&& s.is_empty() if s.is_empty() {
{ *s = "set-your-secret".to_string();
*s = "set-your-secret".to_string(); }
} }
Self(Self::guard(map)) Self(Self::guard(map))
} }

View File

@@ -1,14 +1,14 @@
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge}; use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
use crate::{ use crate::{
config::{PrfItem, profiles_append_item_safe}, config::{profiles_append_item_safe, PrfItem},
core::{CoreManager, handle}, core::{handle, CoreManager},
enhance, logging, enhance, logging,
utils::{dirs, help, logging::Type}, utils::{dirs, help, logging::Type},
}; };
use anyhow::{Result, anyhow}; use anyhow::{anyhow, Result};
use std::path::PathBuf; use std::path::PathBuf;
use tokio::sync::OnceCell; use tokio::sync::OnceCell;
use tokio::time::{Duration, sleep}; use tokio::time::{sleep, Duration};
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml"; pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml"; pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";

View File

@@ -1,9 +1,9 @@
use crate::utils::dirs::get_encryption_key; use crate::utils::dirs::get_encryption_key;
use aes_gcm::{ use aes_gcm::{
Aes256Gcm, Key,
aead::{Aead, KeyInit}, aead::{Aead, KeyInit},
Aes256Gcm, Key,
}; };
use base64::{Engine, engine::general_purpose::STANDARD}; use base64::{engine::general_purpose::STANDARD, Engine};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
const NONCE_LENGTH: usize = 12; const NONCE_LENGTH: usize = 12;

View File

@@ -3,7 +3,7 @@ use crate::utils::{
network::{NetworkManager, ProxyType}, network::{NetworkManager, ProxyType},
tmpl, tmpl,
}; };
use anyhow::{Context, Result, bail}; use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::{fs, time::Duration}; use std::{fs, time::Duration};

View File

@@ -1,10 +1,10 @@
use super::{PrfOption, prfitem::PrfItem}; use super::{prfitem::PrfItem, PrfOption};
use crate::{ use crate::{
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,
utils::{dirs, help, logging::Type}, utils::{dirs, help, logging::Type},
}; };
use anyhow::{Context, Result, bail}; use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::collections::HashSet; use std::collections::HashSet;
@@ -88,12 +88,12 @@ impl IProfiles {
self.items = Some(vec![]); self.items = Some(vec![]);
} }
if let Some(current) = patch.current if let Some(current) = patch.current {
&& let Some(items) = self.items.as_ref() if let Some(items) = self.items.as_ref() {
{ let some_uid = Some(current);
let some_uid = Some(current); if items.iter().any(|e| e.uid == some_uid) {
if items.iter().any(|e| e.uid == some_uid) { self.current = some_uid;
self.current = some_uid; }
} }
} }
@@ -287,24 +287,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = index if let Some(index) = index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// get the merge index // get the merge index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -313,24 +313,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = merge_index if let Some(index) = merge_index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// get the script index // get the script index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -339,24 +339,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = script_index if let Some(index) = script_index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// get the rules index // get the rules index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -365,24 +365,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = rules_index if let Some(index) = rules_index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// get the proxies index // get the proxies index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -391,24 +391,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = proxies_index if let Some(index) = proxies_index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// get the groups index // get the groups index
for (i, _) in items.iter().enumerate() { for (i, _) in items.iter().enumerate() {
@@ -417,24 +417,24 @@ impl IProfiles {
break; break;
} }
} }
if let Some(index) = groups_index if let Some(index) = groups_index {
&& let Some(file) = items.remove(index).file if let Some(file) = items.remove(index).file {
{ let _ = dirs::app_profiles_dir().map(async move |path| {
let _ = dirs::app_profiles_dir().map(async move |path| { let path = path.join(file);
let path = path.join(file); if path.exists() {
if path.exists() { let result = fs::remove_file(path.clone()).await;
let result = fs::remove_file(path.clone()).await; if let Err(err) = result {
if let Err(err) = result { logging_error!(
logging_error!( Type::Config,
Type::Config, false,
false, "[配置文件删除] 删除文件 {} 失败: {}",
"[配置文件删除] 删除文件 {} 失败: {}", path.display(),
path.display(), err
err );
); }
} }
} });
}); }
} }
// delete the original uid // delete the original uid
if current == uid { if current == uid {
@@ -595,25 +595,25 @@ impl IProfiles {
total_files += 1; total_files += 1;
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
&& Self::is_profile_file(file_name) if Self::is_profile_file(file_name) {
{ // 检查是否为全局扩展文件
// 检查是否为全局扩展文件 if protected_files.contains(file_name) {
if protected_files.contains(file_name) { log::debug!(target: "app", "保护全局扩展配置文件: {file_name}");
log::debug!(target: "app", "保护全局扩展配置文件: {file_name}"); continue;
continue; }
}
// 检查是否为活跃文件 // 检查是否为活跃文件
if !active_files.contains(file_name) { if !active_files.contains(file_name) {
match std::fs::remove_file(&path) { match std::fs::remove_file(&path) {
Ok(_) => { Ok(_) => {
deleted_files.push(file_name.to_string()); deleted_files.push(file_name.to_string());
log::info!(target: "app", "已清理冗余文件: {file_name}"); log::info!(target: "app", "已清理冗余文件: {file_name}");
} }
Err(e) => { Err(e) => {
failed_deletions.push(format!("{file_name}: {e}")); failed_deletions.push(format!("{file_name}: {e}"));
log::warn!(target: "app", "清理文件失败: {file_name} - {e}"); log::warn!(target: "app", "清理文件失败: {file_name} - {e}");
}
} }
} }
} }
@@ -659,44 +659,50 @@ impl IProfiles {
} }
// 对于主 profile 类型remote/local还需要收集其关联的扩展文件 // 对于主 profile 类型remote/local还需要收集其关联的扩展文件
if let Some(itype) = &item.itype if let Some(itype) = &item.itype {
&& (itype == "remote" || itype == "local") if itype == "remote" || itype == "local" {
&& let Some(option) = &item.option if let Some(option) = &item.option {
{ // 收集关联的扩展文件
// 收集关联的扩展文件 if let Some(merge_uid) = &option.merge {
if let Some(merge_uid) = &option.merge if let Ok(merge_item) = self.get_item(merge_uid) {
&& let Ok(merge_item) = self.get_item(merge_uid) if let Some(file) = &merge_item.file {
&& let Some(file) = &merge_item.file active_files.insert(file.clone());
{ }
active_files.insert(file.clone()); }
} }
if let Some(script_uid) = &option.script if let Some(script_uid) = &option.script {
&& let Ok(script_item) = self.get_item(script_uid) if let Ok(script_item) = self.get_item(script_uid) {
&& let Some(file) = &script_item.file if let Some(file) = &script_item.file {
{ active_files.insert(file.clone());
active_files.insert(file.clone()); }
} }
}
if let Some(rules_uid) = &option.rules if let Some(rules_uid) = &option.rules {
&& let Ok(rules_item) = self.get_item(rules_uid) if let Ok(rules_item) = self.get_item(rules_uid) {
&& let Some(file) = &rules_item.file if let Some(file) = &rules_item.file {
{ active_files.insert(file.clone());
active_files.insert(file.clone()); }
} }
}
if let Some(proxies_uid) = &option.proxies if let Some(proxies_uid) = &option.proxies {
&& let Ok(proxies_item) = self.get_item(proxies_uid) if let Ok(proxies_item) = self.get_item(proxies_uid) {
&& let Some(file) = &proxies_item.file if let Some(file) = &proxies_item.file {
{ active_files.insert(file.clone());
active_files.insert(file.clone()); }
} }
}
if let Some(groups_uid) = &option.groups if let Some(groups_uid) = &option.groups {
&& let Ok(groups_item) = self.get_item(groups_uid) if let Ok(groups_item) = self.get_item(groups_uid) {
&& let Some(file) = &groups_item.file if let Some(file) = &groups_item.file {
{ active_files.insert(file.clone());
active_files.insert(file.clone()); }
}
}
}
} }
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted}, config::{deserialize_encrypted, serialize_encrypted, DEFAULT_PAC},
logging, logging,
utils::{dirs, help, i18n, logging::Type}, utils::{dirs, help, i18n, logging::Type},
}; };

View File

@@ -2,7 +2,7 @@
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::time::{Duration, timeout}; use tokio::time::{timeout, Duration};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use anyhow::anyhow; use anyhow::anyhow;
@@ -87,7 +87,7 @@ impl AsyncProxyQuery {
use std::ptr; use std::ptr;
use winapi::shared::minwindef::{DWORD, HKEY}; use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ}; use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW}; use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER};
unsafe { unsafe {
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0" let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
@@ -209,13 +209,13 @@ impl AsyncProxyQuery {
// Linux: 检查环境变量和GNOME设置 // Linux: 检查环境变量和GNOME设置
// 首先检查环境变量 // 首先检查环境变量
if let Ok(auto_proxy) = std::env::var("auto_proxy") if let Ok(auto_proxy) = std::env::var("auto_proxy") {
&& !auto_proxy.is_empty() if !auto_proxy.is_empty() {
{ return Ok(AsyncAutoproxy {
return Ok(AsyncAutoproxy { enable: true,
enable: true, url: auto_proxy,
url: auto_proxy, });
}); }
} }
// 尝试使用 gsettings 获取 GNOME 代理设置 // 尝试使用 gsettings 获取 GNOME 代理设置
@@ -224,31 +224,31 @@ impl AsyncProxyQuery {
.output() .output()
.await; .await;
if let Ok(output) = output if let Ok(output) = output {
&& output.status.success() if output.status.success() {
{ let mode = String::from_utf8_lossy(&output.stdout).trim().to_string();
let mode = String::from_utf8_lossy(&output.stdout).trim().to_string(); if mode.contains("auto") {
if mode.contains("auto") { // 获取 PAC URL
// 获取 PAC URL let pac_output = Command::new("gsettings")
let pac_output = Command::new("gsettings") .args(["get", "org.gnome.system.proxy", "autoconfig-url"])
.args(["get", "org.gnome.system.proxy", "autoconfig-url"]) .output()
.output() .await;
.await;
if let Ok(pac_output) = pac_output if let Ok(pac_output) = pac_output {
&& pac_output.status.success() if pac_output.status.success() {
{ let pac_url = String::from_utf8_lossy(&pac_output.stdout)
let pac_url = String::from_utf8_lossy(&pac_output.stdout) .trim()
.trim() .trim_matches('\'')
.trim_matches('\'') .trim_matches('"')
.trim_matches('"') .to_string();
.to_string();
if !pac_url.is_empty() { if !pac_url.is_empty() {
return Ok(AsyncAutoproxy { return Ok(AsyncAutoproxy {
enable: true, enable: true,
url: pac_url, url: pac_url,
}); });
}
}
} }
} }
} }
@@ -271,7 +271,7 @@ impl AsyncProxyQuery {
use std::ptr; use std::ptr;
use winapi::shared::minwindef::{DWORD, HKEY}; use winapi::shared::minwindef::{DWORD, HKEY};
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ}; use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW}; use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER};
unsafe { unsafe {
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0" let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
@@ -402,10 +402,10 @@ impl AsyncProxyQuery {
http_host = host_part.trim().to_string(); http_host = host_part.trim().to_string();
} }
} else if line.contains("HTTPPort") { } else if line.contains("HTTPPort") {
if let Some(port_part) = line.split(':').nth(1) if let Some(port_part) = line.split(':').nth(1) {
&& let Ok(port) = port_part.trim().parse::<u16>() if let Ok(port) = port_part.trim().parse::<u16>() {
{ http_port = port;
http_port = port; }
} }
} else if line.contains("ExceptionsList") { } else if line.contains("ExceptionsList") {
// 解析异常列表 // 解析异常列表
@@ -431,16 +431,16 @@ impl AsyncProxyQuery {
// Linux: 检查环境变量和桌面环境设置 // Linux: 检查环境变量和桌面环境设置
// 首先检查环境变量 // 首先检查环境变量
if let Ok(http_proxy) = std::env::var("http_proxy") if let Ok(http_proxy) = std::env::var("http_proxy") {
&& let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy) if let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy) {
{ return Ok(proxy_info);
return Ok(proxy_info); }
} }
if let Ok(https_proxy) = std::env::var("https_proxy") if let Ok(https_proxy) = std::env::var("https_proxy") {
&& let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy) if let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy) {
{ return Ok(proxy_info);
return Ok(proxy_info); }
} }
// 尝试使用 gsettings 获取 GNOME 代理设置 // 尝试使用 gsettings 获取 GNOME 代理设置
@@ -449,46 +449,45 @@ impl AsyncProxyQuery {
.output() .output()
.await; .await;
if let Ok(mode_output) = mode_output if let Ok(mode_output) = mode_output {
&& mode_output.status.success() if mode_output.status.success() {
{ let mode = String::from_utf8_lossy(&mode_output.stdout)
let mode = String::from_utf8_lossy(&mode_output.stdout) .trim()
.trim() .to_string();
.to_string(); if mode.contains("manual") {
if mode.contains("manual") { // 获取HTTP代理设置
// 获取HTTP代理设置 let host_result = Command::new("gsettings")
let host_result = Command::new("gsettings") .args(["get", "org.gnome.system.proxy.http", "host"])
.args(["get", "org.gnome.system.proxy.http", "host"]) .output()
.output() .await;
.await;
let port_result = Command::new("gsettings") let port_result = Command::new("gsettings")
.args(["get", "org.gnome.system.proxy.http", "port"]) .args(["get", "org.gnome.system.proxy.http", "port"])
.output() .output()
.await; .await;
if let (Ok(host_output), Ok(port_output)) = (host_result, port_result) if let (Ok(host_output), Ok(port_output)) = (host_result, port_result) {
&& host_output.status.success() if host_output.status.success() && port_output.status.success() {
&& port_output.status.success() let host = String::from_utf8_lossy(&host_output.stdout)
{ .trim()
let host = String::from_utf8_lossy(&host_output.stdout) .trim_matches('\'')
.trim() .trim_matches('"')
.trim_matches('\'') .to_string();
.trim_matches('"')
.to_string();
let port = String::from_utf8_lossy(&port_output.stdout) let port = String::from_utf8_lossy(&port_output.stdout)
.trim() .trim()
.parse::<u16>() .parse::<u16>()
.unwrap_or(8080); .unwrap_or(8080);
if !host.is_empty() { if !host.is_empty() {
return Ok(AsyncSysproxy { return Ok(AsyncSysproxy {
enable: true, enable: true,
host, host,
port, port,
bypass: String::new(), bypass: String::new(),
}); });
}
}
} }
} }
} }

View File

@@ -19,12 +19,12 @@ use chrono::Local;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ use std::{
fmt, fmt,
fs::{File, create_dir_all}, fs::{create_dir_all, File},
io::Write, io::Write,
path::PathBuf, path::PathBuf,
sync::Arc, sync::Arc,
}; };
use tauri_plugin_shell::{ShellExt, process::CommandChild}; use tauri_plugin_shell::{process::CommandChild, ShellExt};
#[derive(Debug)] #[derive(Debug)]
pub struct CoreManager { pub struct CoreManager {
@@ -467,18 +467,18 @@ impl CoreManager {
Ok((pids, process_name)) => { Ok((pids, process_name)) => {
for pid in pids { for pid in pids {
// 跳过当前管理的进程 // 跳过当前管理的进程
if let Some(current) = current_pid if let Some(current) = current_pid {
&& pid == current if pid == current {
{ logging!(
logging!( debug,
debug, Type::Core,
Type::Core, true,
true, "跳过当前管理的进程: {} (PID: {})",
"跳过当前管理的进程: {} (PID: {})", process_name,
process_name, pid
pid );
); continue;
continue; }
} }
pids_to_kill.push((pid, process_name.clone())); pids_to_kill.push((pid, process_name.clone()));
} }
@@ -527,7 +527,7 @@ impl CoreManager {
use std::mem; use std::mem;
use winapi::um::handleapi::CloseHandle; use winapi::um::handleapi::CloseHandle;
use winapi::um::tlhelp32::{ use winapi::um::tlhelp32::{
CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW, CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
TH32CS_SNAPPROCESS, TH32CS_SNAPPROCESS,
}; };
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
@@ -703,7 +703,7 @@ impl CoreManager {
use winapi::um::processthreadsapi::OpenProcess; use winapi::um::processthreadsapi::OpenProcess;
use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION}; use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION};
AsyncHandler::spawn_blocking(move || -> Result<bool> { let result = AsyncHandler::spawn_blocking(move || -> Result<bool> {
unsafe { unsafe {
let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
if process_handle.is_null() { if process_handle.is_null() {
@@ -719,7 +719,9 @@ impl CoreManager {
Ok(exit_code == 259) Ok(exit_code == 259)
} }
}) })
.await? .await?;
result
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@@ -765,16 +767,16 @@ impl CoreManager {
AsyncHandler::spawn(move || async move { AsyncHandler::spawn(move || async move {
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event {
&& let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) {
{ logging!(
logging!( error,
error, Type::Core,
Type::Core, true,
true, "[Sidecar] Failed to write stdout to file: {}",
"[Sidecar] Failed to write stdout to file: {}", e
e );
); }
} }
} }
}); });

View File

@@ -1,8 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
use tokio::time::{Duration, sleep, timeout}; use tokio::time::{sleep, timeout, Duration};
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use crate::config::{Config, IVerge}; use crate::config::{Config, IVerge};
use crate::core::async_proxy_query::AsyncProxyQuery; use crate::core::async_proxy_query::AsyncProxyQuery;

View File

@@ -2,9 +2,8 @@ use crate::singleton;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{ use std::{
sync::{ sync::{
Arc,
atomic::{AtomicU64, Ordering}, atomic::{AtomicU64, Ordering},
mpsc, mpsc, Arc,
}, },
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
@@ -99,14 +98,16 @@ impl NotificationSystem {
let is_emergency = *system.emergency_mode.read(); let is_emergency = *system.emergency_mode.read();
if is_emergency if is_emergency {
&& let FrontendEvent::NoticeMessage { ref status, .. } = event if let FrontendEvent::NoticeMessage { ref status, .. } = event {
&& status == "info" { if status == "info" {
log::warn!( log::warn!(
"Emergency mode active, skipping info message" "Emergency mode active, skipping info message"
); );
continue; continue;
} }
}
}
if let Some(window) = handle.get_window() { if let Some(window) = handle.get_window() {
*system.last_emit_time.write() = Instant::now(); *system.last_emit_time.write() = Instant::now();
@@ -202,12 +203,13 @@ impl NotificationSystem {
/// 发送事件到队列 /// 发送事件到队列
fn send_event(&self, event: FrontendEvent) -> bool { fn send_event(&self, event: FrontendEvent) -> bool {
if *self.emergency_mode.read() if *self.emergency_mode.read() {
&& let FrontendEvent::NoticeMessage { ref status, .. } = event if let FrontendEvent::NoticeMessage { ref status, .. } = event {
&& status == "info" if status == "info" {
{ log::info!("Skipping info message in emergency mode");
log::info!("Skipping info message in emergency mode"); return false;
return false; }
}
} }
if let Some(sender) = &self.sender { if let Some(sender) = &self.sender {
@@ -390,9 +392,7 @@ impl Handle {
if let Some(system) = system_opt.as_ref() { if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateStarted { uid }); system.send_event(FrontendEvent::ProfileUpdateStarted { uid });
} else { } else {
log::warn!( log::warn!("Notification system not initialized when trying to send ProfileUpdateStarted event.");
"Notification system not initialized when trying to send ProfileUpdateStarted event."
);
} }
} }
@@ -406,9 +406,7 @@ impl Handle {
if let Some(system) = system_opt.as_ref() { if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::ProfileUpdateCompleted { uid }); system.send_event(FrontendEvent::ProfileUpdateCompleted { uid });
} else { } else {
log::warn!( log::warn!("Notification system not initialized when trying to send ProfileUpdateCompleted event.");
"Notification system not initialized when trying to send ProfileUpdateCompleted event."
);
} }
} }

View File

@@ -1,10 +1,10 @@
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::utils::notification::{NotificationEvent, notify_event}; use crate::utils::notification::{notify_event, NotificationEvent};
use crate::{ use crate::{
config::Config, core::handle, feat, logging, logging_error, config::Config, core::handle, feat, logging, logging_error,
module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type, module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type,
}; };
use anyhow::{Result, bail}; use anyhow::{bail, Result};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc}; use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
@@ -243,11 +243,11 @@ impl Hotkey {
); );
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned { if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
if let Some(window) = app_handle_cloned.get_webview_window("main") if let Some(window) = app_handle_cloned.get_webview_window("main") {
&& window.is_focused().unwrap_or(false) if window.is_focused().unwrap_or(false) {
{ logging!(debug, Type::Hotkey, "Executing quit function");
logging!(debug, Type::Hotkey, "Executing quit function"); Self::execute_function(function_owned, &app_handle_cloned);
Self::execute_function(function_owned, &app_handle_cloned); }
} }
} else { } else {
logging!(debug, Type::Hotkey, "Executing function directly"); logging!(debug, Type::Hotkey, "Executing function directly");

View File

@@ -1,10 +1,10 @@
use crate::{ use crate::{
config::Config, config::Config,
core::service_ipc::{IpcCommand, send_ipc_request}, core::service_ipc::{send_ipc_request, IpcCommand},
logging, logging,
utils::{dirs, logging::Type}, utils::{dirs, logging::Type},
}; };
use anyhow::{Context, Result, bail}; use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
env::current_exe, env::current_exe,
@@ -617,11 +617,17 @@ pub async fn check_service_version() -> Result<String> {
match response.data { match response.data {
Some(data) => { Some(data) => {
if let Some(nested_data) = data.get("data") { if let Some(nested_data) = data.get("data") {
if let Some(version) = nested_data.get("version") if let Some(version) = nested_data.get("version") {
&& let Some(version_str) = version.as_str() if let Some(version_str) = version.as_str() {
{ logging!(
logging!(info, Type::Service, true, "获取到服务版本: {}", version_str); info,
return Ok(version_str.to_string()); Type::Service,
true,
"获取到服务版本: {}",
version_str
);
return Ok(version_str.to_string());
}
} }
logging!( logging!(
error, error,
@@ -786,25 +792,25 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
} }
// 添加对嵌套JSON结构的处理 // 添加对嵌套JSON结构的处理
if let Some(data) = &response.data if let Some(data) = &response.data {
&& let Some(code) = data.get("code") if let Some(code) = data.get("code") {
{ let code_value = code.as_u64().unwrap_or(1);
let code_value = code.as_u64().unwrap_or(1); let msg = data
let msg = data .get("msg")
.get("msg") .and_then(|m| m.as_str())
.and_then(|m| m.as_str()) .unwrap_or("未知错误");
.unwrap_or("未知错误");
if code_value != 0 { if code_value != 0 {
logging!( logging!(
error, error,
Type::Service, Type::Service,
true, true,
"启动核心返回错误: code={}, msg={}", "启动核心返回错误: code={}, msg={}",
code_value, code_value,
msg msg
); );
bail!("启动核心失败: {}", msg); bail!("启动核心失败: {}", msg);
}
} }
} }
@@ -912,25 +918,25 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string())); bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
} }
if let Some(data) = &response.data if let Some(data) = &response.data {
&& let Some(code) = data.get("code") if let Some(code) = data.get("code") {
{ let code_value = code.as_u64().unwrap_or(1);
let code_value = code.as_u64().unwrap_or(1); let msg = data
let msg = data .get("msg")
.get("msg") .and_then(|m| m.as_str())
.and_then(|m| m.as_str()) .unwrap_or("未知错误");
.unwrap_or("未知错误");
if code_value != 0 { if code_value != 0 {
logging!( logging!(
error, error,
Type::Service, Type::Service,
true, true,
"停止核心返回错误: code={}, msg={}", "停止核心返回错误: code={}, msg={}",
code_value, code_value,
msg msg
); );
bail!("停止核心失败: {}", msg); bail!("停止核心失败: {}", msg);
}
} }
} }

View File

@@ -1,7 +1,7 @@
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::{logging, utils::logging::Type}; use crate::{logging, utils::logging::Type};
use anyhow::{Context, Result, bail}; use anyhow::{bail, Context, Result};
use hmac::{Hmac, Mac}; use hmac::{Hmac, Mac};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};

View File

@@ -2,7 +2,7 @@
use crate::utils::autostart as startup_shortcut; use crate::utils::autostart as startup_shortcut;
use crate::{ use crate::{
config::{Config, IVerge}, config::{Config, IVerge},
core::{EventDrivenProxyManager, handle::Handle}, core::{handle::Handle, EventDrivenProxyManager},
logging, logging_error, singleton_lazy, logging, logging_error, singleton_lazy,
utils::logging::Type, utils::logging::Type,
}; };
@@ -24,7 +24,8 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;
static DEFAULT_BYPASS: &str = static DEFAULT_BYPASS: &str =
"localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1"; "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1";
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
static DEFAULT_BYPASS: &str = "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,localhost,*.local,*.crashlytics.com,<local>"; static DEFAULT_BYPASS: &str =
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,localhost,*.local,*.crashlytics.com,<local>";
async fn get_bypass() -> String { async fn get_bypass() -> String {
let use_default = Config::verge() let use_default = Config::verge()

View File

@@ -6,8 +6,8 @@ use std::{
collections::HashMap, collections::HashMap,
pin::Pin, pin::Pin,
sync::{ sync::{
Arc,
atomic::{AtomicBool, AtomicU64, Ordering}, atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
}, },
}; };
@@ -242,18 +242,19 @@ impl Timer {
if let Some(items) = Config::profiles().await.latest_ref().get_items() { if let Some(items) = Config::profiles().await.latest_ref().get_items() {
for item in items.iter() { for item in items.iter() {
if let Some(option) = item.option.as_ref() if let Some(option) = item.option.as_ref() {
&& let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) if let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) {
&& interval > 0 if interval > 0 {
{ logging!(
logging!( debug,
debug, Type::Timer,
Type::Timer, "找到定时更新配置: uid={}, interval={}min",
"找到定时更新配置: uid={}, interval={}min", uid,
uid, interval
interval );
); new_map.insert(uid.clone(), interval);
new_map.insert(uid.clone(), interval); }
}
} }
} }
} }
@@ -389,8 +390,7 @@ impl Timer {
}; };
// Get the profile updated timestamp - now safe to await // Get the profile updated timestamp - now safe to await
let config_profiles = Config::profiles().await; let profiles = { Config::profiles().await.clone().data_ref() }.clone();
let profiles = config_profiles.data_ref().clone();
let items = match profiles.get_items() { let items = match profiles.get_items() {
Some(i) => i, Some(i) => i,
None => { None => {

View File

@@ -1,12 +1,12 @@
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use tauri::Emitter;
use tauri::tray::TrayIconBuilder; use tauri::tray::TrayIconBuilder;
use tauri::Emitter;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub mod speed_rate; pub mod speed_rate;
use crate::ipc::Rate; use crate::ipc::Rate;
use crate::process::AsyncHandler; use crate::process::AsyncHandler;
use crate::{ use crate::{
Type, cmd, cmd,
config::Config, config::Config,
feat, feat,
ipc::IpcManager, ipc::IpcManager,
@@ -14,6 +14,7 @@ use crate::{
module::lightweight::is_in_lightweight_mode, module::lightweight::is_in_lightweight_mode,
singleton_lazy, singleton_lazy,
utils::{dirs::find_target_icons, i18n::t}, utils::{dirs::find_target_icons, i18n::t},
Type,
}; };
use super::handle; use super::handle;
@@ -26,9 +27,9 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tauri::{ use tauri::{
AppHandle, Wry,
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu}, menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
tray::{MouseButton, MouseButtonState, TrayIconEvent}, tray::{MouseButton, MouseButtonState, TrayIconEvent},
AppHandle, Wry,
}; };
#[derive(Clone)] #[derive(Clone)]
@@ -73,11 +74,12 @@ impl TrayState {
pub async fn get_common_tray_icon() -> (bool, Vec<u8>) { pub async fn get_common_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_common_tray_icon = verge.common_tray_icon.unwrap_or(false); let is_common_tray_icon = verge.common_tray_icon.unwrap_or(false);
if is_common_tray_icon if is_common_tray_icon {
&& let Ok(Some(common_icon_path)) = find_target_icons("common") if let Ok(Some(common_icon_path)) = find_target_icons("common") {
&& let Ok(icon_data) = fs::read(common_icon_path) if let Ok(icon_data) = fs::read(common_icon_path) {
{ return (true, icon_data);
return (true, icon_data); }
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -107,11 +109,12 @@ impl TrayState {
pub async fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) { pub async fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.unwrap_or(false); let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.unwrap_or(false);
if is_sysproxy_tray_icon if is_sysproxy_tray_icon {
&& let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy") if let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy") {
&& let Ok(icon_data) = fs::read(sysproxy_icon_path) if let Ok(icon_data) = fs::read(sysproxy_icon_path) {
{ return (true, icon_data);
return (true, icon_data); }
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -141,11 +144,12 @@ impl TrayState {
pub async fn get_tun_tray_icon() -> (bool, Vec<u8>) { pub async fn get_tun_tray_icon() -> (bool, Vec<u8>) {
let verge = Config::verge().await.latest_ref().clone(); let verge = Config::verge().await.latest_ref().clone();
let is_tun_tray_icon = verge.tun_tray_icon.unwrap_or(false); let is_tun_tray_icon = verge.tun_tray_icon.unwrap_or(false);
if is_tun_tray_icon if is_tun_tray_icon {
&& let Ok(Some(tun_icon_path)) = find_target_icons("tun") if let Ok(Some(tun_icon_path)) = find_target_icons("tun") {
&& let Ok(icon_data) = fs::read(tun_icon_path) if let Ok(icon_data) = fs::read(tun_icon_path) {
{ return (true, icon_data);
return (true, icon_data); }
}
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
@@ -425,13 +429,13 @@ impl Tray {
{ {
let profiles = Config::profiles().await; let profiles = Config::profiles().await;
let profiles = profiles.latest_ref(); let profiles = profiles.latest_ref();
if let Some(current_profile_uid) = profiles.get_current() if let Some(current_profile_uid) = profiles.get_current() {
&& let Ok(profile) = profiles.get_item(&current_profile_uid) if let Ok(profile) = profiles.get_item(&current_profile_uid) {
{ current_profile_name = match &profile.name {
current_profile_name = match &profile.name { Some(profile_name) => profile_name.to_string(),
Some(profile_name) => profile_name.to_string(), None => current_profile_name,
None => current_profile_name, };
}; }
} }
} }

View File

@@ -1,7 +1,7 @@
#![cfg(target_os = "windows")] #![cfg(target_os = "windows")]
use crate::utils::dirs; use crate::utils::dirs;
use anyhow::{Result, bail}; use anyhow::{bail, Result};
use deelevate::{PrivilegeLevel, Token}; use deelevate::{PrivilegeLevel, Token};
use runas::Command as RunasCommand; use runas::Command as RunasCommand;
use std::process::Command as StdCommand; use std::process::Command as StdCommand;

View File

@@ -18,10 +18,12 @@ pub fn use_merge(merge: Mapping, config: Mapping) -> Mapping {
deep_merge(&mut config, &Value::from(merge)); deep_merge(&mut config, &Value::from(merge));
config.as_mapping().cloned().unwrap_or_else(|| { let config = config.as_mapping().cloned().unwrap_or_else(|| {
log::error!("Failed to convert merged config to mapping, using empty mapping"); log::error!("Failed to convert merged config to mapping, using empty mapping");
Mapping::new() Mapping::new()
}) });
config
} }
#[test] #[test]

View File

@@ -384,26 +384,29 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
if let Ok(app_dir) = dirs::app_home_dir() { if let Ok(app_dir) = dirs::app_home_dir() {
let dns_path = app_dir.join("dns_config.yaml"); let dns_path = app_dir.join("dns_config.yaml");
if dns_path.exists() if dns_path.exists() {
&& let Ok(dns_yaml) = fs::read_to_string(&dns_path) if let Ok(dns_yaml) = fs::read_to_string(&dns_path) {
&& let Ok(dns_config) = serde_yaml_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml) if let Ok(dns_config) =
{ serde_yaml_ng::from_str::<serde_yaml_ng::Mapping>(&dns_yaml)
// 处理hosts配置 {
if let Some(hosts_value) = dns_config.get("hosts") // 处理hosts配置
&& hosts_value.is_mapping() if let Some(hosts_value) = dns_config.get("hosts") {
{ if hosts_value.is_mapping() {
config.insert("hosts".into(), hosts_value.clone()); config.insert("hosts".into(), hosts_value.clone());
log::info!(target: "app", "apply hosts configuration"); log::info!(target: "app", "apply hosts configuration");
} }
}
if let Some(dns_value) = dns_config.get("dns") { if let Some(dns_value) = dns_config.get("dns") {
if let Some(dns_mapping) = dns_value.as_mapping() { if let Some(dns_mapping) = dns_value.as_mapping() {
config.insert("dns".into(), dns_mapping.clone().into()); config.insert("dns".into(), dns_mapping.clone().into());
log::info!(target: "app", "apply dns_config.yaml (dns section)"); log::info!(target: "app", "apply dns_config.yaml (dns section)");
}
} else {
config.insert("dns".into(), dns_config.into());
log::info!(target: "app", "apply dns_config.yaml");
}
} }
} else {
config.insert("dns".into(), dns_config.into());
log::info!(target: "app", "apply dns_config.yaml");
} }
} }
} }

View File

@@ -7,7 +7,7 @@ pub fn use_script(
config: Mapping, config: Mapping,
name: String, name: String,
) -> Result<(Mapping, Vec<(String, String)>)> { ) -> Result<(Mapping, Vec<(String, String)>)> {
use boa_engine::{Context, JsString, JsValue, Source, native_function::NativeFunction}; use boa_engine::{native_function::NativeFunction, Context, JsString, JsValue, Source};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
let mut context = Context::default(); let mut context = Context::default();

View File

@@ -44,39 +44,39 @@ pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping {
config.insert(Value::String(field.into()), Value::Sequence(new_seq)); config.insert(Value::String(field.into()), Value::Sequence(new_seq));
// If this is proxies field, we also need to filter proxy-groups // If this is proxies field, we also need to filter proxy-groups
if field == "proxies" if field == "proxies" {
&& let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups") if let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups") {
{ let mut new_groups = Sequence::new();
let mut new_groups = Sequence::new(); for group in groups {
for group in groups { if let Value::Mapping(group_map) = group {
if let Value::Mapping(group_map) = group { let mut new_group = group_map.clone();
let mut new_group = group_map.clone(); if let Some(Value::Sequence(proxies)) = group_map.get("proxies") {
if let Some(Value::Sequence(proxies)) = group_map.get("proxies") { let filtered_proxies: Sequence = proxies
let filtered_proxies: Sequence = proxies .iter()
.iter() .filter(|p| {
.filter(|p| { if let Value::String(name) = p {
if let Value::String(name) = p { !delete.contains(name)
!delete.contains(name) } else {
} else { true
true }
} })
}) .cloned()
.cloned() .collect();
.collect(); new_group.insert(
new_group.insert( Value::String("proxies".into()),
Value::String("proxies".into()), Value::Sequence(filtered_proxies),
Value::Sequence(filtered_proxies), );
); }
new_groups.push(Value::Mapping(new_group));
} else {
new_groups.push(group.clone());
} }
new_groups.push(Value::Mapping(new_group));
} else {
new_groups.push(group.clone());
} }
config.insert(
Value::String("proxy-groups".into()),
Value::Sequence(new_groups),
);
} }
config.insert(
Value::String("proxy-groups".into()),
Value::Sequence(new_groups),
);
} }
config config

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
config::Config, config::Config,
core::{CoreManager, handle, tray}, core::{handle, tray, CoreManager},
ipc::IpcManager, ipc::IpcManager,
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
config::{Config, IVerge}, config::{Config, IVerge},
core::{CoreManager, handle, hotkey, sysopt, tray}, core::{handle, hotkey, sysopt, tray, CoreManager},
logging_error, logging_error,
module::lightweight, module::lightweight,
utils::logging::Type, utils::logging::Type,
@@ -202,10 +202,10 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
if (update_flags & (UpdateFlags::SysProxy as i32)) != 0 { if (update_flags & (UpdateFlags::SysProxy as i32)) != 0 {
sysopt::Sysopt::global().update_sysproxy().await?; sysopt::Sysopt::global().update_sysproxy().await?;
} }
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 {
&& let Some(hotkeys) = patch.hotkeys if let Some(hotkeys) = patch.hotkeys {
{ hotkey::Hotkey::global().update(hotkeys).await?;
hotkey::Hotkey::global().update(hotkeys).await?; }
} }
if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 { if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 {
tray::Tray::global().update_menu().await?; tray::Tray::global().update_menu().await?;

View File

@@ -1,11 +1,11 @@
use crate::{ use crate::{
cmd, cmd,
config::{Config, PrfItem, PrfOption, profiles::profiles_draft_update_item_safe}, config::{profiles::profiles_draft_update_item_safe, Config, PrfItem, PrfOption},
core::{CoreManager, handle, tray}, core::{handle, tray, CoreManager},
logging, logging,
utils::logging::Type, utils::logging::Type,
}; };
use anyhow::{Result, bail}; use anyhow::{bail, Result};
/// Toggle proxy profile /// Toggle proxy profile
pub async fn toggle_proxy_profile(profile_index: String) { pub async fn toggle_proxy_profile(profile_index: String) {

View File

@@ -13,22 +13,21 @@ pub async fn toggle_system_proxy() {
// 获取当前系统代理状态 // 获取当前系统代理状态
let enable = { let enable = {
let verge = Config::verge().await; let verge = Config::verge().await;
let enable = verge.latest_ref().enable_system_proxy.unwrap_or(false);
verge.latest_ref().enable_system_proxy.unwrap_or(false) enable
}; };
// 获取自动关闭连接设置 // 获取自动关闭连接设置
let auto_close_connection = { let auto_close_connection = {
let verge = Config::verge().await; let verge = Config::verge().await;
let auto_close = verge.latest_ref().auto_close_connection.unwrap_or(false);
verge.latest_ref().auto_close_connection.unwrap_or(false) auto_close
}; };
// 如果当前系统代理即将关闭且自动关闭连接设置为true则关闭所有连接 // 如果当前系统代理即将关闭且自动关闭连接设置为true则关闭所有连接
if enable if enable && auto_close_connection {
&& auto_close_connection if let Err(err) = IpcManager::global().close_all_connections().await {
&& let Err(err) = IpcManager::global().close_all_connections().await log::error!(target: "app", "Failed to close all connections: {err}");
{ }
log::error!(target: "app", "Failed to close all connections: {err}");
} }
let patch_result = super::patch_verge( let patch_result = super::patch_verge(

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
config::Config, config::Config,
core::{CoreManager, handle, sysopt}, core::{handle, sysopt, CoreManager},
ipc::IpcManager, ipc::IpcManager,
logging, logging,
utils::logging::Type, utils::logging::Type,
@@ -92,7 +92,7 @@ pub async fn quit() {
} }
async fn clean_async() -> bool { async fn clean_async() -> bool {
use tokio::time::{Duration, timeout}; use tokio::time::{timeout, Duration};
logging!(info, Type::System, true, "开始执行异步清理操作..."); logging!(info, Type::System, true, "开始执行异步清理操作...");
@@ -252,10 +252,10 @@ pub async fn hide() {
add_light_weight_timer().await; add_light_weight_timer().await;
} }
if let Some(window) = handle::Handle::global().get_window() if let Some(window) = handle::Handle::global().get_window() {
&& window.is_visible().unwrap_or(false) if window.is_visible().unwrap_or(false) {
{ let _ = window.hide();
let _ = window.hide(); }
} }
handle::Handle::global().set_activation_policy_accessory(); handle::Handle::global().set_activation_policy_accessory();
} }

View File

@@ -1,10 +1,10 @@
use std::time::Duration; use std::time::Duration;
use kode_bridge::{ use kode_bridge::{
ClientConfig, IpcHttpClient, LegacyResponse,
errors::{AnyError, AnyResult}, errors::{AnyError, AnyResult},
ClientConfig, IpcHttpClient, LegacyResponse,
}; };
use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use crate::{ use crate::{
logging, singleton_with_logging, logging, singleton_with_logging,
@@ -199,7 +199,8 @@ impl IpcManager {
// 测速URL不再编码直接传递 // 测速URL不再编码直接传递
let url = format!("/proxies/{encoded_name}/delay?url={test_url}&timeout={timeout}"); let url = format!("/proxies/{encoded_name}/delay?url={test_url}&timeout={timeout}");
self.send_request("GET", &url, None).await let response = self.send_request("GET", &url, None).await;
response
} }
// 版本和配置相关 // 版本和配置相关
@@ -339,7 +340,8 @@ impl IpcManager {
// 测速URL不再编码直接传递 // 测速URL不再编码直接传递
let url = format!("/group/{encoded_group_name}/delay?url={test_url}&timeout={timeout}"); let url = format!("/group/{encoded_group_name}/delay?url={test_url}&timeout={timeout}");
self.send_request("GET", &url, None).await let response = self.send_request("GET", &url, None).await;
response
} }
// 调试相关 // 调试相关

View File

@@ -26,7 +26,7 @@ use tauri::Manager;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_deep_link::DeepLinkExt; use tauri_plugin_deep_link::DeepLinkExt;
use tokio::time::{Duration, timeout}; use tokio::time::{timeout, Duration};
use utils::logging::Type; use utils::logging::Type;
/// Application initialization helper functions /// Application initialization helper functions
@@ -134,8 +134,8 @@ mod app_init {
} }
/// Generate all command handlers for the application /// Generate all command handlers for the application
pub fn generate_handlers() pub fn generate_handlers(
-> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static { ) -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
tauri::generate_handler![ tauri::generate_handler![
// Common commands // Common commands
cmd::get_sys_proxy, cmd::get_sys_proxy,
@@ -275,9 +275,7 @@ pub fn run() {
// Set Linux environment variable // Set Linux environment variable
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
unsafe { std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
}
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP") let desktop_env = std::env::var("XDG_CURRENT_DESKTOP")
.unwrap_or_default() .unwrap_or_default()
@@ -286,9 +284,7 @@ pub fn run() {
let is_plasma_desktop = desktop_env.contains("PLASMA"); let is_plasma_desktop = desktop_env.contains("PLASMA");
if is_kde_desktop || is_plasma_desktop { if is_kde_desktop || is_plasma_desktop {
unsafe { std::env::set_var("GTK_CSD", "0");
std::env::set_var("GTK_CSD", "0");
}
logging!( logging!(
info, info,
Type::Setup, Type::Setup,
@@ -442,10 +438,10 @@ pub fn run() {
} }
} }
if !is_enable_global_hotkey if !is_enable_global_hotkey {
&& let Err(e) = hotkey::Hotkey::global().init().await if let Err(e) = hotkey::Hotkey::global().init().await {
{ logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e);
logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e); }
} }
return; return;
} }
@@ -478,8 +474,10 @@ pub fn run() {
} }
} }
if !is_enable_global_hotkey && let Err(e) = hotkey::Hotkey::global().reset() { if !is_enable_global_hotkey {
logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e); if let Err(e) = hotkey::Hotkey::global().reset() {
logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e);
}
} }
}); });
} }

View File

@@ -7,7 +7,6 @@ use crate::{
utils::{logging::Type, window_manager::WindowManager}, utils::{logging::Type, window_manager::WindowManager},
}; };
#[cfg(target_os = "macos")]
use crate::logging_error; use crate::logging_error;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
@@ -137,13 +136,13 @@ pub async fn entry_lightweight_mode() {
result result
); );
if let Some(window) = handle::Handle::global().get_window() if let Some(window) = handle::Handle::global().get_window() {
&& let Some(webview) = window.get_webview_window("main") if let Some(webview) = window.get_webview_window("main") {
{ let _ = webview.destroy();
let _ = webview.destroy(); }
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_accessory();
} }
#[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_accessory();
set_lightweight_mode(true).await; set_lightweight_mode(true).await;
let _ = cancel_light_weight_timer(); let _ = cancel_light_weight_timer();
ProxyRequestCache::global().clean_default_keys(); ProxyRequestCache::global().clean_default_keys();

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
cmd::system, cmd::system,
core::{CoreManager, handle}, core::{handle, CoreManager},
}; };
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use sysinfo::System; use sysinfo::System;
@@ -20,13 +20,7 @@ impl Debug for PlatformSpecification {
write!( write!(
f, f,
"System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}\nIs Admin: {}", "System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}\nIs Admin: {}",
self.system_name, self.system_name, self.system_version, self.system_kernel_version, self.system_arch, self.verge_version, self.running_mode, self.is_admin
self.system_version,
self.system_kernel_version,
self.system_arch,
self.verge_version,
self.running_mode,
self.is_admin
) )
} }
} }

View File

@@ -67,18 +67,12 @@ impl AsyncHandler {
location.column() location.column()
); );
println!( println!("┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐");
"┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"
);
println!("{:<18}{:<80}", "Field", "Value"); println!("{:<18}{:<80}", "Field", "Value");
println!( println!("├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤");
"├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"
);
println!("{:<18}{:<80}", "Type of task", type_str); println!("{:<18}{:<80}", "Type of task", type_str);
println!("{:<18}{:<80}", "Size of task", size_str); println!("{:<18}{:<80}", "Size of task", size_str);
println!("{:<18}{:<80}", "Called from", loc_str); println!("{:<18}{:<80}", "Called from", loc_str);
println!( println!("└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘");
"└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"
);
} }
} }

View File

@@ -1,5 +1,5 @@
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use anyhow::{Result, anyhow}; use anyhow::{anyhow, Result};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use log::info; use log::info;

View File

@@ -151,11 +151,12 @@ pub fn find_target_icons(target: &str) -> Result<Option<String>> {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
&& file_name.starts_with(target) if file_name.starts_with(target)
&& (file_name.ends_with(".ico") || file_name.ends_with(".png")) && (file_name.ends_with(".ico") || file_name.ends_with(".png"))
{ {
matching_files.push(path); matching_files.push(path);
}
} }
} }

View File

@@ -1,7 +1,7 @@
use crate::{enhance::seq::SeqMap, logging, utils::logging::Type}; use crate::{enhance::seq::SeqMap, logging, utils::logging::Type};
use anyhow::{Context, Result, anyhow, bail}; use anyhow::{anyhow, bail, Context, Result};
use nanoid::nanoid; use nanoid::nanoid;
use serde::{Serialize, de::DeserializeOwned}; use serde::{de::DeserializeOwned, Serialize};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
use std::{path::PathBuf, str::FromStr}; use std::{path::PathBuf, str::FromStr};
@@ -154,6 +154,10 @@ macro_rules! ret_err {
#[macro_export] #[macro_export]
macro_rules! t { macro_rules! t {
($en:expr, $zh:expr, $use_zh:expr) => { ($en:expr, $zh:expr, $use_zh:expr) => {
if $use_zh { $zh } else { $en } if $use_zh {
$zh
} else {
$en
}
}; };
} }

View File

@@ -15,14 +15,14 @@ fn get_locales_dir() -> Option<PathBuf> {
pub fn get_supported_languages() -> Vec<String> { pub fn get_supported_languages() -> Vec<String> {
let mut languages = Vec::new(); let mut languages = Vec::new();
if let Some(locales_dir) = get_locales_dir() if let Some(locales_dir) = get_locales_dir() {
&& let Ok(entries) = fs::read_dir(locales_dir) if let Ok(entries) = fs::read_dir(locales_dir) {
{ for entry in entries.flatten() {
for entry in entries.flatten() { if let Some(file_name) = entry.file_name().to_str() {
if let Some(file_name) = entry.file_name().to_str() if let Some(lang) = file_name.strip_suffix(".json") {
&& let Some(lang) = file_name.strip_suffix(".json") languages.push(lang.to_string());
{ }
languages.push(lang.to_string()); }
} }
} }
} }
@@ -39,10 +39,10 @@ static TRANSLATIONS: Lazy<HashMap<String, Value>> = Lazy::new(|| {
if let Some(locales_dir) = get_locales_dir() { if let Some(locales_dir) = get_locales_dir() {
for lang in get_supported_languages() { for lang in get_supported_languages() {
let file_path = locales_dir.join(format!("{lang}.json")); let file_path = locales_dir.join(format!("{lang}.json"));
if let Ok(content) = fs::read_to_string(file_path) if let Ok(content) = fs::read_to_string(file_path) {
&& let Ok(json) = serde_json::from_str(&content) if let Ok(json) = serde_json::from_str(&content) {
{ translations.insert(lang.to_string(), json);
translations.insert(lang.to_string(), json); }
} }
} }
} }
@@ -76,13 +76,14 @@ pub async fn t(key: &str) -> String {
return text.to_string(); return text.to_string();
} }
if current_lang != DEFAULT_LANGUAGE if current_lang != DEFAULT_LANGUAGE {
&& let Some(text) = TRANSLATIONS if let Some(text) = TRANSLATIONS
.get(DEFAULT_LANGUAGE) .get(DEFAULT_LANGUAGE)
.and_then(|trans| trans.get(&key)) .and_then(|trans| trans.get(&key))
.and_then(|val| val.as_str()) .and_then(|val| val.as_str())
{ {
return text.to_string(); return text.to_string();
}
} }
key key

View File

@@ -296,52 +296,52 @@ async fn ensure_directories() -> Result<()> {
/// 初始化配置文件 /// 初始化配置文件
async fn initialize_config_files() -> Result<()> { async fn initialize_config_files() -> Result<()> {
if let Ok(path) = dirs::clash_path() if let Ok(path) = dirs::clash_path() {
&& !path.exists() if !path.exists() {
{ let template = IClashTemp::template().0;
let template = IClashTemp::template().0; help::save_yaml(&path, &template, Some("# Clash Verge"))
help::save_yaml(&path, &template, Some("# Clash Verge")) .await
.await .map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?;
.map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?; logging!(
logging!( info,
info, Type::Setup,
Type::Setup, true,
true, "Created clash config at {:?}",
"Created clash config at {:?}", path
path );
); }
} }
if let Ok(path) = dirs::verge_path() if let Ok(path) = dirs::verge_path() {
&& !path.exists() if !path.exists() {
{ let template = IVerge::template();
let template = IVerge::template(); help::save_yaml(&path, &template, Some("# Clash Verge"))
help::save_yaml(&path, &template, Some("# Clash Verge")) .await
.await .map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?;
.map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?; logging!(
logging!( info,
info, Type::Setup,
Type::Setup, true,
true, "Created verge config at {:?}",
"Created verge config at {:?}", path
path );
); }
} }
if let Ok(path) = dirs::profiles_path() if let Ok(path) = dirs::profiles_path() {
&& !path.exists() if !path.exists() {
{ let template = IProfiles::template();
let template = IProfiles::template(); help::save_yaml(&path, &template, Some("# Clash Verge"))
help::save_yaml(&path, &template, Some("# Clash Verge")) .await
.await .map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?; logging!(
logging!( info,
info, Type::Setup,
Type::Setup, true,
true, "Created profiles config at {:?}",
"Created profiles config at {:?}", path
path );
); }
} }
// 验证并修正verge配置 // 验证并修正verge配置
@@ -459,7 +459,7 @@ pub async fn init_resources() -> Result<()> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub fn init_scheme() -> Result<()> { pub fn init_scheme() -> Result<()> {
use tauri::utils::platform::current_exe; use tauri::utils::platform::current_exe;
use winreg::{RegKey, enums::*}; use winreg::{enums::*, RegKey};
let app_exe = current_exe()?; let app_exe = current_exe()?;
let app_exe = dunce::canonicalize(app_exe)?; let app_exe = dunce::canonicalize(app_exe)?;

View File

@@ -1,14 +1,14 @@
use anyhow::Result; use anyhow::Result;
use base64::{Engine as _, engine::general_purpose}; use base64::{engine::general_purpose, Engine as _};
use isahc::prelude::*; use isahc::prelude::*;
use isahc::{HttpClient, config::SslOption};
use isahc::{ use isahc::{
config::RedirectPolicy, config::RedirectPolicy,
http::{ http::{
StatusCode, Uri,
header::{HeaderMap, HeaderValue, USER_AGENT}, header::{HeaderMap, HeaderValue, USER_AGENT},
StatusCode, Uri,
}, },
}; };
use isahc::{config::SslOption, HttpClient};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use sysproxy::Sysproxy; use sysproxy::Sysproxy;
use tauri::Url; use tauri::Url;
@@ -88,11 +88,10 @@ impl NetworkManager {
return true; return true;
} }
if let Some((time, _)) = &*last_error_guard if let Some((time, _)) = &*last_error_guard {
&& time.elapsed() < Duration::from_secs(30) if time.elapsed() < Duration::from_secs(30) && count > 2 {
&& count > 2 return true;
{ }
return true;
} }
false false
@@ -114,8 +113,7 @@ impl NetworkManager {
) -> Result<HttpClient> { ) -> Result<HttpClient> {
let proxy_uri_clone = proxy_uri.clone(); let proxy_uri_clone = proxy_uri.clone();
let headers_clone = default_headers.clone(); let headers_clone = default_headers.clone();
let client = {
{
let mut builder = HttpClient::builder(); let mut builder = HttpClient::builder();
builder = match proxy_uri_clone { builder = match proxy_uri_clone {
@@ -138,7 +136,9 @@ impl NetworkManager {
builder = builder.redirect_policy(RedirectPolicy::Follow); builder = builder.redirect_policy(RedirectPolicy::Follow);
Ok(builder.build()?) Ok(builder.build()?)
} };
client
} }
pub async fn create_request( pub async fn create_request(
@@ -200,15 +200,15 @@ impl NetworkManager {
let parsed = Url::parse(url)?; let parsed = Url::parse(url)?;
let mut extra_headers = HeaderMap::new(); let mut extra_headers = HeaderMap::new();
if !parsed.username().is_empty() if !parsed.username().is_empty() {
&& let Some(pass) = parsed.password() if let Some(pass) = parsed.password() {
{ let auth_str = format!("{}:{}", parsed.username(), pass);
let auth_str = format!("{}:{}", parsed.username(), pass); let encoded = general_purpose::STANDARD.encode(auth_str);
let encoded = general_purpose::STANDARD.encode(auth_str); extra_headers.insert(
extra_headers.insert( "Authorization",
"Authorization", HeaderValue::from_str(&format!("Basic {}", encoded))?,
HeaderValue::from_str(&format!("Basic {}", encoded))?, );
); }
} }
let clean_url = { let clean_url = {

View File

@@ -3,7 +3,7 @@ use tauri::AppHandle;
use crate::{ use crate::{
config::Config, config::Config,
core::{CoreManager, Timer, handle, hotkey::Hotkey, sysopt, tray::Tray}, core::{handle, hotkey::Hotkey, sysopt, tray::Tray, CoreManager, Timer},
logging, logging_error, logging, logging_error,
module::lightweight::auto_lightweight_mode_init, module::lightweight::auto_lightweight_mode_init,
process::AsyncHandler, process::AsyncHandler,

View File

@@ -1,4 +1,4 @@
use anyhow::{Result, bail}; use anyhow::{bail, Result};
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use tauri::Url; use tauri::Url;

View File

@@ -1,8 +1,8 @@
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::sync::{ use std::sync::{
Arc,
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc,
}; };
use tokio::sync::Notify; use tokio::sync::Notify;

View File

@@ -12,7 +12,7 @@ use crate::{
utils::{ utils::{
logging::Type, logging::Type,
resolve::{ resolve::{
ui::{UiReadyStage, get_ui_ready, update_ui_ready_stage, wait_for_ui_ready}, ui::{get_ui_ready, update_ui_ready_stage, wait_for_ui_ready, UiReadyStage},
window_script::{INITIAL_LOADING_OVERLAY, WINDOW_INITIAL_SCRIPT}, window_script::{INITIAL_LOADING_OVERLAY, WINDOW_INITIAL_SCRIPT},
}, },
}, },
@@ -34,22 +34,22 @@ fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
/// 检查是否已存在窗口,如果存在则显示并返回 true /// 检查是否已存在窗口,如果存在则显示并返回 true
fn check_existing_window(is_show: bool) -> Option<bool> { fn check_existing_window(is_show: bool) -> Option<bool> {
if let Some(app_handle) = handle::Handle::global().app_handle() if let Some(app_handle) = handle::Handle::global().app_handle() {
&& let Some(window) = app_handle.get_webview_window("main") if let Some(window) = app_handle.get_webview_window("main") {
{ logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口"); if is_show {
if is_show { if window.is_minimized().unwrap_or(false) {
if window.is_minimized().unwrap_or(false) { logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化");
logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化"); let _ = window.unminimize();
let _ = window.unminimize(); }
} let _ = window.show();
let _ = window.show(); let _ = window.set_focus();
let _ = window.set_focus();
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
handle::Handle::global().set_activation_policy_regular(); handle::Handle::global().set_activation_policy_regular();
}
return Some(true);
} }
return Some(true);
} }
None None
} }

View File

@@ -1,11 +1,11 @@
use super::resolve; use super::resolve;
use crate::{ use crate::{
config::{Config, DEFAULT_PAC, IVerge}, config::{Config, IVerge, DEFAULT_PAC},
logging_error, logging_error,
process::AsyncHandler, process::AsyncHandler,
utils::logging::Type, utils::logging::Type,
}; };
use anyhow::{Result, bail}; use anyhow::{bail, Result};
use port_scanner::local_port_available; use port_scanner::local_port_available;
use warp::Filter; use warp::Filter;