mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-28 07:14:40 +08:00
feat: update Cargo.toml for 2024 edition and optimize release profiles (#4681)
* feat: update Cargo.toml for 2024 edition and optimize release profiles * feat: refactor environment variable settings for Linux and improve code organization * Refactor conditional statements to use `&&` for improved readability - Updated multiple files to combine nested `if let` statements using `&&` for better clarity and conciseness. - This change enhances the readability of the code by reducing indentation levels and making the conditions more straightforward. - Affected files include: media_unlock_checker.rs, profile.rs, clash.rs, profiles.rs, async_proxy_query.rs, core.rs, handle.rs, hotkey.rs, service.rs, timer.rs, tray/mod.rs, merge.rs, seq.rs, config.rs, proxy.rs, window.rs, general.rs, dirs.rs, i18n.rs, init.rs, network.rs, and window.rs in the resolve module. * refactor: streamline conditional checks using `&&` for improved readability
This commit is contained in:
@@ -6,7 +6,7 @@ authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
repository = "https://github.com/clash-verge-rev/clash-verge-rev.git"
|
||||
default-run = "clash-verge"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
[package.metadata.bundle]
|
||||
@@ -117,27 +117,33 @@ verge-dev = []
|
||||
tokio-trace = ["console-subscriber"]
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
codegen-units = 1
|
||||
panic = "unwind"
|
||||
codegen-units = 16
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
opt-level = 3
|
||||
debug = false
|
||||
strip = "none"
|
||||
overflow-checks = false
|
||||
rpath = false
|
||||
|
||||
[profile.dev]
|
||||
incremental = true
|
||||
codegen-units = 256 # 增加编译单元,提升编译速度
|
||||
opt-level = 0 # 禁用优化,进一步提升编译速度
|
||||
debug = true # 保留调试信息
|
||||
strip = false # 不剥离符号,保留调试信息
|
||||
codegen-units = 64
|
||||
opt-level = 0
|
||||
debug = true
|
||||
strip = "none"
|
||||
overflow-checks = true
|
||||
lto = false
|
||||
rpath = false
|
||||
|
||||
[profile.fast-release]
|
||||
inherits = "release" # 继承 release 的配置
|
||||
panic = "abort" # 与 release 相同
|
||||
codegen-units = 256 # 增加编译单元,提升编译速度
|
||||
lto = false # 禁用 LTO,提升编译速度
|
||||
opt-level = 0 # 禁用优化,大幅提升编译速度
|
||||
debug = true # 保留调试信息
|
||||
strip = false # 不剥离符号,保留调试信息
|
||||
inherits = "release"
|
||||
panic = "abort"
|
||||
codegen-units = 64
|
||||
lto = false
|
||||
opt-level = 0
|
||||
debug = true
|
||||
strip = false
|
||||
|
||||
[lib]
|
||||
name = "app_lib"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use std::hint::black_box;
|
||||
|
||||
// 业务模型 & Draft
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, CoreManager},
|
||||
core::{CoreManager, handle},
|
||||
};
|
||||
use crate::{
|
||||
config::*,
|
||||
@@ -166,7 +166,7 @@ pub async fn save_dns_config(dns_config: Mapping) -> CmdResult {
|
||||
pub async fn apply_dns_config(apply: bool) -> CmdResult {
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, CoreManager},
|
||||
core::{CoreManager, handle},
|
||||
utils::dirs,
|
||||
};
|
||||
|
||||
|
||||
@@ -618,20 +618,20 @@ async fn check_netflix(client: &Client) -> UnlockItem {
|
||||
{
|
||||
Ok(response) => {
|
||||
// 检查重定向位置
|
||||
if let Some(location) = response.headers().get("location") {
|
||||
if let Ok(location_str) = location.to_str() {
|
||||
// 解析位置获取区域
|
||||
let parts: Vec<&str> = location_str.split('/').collect();
|
||||
if parts.len() >= 4 {
|
||||
let region_code = parts[3].split('-').next().unwrap_or("unknown");
|
||||
let emoji = country_code_to_emoji(region_code);
|
||||
return UnlockItem {
|
||||
name: "Netflix".to_string(),
|
||||
status: "Yes".to_string(),
|
||||
region: Some(format!("{emoji}{region_code}")),
|
||||
check_time: Some(get_local_date_string()),
|
||||
};
|
||||
}
|
||||
if let Some(location) = response.headers().get("location")
|
||||
&& let Ok(location_str) = location.to_str()
|
||||
{
|
||||
// 解析位置获取区域
|
||||
let parts: Vec<&str> = location_str.split('/').collect();
|
||||
if parts.len() >= 4 {
|
||||
let region_code = parts[3].split('-').next().unwrap_or("unknown");
|
||||
let emoji = country_code_to_emoji(region_code);
|
||||
return UnlockItem {
|
||||
name: "Netflix".to_string(),
|
||||
status: "Yes".to_string(),
|
||||
region: Some(format!("{emoji}{region_code}")),
|
||||
check_time: Some(get_local_date_string()),
|
||||
};
|
||||
}
|
||||
}
|
||||
// 如果没有重定向,假设是美国
|
||||
@@ -691,22 +691,18 @@ async fn check_netflix_cdn(client: &Client) -> UnlockItem {
|
||||
match response.json::<serde_json::Value>().await {
|
||||
Ok(data) => {
|
||||
// 尝试从数据中提取区域信息
|
||||
if let Some(targets) = data.get("targets").and_then(|t| t.as_array()) {
|
||||
if !targets.is_empty() {
|
||||
if let Some(location) = targets[0].get("location") {
|
||||
if let Some(country) =
|
||||
location.get("country").and_then(|c| c.as_str())
|
||||
{
|
||||
let emoji = country_code_to_emoji(country);
|
||||
return UnlockItem {
|
||||
name: "Netflix".to_string(),
|
||||
status: "Yes".to_string(),
|
||||
region: Some(format!("{emoji}{country}")),
|
||||
check_time: Some(get_local_date_string()),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(targets) = data.get("targets").and_then(|t| t.as_array())
|
||||
&& !targets.is_empty()
|
||||
&& let Some(location) = targets[0].get("location")
|
||||
&& let Some(country) = location.get("country").and_then(|c| c.as_str())
|
||||
{
|
||||
let emoji = country_code_to_emoji(country);
|
||||
return UnlockItem {
|
||||
name: "Netflix".to_string(),
|
||||
status: "Yes".to_string(),
|
||||
region: Some(format!("{emoji}{country}")),
|
||||
check_time: Some(get_local_date_string()),
|
||||
};
|
||||
}
|
||||
|
||||
// 如果无法解析区域信息
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::CmdResult;
|
||||
use crate::core::{async_proxy_query::AsyncProxyQuery, EventDrivenProxyManager};
|
||||
use crate::core::{EventDrivenProxyManager, async_proxy_query::AsyncProxyQuery};
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::wrap_err;
|
||||
use network_interface::NetworkInterface;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
config::{
|
||||
Config, IProfiles, PrfItem, PrfOption,
|
||||
profiles::{
|
||||
profiles_append_item_with_filedata_safe, profiles_delete_item_safe,
|
||||
profiles_patch_item_safe, profiles_reorder_safe, profiles_save_file_safe,
|
||||
},
|
||||
profiles_append_item_safe, Config, IProfiles, PrfItem, PrfOption,
|
||||
profiles_append_item_safe,
|
||||
},
|
||||
core::{handle, timer::Timer, tray::Tray, CoreManager},
|
||||
core::{CoreManager, handle, timer::Timer, tray::Tray},
|
||||
feat, logging,
|
||||
process::AsyncHandler,
|
||||
ret_err,
|
||||
@@ -290,109 +291,106 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
|
||||
|
||||
// 如果要切换配置,先检查目标配置文件是否有语法错误
|
||||
if let Some(new_profile) = profiles.current.as_ref() {
|
||||
if current_profile.as_ref() != Some(new_profile) {
|
||||
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
|
||||
if let Some(new_profile) = profiles.current.as_ref()
|
||||
&& current_profile.as_ref() != Some(new_profile)
|
||||
{
|
||||
logging!(info, Type::Cmd, true, "正在切换到新配置: {}", new_profile);
|
||||
|
||||
// 获取目标配置文件路径
|
||||
let config_file_result = {
|
||||
let profiles_config = Config::profiles().await;
|
||||
let profiles_data = profiles_config.latest_ref();
|
||||
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));
|
||||
path.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
|
||||
// 获取目标配置文件路径
|
||||
let config_file_result = {
|
||||
let profiles_config = Config::profiles().await;
|
||||
let profiles_data = profiles_config.latest_ref();
|
||||
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));
|
||||
path.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 如果获取到文件路径,检查YAML语法
|
||||
if let Some(file_path) = config_file_result {
|
||||
if !file_path.exists() {
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
true,
|
||||
"目标配置文件不存在: {}",
|
||||
file_path.display()
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_not_found",
|
||||
format!("{}", file_path.display()),
|
||||
);
|
||||
return Ok(false);
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, true, "获取目标配置信息失败: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 超时保护
|
||||
let file_read_result = tokio::time::timeout(
|
||||
Duration::from_secs(5),
|
||||
tokio::fs::read_to_string(&file_path),
|
||||
)
|
||||
.await;
|
||||
// 如果获取到文件路径,检查YAML语法
|
||||
if let Some(file_path) = config_file_result {
|
||||
if !file_path.exists() {
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
true,
|
||||
"目标配置文件不存在: {}",
|
||||
file_path.display()
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_not_found",
|
||||
format!("{}", file_path.display()),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
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;
|
||||
// 超时保护
|
||||
let file_read_result = tokio::time::timeout(
|
||||
Duration::from_secs(5),
|
||||
tokio::fs::read_to_string(&file_path),
|
||||
)
|
||||
.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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -663,8 +661,9 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
||||
#[tauri::command]
|
||||
pub async fn view_profile(index: String) -> CmdResult {
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles_ref = profiles.latest_ref();
|
||||
let file = {
|
||||
wrap_err!(profiles.latest_ref().get_item(&index))?
|
||||
wrap_err!(profiles_ref.get_item(&index))?
|
||||
.file
|
||||
.clone()
|
||||
.ok_or("the file field is null")
|
||||
|
||||
@@ -16,11 +16,12 @@ pub async fn get_runtime_yaml() -> CmdResult<String> {
|
||||
let runtime = Config::runtime().await;
|
||||
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")
|
||||
))
|
||||
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"))
|
||||
)
|
||||
}
|
||||
|
||||
/// 获取运行时存在的键
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
core::{service, CoreManager},
|
||||
core::{CoreManager, service},
|
||||
utils::i18n::t,
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
core::{handle, CoreManager},
|
||||
core::{CoreManager, handle},
|
||||
logging,
|
||||
module::sysinfo::PlatformSpecification,
|
||||
utils::logging::Type,
|
||||
|
||||
@@ -25,17 +25,17 @@ impl IClashTemp {
|
||||
match map_result {
|
||||
Ok(mut map) => {
|
||||
template.0.keys().for_each(|key| {
|
||||
if !map.contains_key(key) {
|
||||
if let Some(value) = template.0.get(key) {
|
||||
map.insert(key.clone(), value.clone());
|
||||
}
|
||||
if !map.contains_key(key)
|
||||
&& let Some(value) = template.0.get(key)
|
||||
{
|
||||
map.insert(key.clone(), value.clone());
|
||||
}
|
||||
});
|
||||
// 确保 secret 字段存在且不为空
|
||||
if let Some(Value::String(s)) = map.get_mut("secret") {
|
||||
if s.is_empty() {
|
||||
*s = "set-your-secret".to_string();
|
||||
}
|
||||
if let Some(Value::String(s)) = map.get_mut("secret")
|
||||
&& s.is_empty()
|
||||
{
|
||||
*s = "set-your-secret".to_string();
|
||||
}
|
||||
Self(Self::guard(map))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
|
||||
use crate::{
|
||||
config::{profiles_append_item_safe, PrfItem},
|
||||
core::{handle, CoreManager},
|
||||
config::{PrfItem, profiles_append_item_safe},
|
||||
core::{CoreManager, handle},
|
||||
enhance, logging,
|
||||
utils::{dirs, help, logging::Type},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{Result, anyhow};
|
||||
use std::path::PathBuf;
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio::time::{sleep, Duration};
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
|
||||
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::utils::dirs::get_encryption_key;
|
||||
use aes_gcm::{
|
||||
aead::{Aead, KeyInit},
|
||||
Aes256Gcm, Key,
|
||||
aead::{Aead, KeyInit},
|
||||
};
|
||||
use base64::{engine::general_purpose::STANDARD, Engine};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
const NONCE_LENGTH: usize = 12;
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::utils::{
|
||||
network::{NetworkManager, ProxyType},
|
||||
tmpl,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use std::{fs, time::Duration};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::{prfitem::PrfItem, PrfOption};
|
||||
use super::{PrfOption, prfitem::PrfItem};
|
||||
use crate::{
|
||||
logging_error,
|
||||
process::AsyncHandler,
|
||||
utils::{dirs, help, logging::Type},
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use std::collections::HashSet;
|
||||
@@ -88,12 +88,12 @@ impl IProfiles {
|
||||
self.items = Some(vec![]);
|
||||
}
|
||||
|
||||
if let Some(current) = patch.current {
|
||||
if let Some(items) = self.items.as_ref() {
|
||||
let some_uid = Some(current);
|
||||
if items.iter().any(|e| e.uid == some_uid) {
|
||||
self.current = some_uid;
|
||||
}
|
||||
if let Some(current) = patch.current
|
||||
&& let Some(items) = self.items.as_ref()
|
||||
{
|
||||
let some_uid = Some(current);
|
||||
if items.iter().any(|e| e.uid == some_uid) {
|
||||
self.current = some_uid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,24 +287,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// get the merge index
|
||||
for (i, _) in items.iter().enumerate() {
|
||||
@@ -313,24 +313,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = merge_index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = merge_index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// get the script index
|
||||
for (i, _) in items.iter().enumerate() {
|
||||
@@ -339,24 +339,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = script_index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = script_index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// get the rules index
|
||||
for (i, _) in items.iter().enumerate() {
|
||||
@@ -365,24 +365,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = rules_index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = rules_index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// get the proxies index
|
||||
for (i, _) in items.iter().enumerate() {
|
||||
@@ -391,24 +391,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = proxies_index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = proxies_index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// get the groups index
|
||||
for (i, _) in items.iter().enumerate() {
|
||||
@@ -417,24 +417,24 @@ impl IProfiles {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(index) = groups_index {
|
||||
if let Some(file) = items.remove(index).file {
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
if let Some(index) = groups_index
|
||||
&& let Some(file) = items.remove(index).file
|
||||
{
|
||||
let _ = dirs::app_profiles_dir().map(async move |path| {
|
||||
let path = path.join(file);
|
||||
if path.exists() {
|
||||
let result = fs::remove_file(path.clone()).await;
|
||||
if let Err(err) = result {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
false,
|
||||
"[配置文件删除] 删除文件 {} 失败: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// delete the original uid
|
||||
if current == uid {
|
||||
@@ -595,25 +595,25 @@ impl IProfiles {
|
||||
|
||||
total_files += 1;
|
||||
|
||||
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if Self::is_profile_file(file_name) {
|
||||
// 检查是否为全局扩展文件
|
||||
if protected_files.contains(file_name) {
|
||||
log::debug!(target: "app", "保护全局扩展配置文件: {file_name}");
|
||||
continue;
|
||||
}
|
||||
if let Some(file_name) = path.file_name().and_then(|n| n.to_str())
|
||||
&& Self::is_profile_file(file_name)
|
||||
{
|
||||
// 检查是否为全局扩展文件
|
||||
if protected_files.contains(file_name) {
|
||||
log::debug!(target: "app", "保护全局扩展配置文件: {file_name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否为活跃文件
|
||||
if !active_files.contains(file_name) {
|
||||
match std::fs::remove_file(&path) {
|
||||
Ok(_) => {
|
||||
deleted_files.push(file_name.to_string());
|
||||
log::info!(target: "app", "已清理冗余文件: {file_name}");
|
||||
}
|
||||
Err(e) => {
|
||||
failed_deletions.push(format!("{file_name}: {e}"));
|
||||
log::warn!(target: "app", "清理文件失败: {file_name} - {e}");
|
||||
}
|
||||
// 检查是否为活跃文件
|
||||
if !active_files.contains(file_name) {
|
||||
match std::fs::remove_file(&path) {
|
||||
Ok(_) => {
|
||||
deleted_files.push(file_name.to_string());
|
||||
log::info!(target: "app", "已清理冗余文件: {file_name}");
|
||||
}
|
||||
Err(e) => {
|
||||
failed_deletions.push(format!("{file_name}: {e}"));
|
||||
log::warn!(target: "app", "清理文件失败: {file_name} - {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,50 +659,44 @@ impl IProfiles {
|
||||
}
|
||||
|
||||
// 对于主 profile 类型(remote/local),还需要收集其关联的扩展文件
|
||||
if let Some(itype) = &item.itype {
|
||||
if itype == "remote" || itype == "local" {
|
||||
if let Some(option) = &item.option {
|
||||
// 收集关联的扩展文件
|
||||
if let Some(merge_uid) = &option.merge {
|
||||
if let Ok(merge_item) = self.get_item(merge_uid) {
|
||||
if let Some(file) = &merge_item.file {
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(itype) = &item.itype
|
||||
&& (itype == "remote" || itype == "local")
|
||||
&& let Some(option) = &item.option
|
||||
{
|
||||
// 收集关联的扩展文件
|
||||
if let Some(merge_uid) = &option.merge
|
||||
&& let Ok(merge_item) = self.get_item(merge_uid)
|
||||
&& let Some(file) = &merge_item.file
|
||||
{
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
|
||||
if let Some(script_uid) = &option.script {
|
||||
if let Ok(script_item) = self.get_item(script_uid) {
|
||||
if let Some(file) = &script_item.file {
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(script_uid) = &option.script
|
||||
&& let Ok(script_item) = self.get_item(script_uid)
|
||||
&& let Some(file) = &script_item.file
|
||||
{
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
|
||||
if let Some(rules_uid) = &option.rules {
|
||||
if let Ok(rules_item) = self.get_item(rules_uid) {
|
||||
if let Some(file) = &rules_item.file {
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(rules_uid) = &option.rules
|
||||
&& let Ok(rules_item) = self.get_item(rules_uid)
|
||||
&& let Some(file) = &rules_item.file
|
||||
{
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
|
||||
if let Some(proxies_uid) = &option.proxies {
|
||||
if let Ok(proxies_item) = self.get_item(proxies_uid) {
|
||||
if let Some(file) = &proxies_item.file {
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(proxies_uid) = &option.proxies
|
||||
&& let Ok(proxies_item) = self.get_item(proxies_uid)
|
||||
&& let Some(file) = &proxies_item.file
|
||||
{
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
|
||||
if let Some(groups_uid) = &option.groups {
|
||||
if let Ok(groups_item) = self.get_item(groups_uid) {
|
||||
if let Some(file) = &groups_item.file {
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(groups_uid) = &option.groups
|
||||
&& let Ok(groups_item) = self.get_item(groups_uid)
|
||||
&& let Some(file) = &groups_item.file
|
||||
{
|
||||
active_files.insert(file.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
config::{deserialize_encrypted, serialize_encrypted, DEFAULT_PAC},
|
||||
config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted},
|
||||
logging,
|
||||
utils::{dirs, help, i18n, logging::Type},
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::process::AsyncHandler;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::time::{timeout, Duration};
|
||||
use tokio::time::{Duration, timeout};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use anyhow::anyhow;
|
||||
@@ -87,7 +87,7 @@ impl AsyncProxyQuery {
|
||||
use std::ptr;
|
||||
use winapi::shared::minwindef::{DWORD, HKEY};
|
||||
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
|
||||
use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER};
|
||||
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
|
||||
|
||||
unsafe {
|
||||
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
|
||||
@@ -209,13 +209,13 @@ impl AsyncProxyQuery {
|
||||
// Linux: 检查环境变量和GNOME设置
|
||||
|
||||
// 首先检查环境变量
|
||||
if let Ok(auto_proxy) = std::env::var("auto_proxy") {
|
||||
if !auto_proxy.is_empty() {
|
||||
return Ok(AsyncAutoproxy {
|
||||
enable: true,
|
||||
url: auto_proxy,
|
||||
});
|
||||
}
|
||||
if let Ok(auto_proxy) = std::env::var("auto_proxy")
|
||||
&& !auto_proxy.is_empty()
|
||||
{
|
||||
return Ok(AsyncAutoproxy {
|
||||
enable: true,
|
||||
url: auto_proxy,
|
||||
});
|
||||
}
|
||||
|
||||
// 尝试使用 gsettings 获取 GNOME 代理设置
|
||||
@@ -224,31 +224,31 @@ impl AsyncProxyQuery {
|
||||
.output()
|
||||
.await;
|
||||
|
||||
if let Ok(output) = output {
|
||||
if output.status.success() {
|
||||
let mode = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if mode.contains("auto") {
|
||||
// 获取 PAC URL
|
||||
let pac_output = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy", "autoconfig-url"])
|
||||
.output()
|
||||
.await;
|
||||
if let Ok(output) = output
|
||||
&& output.status.success()
|
||||
{
|
||||
let mode = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if mode.contains("auto") {
|
||||
// 获取 PAC URL
|
||||
let pac_output = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy", "autoconfig-url"])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
if let Ok(pac_output) = pac_output {
|
||||
if pac_output.status.success() {
|
||||
let pac_url = String::from_utf8_lossy(&pac_output.stdout)
|
||||
.trim()
|
||||
.trim_matches('\'')
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
if let Ok(pac_output) = pac_output
|
||||
&& pac_output.status.success()
|
||||
{
|
||||
let pac_url = String::from_utf8_lossy(&pac_output.stdout)
|
||||
.trim()
|
||||
.trim_matches('\'')
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
|
||||
if !pac_url.is_empty() {
|
||||
return Ok(AsyncAutoproxy {
|
||||
enable: true,
|
||||
url: pac_url,
|
||||
});
|
||||
}
|
||||
}
|
||||
if !pac_url.is_empty() {
|
||||
return Ok(AsyncAutoproxy {
|
||||
enable: true,
|
||||
url: pac_url,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ impl AsyncProxyQuery {
|
||||
use std::ptr;
|
||||
use winapi::shared::minwindef::{DWORD, HKEY};
|
||||
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
|
||||
use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW, HKEY_CURRENT_USER};
|
||||
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
|
||||
|
||||
unsafe {
|
||||
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
|
||||
@@ -402,10 +402,10 @@ impl AsyncProxyQuery {
|
||||
http_host = host_part.trim().to_string();
|
||||
}
|
||||
} else if line.contains("HTTPPort") {
|
||||
if let Some(port_part) = line.split(':').nth(1) {
|
||||
if let Ok(port) = port_part.trim().parse::<u16>() {
|
||||
http_port = port;
|
||||
}
|
||||
if let Some(port_part) = line.split(':').nth(1)
|
||||
&& let Ok(port) = port_part.trim().parse::<u16>()
|
||||
{
|
||||
http_port = port;
|
||||
}
|
||||
} else if line.contains("ExceptionsList") {
|
||||
// 解析异常列表
|
||||
@@ -431,16 +431,16 @@ impl AsyncProxyQuery {
|
||||
// Linux: 检查环境变量和桌面环境设置
|
||||
|
||||
// 首先检查环境变量
|
||||
if let Ok(http_proxy) = std::env::var("http_proxy") {
|
||||
if let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy) {
|
||||
return Ok(proxy_info);
|
||||
}
|
||||
if let Ok(http_proxy) = std::env::var("http_proxy")
|
||||
&& let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy)
|
||||
{
|
||||
return Ok(proxy_info);
|
||||
}
|
||||
|
||||
if let Ok(https_proxy) = std::env::var("https_proxy") {
|
||||
if let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy) {
|
||||
return Ok(proxy_info);
|
||||
}
|
||||
if let Ok(https_proxy) = std::env::var("https_proxy")
|
||||
&& let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy)
|
||||
{
|
||||
return Ok(proxy_info);
|
||||
}
|
||||
|
||||
// 尝试使用 gsettings 获取 GNOME 代理设置
|
||||
@@ -449,45 +449,46 @@ impl AsyncProxyQuery {
|
||||
.output()
|
||||
.await;
|
||||
|
||||
if let Ok(mode_output) = mode_output {
|
||||
if mode_output.status.success() {
|
||||
let mode = String::from_utf8_lossy(&mode_output.stdout)
|
||||
.trim()
|
||||
.to_string();
|
||||
if mode.contains("manual") {
|
||||
// 获取HTTP代理设置
|
||||
let host_result = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy.http", "host"])
|
||||
.output()
|
||||
.await;
|
||||
if let Ok(mode_output) = mode_output
|
||||
&& mode_output.status.success()
|
||||
{
|
||||
let mode = String::from_utf8_lossy(&mode_output.stdout)
|
||||
.trim()
|
||||
.to_string();
|
||||
if mode.contains("manual") {
|
||||
// 获取HTTP代理设置
|
||||
let host_result = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy.http", "host"])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
let port_result = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy.http", "port"])
|
||||
.output()
|
||||
.await;
|
||||
let port_result = Command::new("gsettings")
|
||||
.args(["get", "org.gnome.system.proxy.http", "port"])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
if let (Ok(host_output), Ok(port_output)) = (host_result, port_result) {
|
||||
if host_output.status.success() && port_output.status.success() {
|
||||
let host = String::from_utf8_lossy(&host_output.stdout)
|
||||
.trim()
|
||||
.trim_matches('\'')
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
if let (Ok(host_output), Ok(port_output)) = (host_result, port_result)
|
||||
&& host_output.status.success()
|
||||
&& port_output.status.success()
|
||||
{
|
||||
let host = String::from_utf8_lossy(&host_output.stdout)
|
||||
.trim()
|
||||
.trim_matches('\'')
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
|
||||
let port = String::from_utf8_lossy(&port_output.stdout)
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.unwrap_or(8080);
|
||||
let port = String::from_utf8_lossy(&port_output.stdout)
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.unwrap_or(8080);
|
||||
|
||||
if !host.is_empty() {
|
||||
return Ok(AsyncSysproxy {
|
||||
enable: true,
|
||||
host,
|
||||
port,
|
||||
bypass: String::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
if !host.is_empty() {
|
||||
return Ok(AsyncSysproxy {
|
||||
enable: true,
|
||||
host,
|
||||
port,
|
||||
bypass: String::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ use chrono::Local;
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
fmt,
|
||||
fs::{create_dir_all, File},
|
||||
fs::{File, create_dir_all},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use tauri_plugin_shell::{process::CommandChild, ShellExt};
|
||||
use tauri_plugin_shell::{ShellExt, process::CommandChild};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CoreManager {
|
||||
@@ -467,18 +467,18 @@ impl CoreManager {
|
||||
Ok((pids, process_name)) => {
|
||||
for pid in pids {
|
||||
// 跳过当前管理的进程
|
||||
if let Some(current) = current_pid {
|
||||
if pid == current {
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
true,
|
||||
"跳过当前管理的进程: {} (PID: {})",
|
||||
process_name,
|
||||
pid
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if let Some(current) = current_pid
|
||||
&& pid == current
|
||||
{
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
true,
|
||||
"跳过当前管理的进程: {} (PID: {})",
|
||||
process_name,
|
||||
pid
|
||||
);
|
||||
continue;
|
||||
}
|
||||
pids_to_kill.push((pid, process_name.clone()));
|
||||
}
|
||||
@@ -527,7 +527,7 @@ impl CoreManager {
|
||||
use std::mem;
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::tlhelp32::{
|
||||
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
|
||||
CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW,
|
||||
TH32CS_SNAPPROCESS,
|
||||
};
|
||||
use winapi::um::winnt::HANDLE;
|
||||
@@ -703,7 +703,7 @@ impl CoreManager {
|
||||
use winapi::um::processthreadsapi::OpenProcess;
|
||||
use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION};
|
||||
|
||||
let result = AsyncHandler::spawn_blocking(move || -> Result<bool> {
|
||||
AsyncHandler::spawn_blocking(move || -> Result<bool> {
|
||||
unsafe {
|
||||
let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
|
||||
if process_handle.is_null() {
|
||||
@@ -719,9 +719,7 @@ impl CoreManager {
|
||||
Ok(exit_code == 259)
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
|
||||
result
|
||||
.await?
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -767,16 +765,16 @@ impl CoreManager {
|
||||
|
||||
AsyncHandler::spawn(move || async move {
|
||||
while let Some(event) = rx.recv().await {
|
||||
if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event {
|
||||
if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) {
|
||||
logging!(
|
||||
error,
|
||||
Type::Core,
|
||||
true,
|
||||
"[Sidecar] Failed to write stdout to file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event
|
||||
&& let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line))
|
||||
{
|
||||
logging!(
|
||||
error,
|
||||
Type::Core,
|
||||
true,
|
||||
"[Sidecar] Failed to write stdout to file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use tokio::time::{sleep, timeout, Duration};
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use tokio::time::{Duration, sleep, timeout};
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
|
||||
use crate::config::{Config, IVerge};
|
||||
use crate::core::async_proxy_query::AsyncProxyQuery;
|
||||
|
||||
@@ -2,8 +2,9 @@ use crate::singleton;
|
||||
use parking_lot::RwLock;
|
||||
use std::{
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicU64, Ordering},
|
||||
mpsc, Arc,
|
||||
mpsc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
@@ -98,16 +99,14 @@ impl NotificationSystem {
|
||||
|
||||
let is_emergency = *system.emergency_mode.read();
|
||||
|
||||
if is_emergency {
|
||||
if let FrontendEvent::NoticeMessage { ref status, .. } = event {
|
||||
if status == "info" {
|
||||
if is_emergency
|
||||
&& let FrontendEvent::NoticeMessage { ref status, .. } = event
|
||||
&& status == "info" {
|
||||
log::warn!(
|
||||
"Emergency mode active, skipping info message"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(window) = handle.get_window() {
|
||||
*system.last_emit_time.write() = Instant::now();
|
||||
@@ -203,13 +202,12 @@ impl NotificationSystem {
|
||||
|
||||
/// 发送事件到队列
|
||||
fn send_event(&self, event: FrontendEvent) -> bool {
|
||||
if *self.emergency_mode.read() {
|
||||
if let FrontendEvent::NoticeMessage { ref status, .. } = event {
|
||||
if status == "info" {
|
||||
log::info!("Skipping info message in emergency mode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if *self.emergency_mode.read()
|
||||
&& let FrontendEvent::NoticeMessage { ref status, .. } = event
|
||||
&& status == "info"
|
||||
{
|
||||
log::info!("Skipping info message in emergency mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(sender) = &self.sender {
|
||||
@@ -392,7 +390,9 @@ impl Handle {
|
||||
if let Some(system) = system_opt.as_ref() {
|
||||
system.send_event(FrontendEvent::ProfileUpdateStarted { uid });
|
||||
} else {
|
||||
log::warn!("Notification system not initialized when trying to send ProfileUpdateStarted event.");
|
||||
log::warn!(
|
||||
"Notification system not initialized when trying to send ProfileUpdateStarted event."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +406,9 @@ impl Handle {
|
||||
if let Some(system) = system_opt.as_ref() {
|
||||
system.send_event(FrontendEvent::ProfileUpdateCompleted { uid });
|
||||
} else {
|
||||
log::warn!("Notification system not initialized when trying to send ProfileUpdateCompleted event.");
|
||||
log::warn!(
|
||||
"Notification system not initialized when trying to send ProfileUpdateCompleted event."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::utils::notification::{notify_event, NotificationEvent};
|
||||
use crate::utils::notification::{NotificationEvent, notify_event};
|
||||
use crate::{
|
||||
config::Config, core::handle, feat, logging, logging_error,
|
||||
module::lightweight::entry_lightweight_mode, singleton_with_logging, utils::logging::Type,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{Result, bail};
|
||||
use parking_lot::Mutex;
|
||||
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
|
||||
use tauri::{AppHandle, Manager};
|
||||
@@ -243,11 +243,11 @@ impl Hotkey {
|
||||
);
|
||||
|
||||
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
|
||||
if let Some(window) = app_handle_cloned.get_webview_window("main") {
|
||||
if window.is_focused().unwrap_or(false) {
|
||||
logging!(debug, Type::Hotkey, "Executing quit function");
|
||||
Self::execute_function(function_owned, &app_handle_cloned);
|
||||
}
|
||||
if let Some(window) = app_handle_cloned.get_webview_window("main")
|
||||
&& window.is_focused().unwrap_or(false)
|
||||
{
|
||||
logging!(debug, Type::Hotkey, "Executing quit function");
|
||||
Self::execute_function(function_owned, &app_handle_cloned);
|
||||
}
|
||||
} else {
|
||||
logging!(debug, Type::Hotkey, "Executing function directly");
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::service_ipc::{send_ipc_request, IpcCommand},
|
||||
core::service_ipc::{IpcCommand, send_ipc_request},
|
||||
logging,
|
||||
utils::{dirs, logging::Type},
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
env::current_exe,
|
||||
@@ -617,17 +617,11 @@ pub async fn check_service_version() -> Result<String> {
|
||||
match response.data {
|
||||
Some(data) => {
|
||||
if let Some(nested_data) = data.get("data") {
|
||||
if let Some(version) = nested_data.get("version") {
|
||||
if let Some(version_str) = version.as_str() {
|
||||
logging!(
|
||||
info,
|
||||
Type::Service,
|
||||
true,
|
||||
"获取到服务版本: {}",
|
||||
version_str
|
||||
);
|
||||
return Ok(version_str.to_string());
|
||||
}
|
||||
if let Some(version) = nested_data.get("version")
|
||||
&& let Some(version_str) = version.as_str()
|
||||
{
|
||||
logging!(info, Type::Service, true, "获取到服务版本: {}", version_str);
|
||||
return Ok(version_str.to_string());
|
||||
}
|
||||
logging!(
|
||||
error,
|
||||
@@ -792,25 +786,25 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
||||
}
|
||||
|
||||
// 添加对嵌套JSON结构的处理
|
||||
if let Some(data) = &response.data {
|
||||
if let Some(code) = data.get("code") {
|
||||
let code_value = code.as_u64().unwrap_or(1);
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
if let Some(data) = &response.data
|
||||
&& let Some(code) = data.get("code")
|
||||
{
|
||||
let code_value = code.as_u64().unwrap_or(1);
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
|
||||
if code_value != 0 {
|
||||
logging!(
|
||||
error,
|
||||
Type::Service,
|
||||
true,
|
||||
"启动核心返回错误: code={}, msg={}",
|
||||
code_value,
|
||||
msg
|
||||
);
|
||||
bail!("启动核心失败: {}", msg);
|
||||
}
|
||||
if code_value != 0 {
|
||||
logging!(
|
||||
error,
|
||||
Type::Service,
|
||||
true,
|
||||
"启动核心返回错误: code={}, msg={}",
|
||||
code_value,
|
||||
msg
|
||||
);
|
||||
bail!("启动核心失败: {}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,25 +912,25 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
||||
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
|
||||
}
|
||||
|
||||
if let Some(data) = &response.data {
|
||||
if let Some(code) = data.get("code") {
|
||||
let code_value = code.as_u64().unwrap_or(1);
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
if let Some(data) = &response.data
|
||||
&& let Some(code) = data.get("code")
|
||||
{
|
||||
let code_value = code.as_u64().unwrap_or(1);
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
|
||||
if code_value != 0 {
|
||||
logging!(
|
||||
error,
|
||||
Type::Service,
|
||||
true,
|
||||
"停止核心返回错误: code={}, msg={}",
|
||||
code_value,
|
||||
msg
|
||||
);
|
||||
bail!("停止核心失败: {}", msg);
|
||||
}
|
||||
if code_value != 0 {
|
||||
logging!(
|
||||
error,
|
||||
Type::Service,
|
||||
true,
|
||||
"停止核心返回错误: code={}, msg={}",
|
||||
code_value,
|
||||
msg
|
||||
);
|
||||
bail!("停止核心失败: {}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::{logging, utils::logging::Type};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use hmac::{Hmac, Mac};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::utils::autostart as startup_shortcut;
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
core::{handle::Handle, EventDrivenProxyManager},
|
||||
core::{EventDrivenProxyManager, handle::Handle},
|
||||
logging, logging_error, singleton_lazy,
|
||||
utils::logging::Type,
|
||||
};
|
||||
@@ -24,8 +24,7 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;
|
||||
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";
|
||||
#[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 {
|
||||
let use_default = Config::verge()
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::{
|
||||
collections::HashMap,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -242,19 +242,18 @@ impl Timer {
|
||||
|
||||
if let Some(items) = Config::profiles().await.latest_ref().get_items() {
|
||||
for item in items.iter() {
|
||||
if let Some(option) = item.option.as_ref() {
|
||||
if let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) {
|
||||
if interval > 0 {
|
||||
logging!(
|
||||
debug,
|
||||
Type::Timer,
|
||||
"找到定时更新配置: uid={}, interval={}min",
|
||||
uid,
|
||||
interval
|
||||
);
|
||||
new_map.insert(uid.clone(), interval);
|
||||
}
|
||||
}
|
||||
if let Some(option) = item.option.as_ref()
|
||||
&& let (Some(interval), Some(uid)) = (option.update_interval, &item.uid)
|
||||
&& interval > 0
|
||||
{
|
||||
logging!(
|
||||
debug,
|
||||
Type::Timer,
|
||||
"找到定时更新配置: uid={}, interval={}min",
|
||||
uid,
|
||||
interval
|
||||
);
|
||||
new_map.insert(uid.clone(), interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,7 +389,8 @@ impl Timer {
|
||||
};
|
||||
|
||||
// Get the profile updated timestamp - now safe to await
|
||||
let profiles = { Config::profiles().await.clone().data_ref() }.clone();
|
||||
let config_profiles = Config::profiles().await;
|
||||
let profiles = config_profiles.data_ref().clone();
|
||||
let items = match profiles.get_items() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use once_cell::sync::OnceCell;
|
||||
use tauri::tray::TrayIconBuilder;
|
||||
use tauri::Emitter;
|
||||
use tauri::tray::TrayIconBuilder;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod speed_rate;
|
||||
use crate::ipc::Rate;
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::{
|
||||
cmd,
|
||||
Type, cmd,
|
||||
config::Config,
|
||||
feat,
|
||||
ipc::IpcManager,
|
||||
@@ -14,7 +14,6 @@ use crate::{
|
||||
module::lightweight::is_in_lightweight_mode,
|
||||
singleton_lazy,
|
||||
utils::{dirs::find_target_icons, i18n::t},
|
||||
Type,
|
||||
};
|
||||
|
||||
use super::handle;
|
||||
@@ -27,9 +26,9 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tauri::{
|
||||
AppHandle, Wry,
|
||||
menu::{CheckMenuItem, IsMenuItem, MenuEvent, MenuItem, PredefinedMenuItem, Submenu},
|
||||
tray::{MouseButton, MouseButtonState, TrayIconEvent},
|
||||
AppHandle, Wry,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -74,12 +73,11 @@ impl TrayState {
|
||||
pub async fn get_common_tray_icon() -> (bool, Vec<u8>) {
|
||||
let verge = Config::verge().await.latest_ref().clone();
|
||||
let is_common_tray_icon = verge.common_tray_icon.unwrap_or(false);
|
||||
if is_common_tray_icon {
|
||||
if let Ok(Some(common_icon_path)) = find_target_icons("common") {
|
||||
if let Ok(icon_data) = fs::read(common_icon_path) {
|
||||
return (true, icon_data);
|
||||
}
|
||||
}
|
||||
if is_common_tray_icon
|
||||
&& let Ok(Some(common_icon_path)) = find_target_icons("common")
|
||||
&& let Ok(icon_data) = fs::read(common_icon_path)
|
||||
{
|
||||
return (true, icon_data);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@@ -109,12 +107,11 @@ impl TrayState {
|
||||
pub async fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) {
|
||||
let verge = Config::verge().await.latest_ref().clone();
|
||||
let is_sysproxy_tray_icon = verge.sysproxy_tray_icon.unwrap_or(false);
|
||||
if is_sysproxy_tray_icon {
|
||||
if let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy") {
|
||||
if let Ok(icon_data) = fs::read(sysproxy_icon_path) {
|
||||
return (true, icon_data);
|
||||
}
|
||||
}
|
||||
if is_sysproxy_tray_icon
|
||||
&& let Ok(Some(sysproxy_icon_path)) = find_target_icons("sysproxy")
|
||||
&& let Ok(icon_data) = fs::read(sysproxy_icon_path)
|
||||
{
|
||||
return (true, icon_data);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@@ -144,12 +141,11 @@ impl TrayState {
|
||||
pub async fn get_tun_tray_icon() -> (bool, Vec<u8>) {
|
||||
let verge = Config::verge().await.latest_ref().clone();
|
||||
let is_tun_tray_icon = verge.tun_tray_icon.unwrap_or(false);
|
||||
if is_tun_tray_icon {
|
||||
if let Ok(Some(tun_icon_path)) = find_target_icons("tun") {
|
||||
if let Ok(icon_data) = fs::read(tun_icon_path) {
|
||||
return (true, icon_data);
|
||||
}
|
||||
}
|
||||
if is_tun_tray_icon
|
||||
&& let Ok(Some(tun_icon_path)) = find_target_icons("tun")
|
||||
&& let Ok(icon_data) = fs::read(tun_icon_path)
|
||||
{
|
||||
return (true, icon_data);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@@ -429,13 +425,13 @@ impl Tray {
|
||||
{
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles = profiles.latest_ref();
|
||||
if let Some(current_profile_uid) = profiles.get_current() {
|
||||
if let Ok(profile) = profiles.get_item(¤t_profile_uid) {
|
||||
current_profile_name = match &profile.name {
|
||||
Some(profile_name) => profile_name.to_string(),
|
||||
None => current_profile_name,
|
||||
};
|
||||
}
|
||||
if let Some(current_profile_uid) = profiles.get_current()
|
||||
&& let Ok(profile) = profiles.get_item(¤t_profile_uid)
|
||||
{
|
||||
current_profile_name = match &profile.name {
|
||||
Some(profile_name) => profile_name.to_string(),
|
||||
None => current_profile_name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#![cfg(target_os = "windows")]
|
||||
|
||||
use crate::utils::dirs;
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{Result, bail};
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommand;
|
||||
use std::process::Command as StdCommand;
|
||||
|
||||
@@ -18,12 +18,10 @@ pub fn use_merge(merge: Mapping, config: Mapping) -> Mapping {
|
||||
|
||||
deep_merge(&mut config, &Value::from(merge));
|
||||
|
||||
let config = config.as_mapping().cloned().unwrap_or_else(|| {
|
||||
config.as_mapping().cloned().unwrap_or_else(|| {
|
||||
log::error!("Failed to convert merged config to mapping, using empty mapping");
|
||||
Mapping::new()
|
||||
});
|
||||
|
||||
config
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -384,29 +384,26 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
if let Ok(app_dir) = dirs::app_home_dir() {
|
||||
let dns_path = app_dir.join("dns_config.yaml");
|
||||
|
||||
if dns_path.exists() {
|
||||
if let Ok(dns_yaml) = fs::read_to_string(&dns_path) {
|
||||
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") {
|
||||
if hosts_value.is_mapping() {
|
||||
config.insert("hosts".into(), hosts_value.clone());
|
||||
log::info!(target: "app", "apply hosts configuration");
|
||||
}
|
||||
}
|
||||
if dns_path.exists()
|
||||
&& 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)
|
||||
{
|
||||
// 处理hosts配置
|
||||
if let Some(hosts_value) = dns_config.get("hosts")
|
||||
&& hosts_value.is_mapping()
|
||||
{
|
||||
config.insert("hosts".into(), hosts_value.clone());
|
||||
log::info!(target: "app", "apply hosts configuration");
|
||||
}
|
||||
|
||||
if let Some(dns_value) = dns_config.get("dns") {
|
||||
if let Some(dns_mapping) = dns_value.as_mapping() {
|
||||
config.insert("dns".into(), dns_mapping.clone().into());
|
||||
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");
|
||||
}
|
||||
if let Some(dns_value) = dns_config.get("dns") {
|
||||
if let Some(dns_mapping) = dns_value.as_mapping() {
|
||||
config.insert("dns".into(), dns_mapping.clone().into());
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ pub fn use_script(
|
||||
config: Mapping,
|
||||
name: String,
|
||||
) -> Result<(Mapping, Vec<(String, String)>)> {
|
||||
use boa_engine::{native_function::NativeFunction, Context, JsString, JsValue, Source};
|
||||
use boa_engine::{Context, JsString, JsValue, Source, native_function::NativeFunction};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
let mut context = Context::default();
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
// If this is proxies field, we also need to filter proxy-groups
|
||||
if field == "proxies" {
|
||||
if let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups") {
|
||||
let mut new_groups = Sequence::new();
|
||||
for group in groups {
|
||||
if let Value::Mapping(group_map) = group {
|
||||
let mut new_group = group_map.clone();
|
||||
if let Some(Value::Sequence(proxies)) = group_map.get("proxies") {
|
||||
let filtered_proxies: Sequence = proxies
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
if let Value::String(name) = p {
|
||||
!delete.contains(name)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
new_group.insert(
|
||||
Value::String("proxies".into()),
|
||||
Value::Sequence(filtered_proxies),
|
||||
);
|
||||
}
|
||||
new_groups.push(Value::Mapping(new_group));
|
||||
} else {
|
||||
new_groups.push(group.clone());
|
||||
if field == "proxies"
|
||||
&& let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups")
|
||||
{
|
||||
let mut new_groups = Sequence::new();
|
||||
for group in groups {
|
||||
if let Value::Mapping(group_map) = group {
|
||||
let mut new_group = group_map.clone();
|
||||
if let Some(Value::Sequence(proxies)) = group_map.get("proxies") {
|
||||
let filtered_proxies: Sequence = proxies
|
||||
.iter()
|
||||
.filter(|p| {
|
||||
if let Value::String(name) = p {
|
||||
!delete.contains(name)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
new_group.insert(
|
||||
Value::String("proxies".into()),
|
||||
Value::Sequence(filtered_proxies),
|
||||
);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, tray, CoreManager},
|
||||
core::{CoreManager, handle, tray},
|
||||
ipc::IpcManager,
|
||||
logging_error,
|
||||
process::AsyncHandler,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
core::{handle, hotkey, sysopt, tray, CoreManager},
|
||||
core::{CoreManager, handle, hotkey, sysopt, tray},
|
||||
logging_error,
|
||||
module::lightweight,
|
||||
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 {
|
||||
sysopt::Sysopt::global().update_sysproxy().await?;
|
||||
}
|
||||
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 {
|
||||
if let Some(hotkeys) = patch.hotkeys {
|
||||
hotkey::Hotkey::global().update(hotkeys).await?;
|
||||
}
|
||||
if (update_flags & (UpdateFlags::Hotkey as i32)) != 0
|
||||
&& let Some(hotkeys) = patch.hotkeys
|
||||
{
|
||||
hotkey::Hotkey::global().update(hotkeys).await?;
|
||||
}
|
||||
if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 {
|
||||
tray::Tray::global().update_menu().await?;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
cmd,
|
||||
config::{profiles::profiles_draft_update_item_safe, Config, PrfItem, PrfOption},
|
||||
core::{handle, tray, CoreManager},
|
||||
config::{Config, PrfItem, PrfOption, profiles::profiles_draft_update_item_safe},
|
||||
core::{CoreManager, handle, tray},
|
||||
logging,
|
||||
utils::logging::Type,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{Result, bail};
|
||||
|
||||
/// Toggle proxy profile
|
||||
pub async fn toggle_proxy_profile(profile_index: String) {
|
||||
|
||||
@@ -13,21 +13,22 @@ pub async fn toggle_system_proxy() {
|
||||
// 获取当前系统代理状态
|
||||
let enable = {
|
||||
let verge = Config::verge().await;
|
||||
let enable = verge.latest_ref().enable_system_proxy.unwrap_or(false);
|
||||
enable
|
||||
|
||||
verge.latest_ref().enable_system_proxy.unwrap_or(false)
|
||||
};
|
||||
// 获取自动关闭连接设置
|
||||
let auto_close_connection = {
|
||||
let verge = Config::verge().await;
|
||||
let auto_close = verge.latest_ref().auto_close_connection.unwrap_or(false);
|
||||
auto_close
|
||||
|
||||
verge.latest_ref().auto_close_connection.unwrap_or(false)
|
||||
};
|
||||
|
||||
// 如果当前系统代理即将关闭,且自动关闭连接设置为true,则关闭所有连接
|
||||
if enable && auto_close_connection {
|
||||
if let Err(err) = IpcManager::global().close_all_connections().await {
|
||||
log::error!(target: "app", "Failed to close all connections: {err}");
|
||||
}
|
||||
if enable
|
||||
&& auto_close_connection
|
||||
&& let Err(err) = IpcManager::global().close_all_connections().await
|
||||
{
|
||||
log::error!(target: "app", "Failed to close all connections: {err}");
|
||||
}
|
||||
|
||||
let patch_result = super::patch_verge(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, sysopt, CoreManager},
|
||||
core::{CoreManager, handle, sysopt},
|
||||
ipc::IpcManager,
|
||||
logging,
|
||||
utils::logging::Type,
|
||||
@@ -92,7 +92,7 @@ pub async fn quit() {
|
||||
}
|
||||
|
||||
async fn clean_async() -> bool {
|
||||
use tokio::time::{timeout, Duration};
|
||||
use tokio::time::{Duration, timeout};
|
||||
|
||||
logging!(info, Type::System, true, "开始执行异步清理操作...");
|
||||
|
||||
@@ -252,10 +252,10 @@ pub async fn hide() {
|
||||
add_light_weight_timer().await;
|
||||
}
|
||||
|
||||
if let Some(window) = handle::Handle::global().get_window() {
|
||||
if window.is_visible().unwrap_or(false) {
|
||||
let _ = window.hide();
|
||||
}
|
||||
if let Some(window) = handle::Handle::global().get_window()
|
||||
&& window.is_visible().unwrap_or(false)
|
||||
{
|
||||
let _ = window.hide();
|
||||
}
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use kode_bridge::{
|
||||
errors::{AnyError, AnyResult},
|
||||
ClientConfig, IpcHttpClient, LegacyResponse,
|
||||
errors::{AnyError, AnyResult},
|
||||
};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
|
||||
|
||||
use crate::{
|
||||
logging, singleton_with_logging,
|
||||
@@ -199,8 +199,7 @@ impl IpcManager {
|
||||
// 测速URL不再编码,直接传递
|
||||
let url = format!("/proxies/{encoded_name}/delay?url={test_url}&timeout={timeout}");
|
||||
|
||||
let response = self.send_request("GET", &url, None).await;
|
||||
response
|
||||
self.send_request("GET", &url, None).await
|
||||
}
|
||||
|
||||
// 版本和配置相关
|
||||
@@ -340,8 +339,7 @@ impl IpcManager {
|
||||
// 测速URL不再编码,直接传递
|
||||
let url = format!("/group/{encoded_group_name}/delay?url={test_url}&timeout={timeout}");
|
||||
|
||||
let response = self.send_request("GET", &url, None).await;
|
||||
response
|
||||
self.send_request("GET", &url, None).await
|
||||
}
|
||||
|
||||
// 调试相关
|
||||
|
||||
@@ -26,7 +26,7 @@ use tauri::Manager;
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri_plugin_autostart::MacosLauncher;
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
use tokio::time::{timeout, Duration};
|
||||
use tokio::time::{Duration, timeout};
|
||||
use utils::logging::Type;
|
||||
|
||||
/// Application initialization helper functions
|
||||
@@ -134,8 +134,8 @@ mod app_init {
|
||||
}
|
||||
|
||||
/// Generate all command handlers for the application
|
||||
pub fn generate_handlers(
|
||||
) -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
|
||||
pub fn generate_handlers()
|
||||
-> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
|
||||
tauri::generate_handler![
|
||||
// Common commands
|
||||
cmd::get_sys_proxy,
|
||||
@@ -275,7 +275,9 @@ pub fn run() {
|
||||
// Set Linux environment variable
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
unsafe {
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
}
|
||||
|
||||
let desktop_env = std::env::var("XDG_CURRENT_DESKTOP")
|
||||
.unwrap_or_default()
|
||||
@@ -284,7 +286,9 @@ pub fn run() {
|
||||
let is_plasma_desktop = desktop_env.contains("PLASMA");
|
||||
|
||||
if is_kde_desktop || is_plasma_desktop {
|
||||
std::env::set_var("GTK_CSD", "0");
|
||||
unsafe {
|
||||
std::env::set_var("GTK_CSD", "0");
|
||||
}
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
@@ -438,10 +442,10 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
|
||||
if !is_enable_global_hotkey {
|
||||
if let Err(e) = hotkey::Hotkey::global().init().await {
|
||||
logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e);
|
||||
}
|
||||
if !is_enable_global_hotkey
|
||||
&& let Err(e) = hotkey::Hotkey::global().init().await
|
||||
{
|
||||
logging!(error, Type::Hotkey, true, "Failed to init hotkeys: {}", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -474,10 +478,8 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
|
||||
if !is_enable_global_hotkey {
|
||||
if let Err(e) = hotkey::Hotkey::global().reset() {
|
||||
logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e);
|
||||
}
|
||||
if !is_enable_global_hotkey && let Err(e) = hotkey::Hotkey::global().reset() {
|
||||
logging!(error, Type::Hotkey, true, "Failed to reset hotkeys: {}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{
|
||||
utils::{logging::Type, window_manager::WindowManager},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::logging_error;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
@@ -136,13 +137,13 @@ pub async fn entry_lightweight_mode() {
|
||||
result
|
||||
);
|
||||
|
||||
if let Some(window) = handle::Handle::global().get_window() {
|
||||
if let Some(webview) = window.get_webview_window("main") {
|
||||
let _ = webview.destroy();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
if let Some(window) = handle::Handle::global().get_window()
|
||||
&& let Some(webview) = window.get_webview_window("main")
|
||||
{
|
||||
let _ = webview.destroy();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
set_lightweight_mode(true).await;
|
||||
let _ = cancel_light_weight_timer();
|
||||
ProxyRequestCache::global().clean_default_keys();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
cmd::system,
|
||||
core::{handle, CoreManager},
|
||||
core::{CoreManager, handle},
|
||||
};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use sysinfo::System;
|
||||
@@ -20,7 +20,13 @@ impl Debug for PlatformSpecification {
|
||||
write!(
|
||||
f,
|
||||
"System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}\nIs Admin: {}",
|
||||
self.system_name, self.system_version, self.system_kernel_version, self.system_arch, self.verge_version, self.running_mode, self.is_admin
|
||||
self.system_name,
|
||||
self.system_version,
|
||||
self.system_kernel_version,
|
||||
self.system_arch,
|
||||
self.verge_version,
|
||||
self.running_mode,
|
||||
self.is_admin
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,12 +67,18 @@ impl AsyncHandler {
|
||||
location.column()
|
||||
);
|
||||
|
||||
println!("┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐");
|
||||
println!(
|
||||
"┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"
|
||||
);
|
||||
println!("│ {:<18} │ {:<80} │", "Field", "Value");
|
||||
println!("├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤");
|
||||
println!(
|
||||
"├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"
|
||||
);
|
||||
println!("│ {:<18} │ {:<80} │", "Type of task", type_str);
|
||||
println!("│ {:<18} │ {:<80} │", "Size of task", size_str);
|
||||
println!("│ {:<18} │ {:<80} │", "Called from", loc_str);
|
||||
println!("└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘");
|
||||
println!(
|
||||
"└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{Result, anyhow};
|
||||
#[cfg(target_os = "windows")]
|
||||
use log::info;
|
||||
|
||||
|
||||
@@ -151,12 +151,11 @@ pub fn find_target_icons(target: &str) -> Result<Option<String>> {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if file_name.starts_with(target)
|
||||
&& (file_name.ends_with(".ico") || file_name.ends_with(".png"))
|
||||
{
|
||||
matching_files.push(path);
|
||||
}
|
||||
if let Some(file_name) = path.file_name().and_then(|n| n.to_str())
|
||||
&& file_name.starts_with(target)
|
||||
&& (file_name.ends_with(".ico") || file_name.ends_with(".png"))
|
||||
{
|
||||
matching_files.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{enhance::seq::SeqMap, logging, utils::logging::Type};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use anyhow::{Context, Result, anyhow, bail};
|
||||
use nanoid::nanoid;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use serde_yaml_ng::Mapping;
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
@@ -154,10 +154,6 @@ macro_rules! ret_err {
|
||||
#[macro_export]
|
||||
macro_rules! t {
|
||||
($en:expr, $zh:expr, $use_zh:expr) => {
|
||||
if $use_zh {
|
||||
$zh
|
||||
} else {
|
||||
$en
|
||||
}
|
||||
if $use_zh { $zh } else { $en }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@ fn get_locales_dir() -> Option<PathBuf> {
|
||||
pub fn get_supported_languages() -> Vec<String> {
|
||||
let mut languages = Vec::new();
|
||||
|
||||
if let Some(locales_dir) = get_locales_dir() {
|
||||
if let Ok(entries) = fs::read_dir(locales_dir) {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if let Some(lang) = file_name.strip_suffix(".json") {
|
||||
languages.push(lang.to_string());
|
||||
}
|
||||
}
|
||||
if let Some(locales_dir) = get_locales_dir()
|
||||
&& let Ok(entries) = fs::read_dir(locales_dir)
|
||||
{
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str()
|
||||
&& let Some(lang) = file_name.strip_suffix(".json")
|
||||
{
|
||||
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() {
|
||||
for lang in get_supported_languages() {
|
||||
let file_path = locales_dir.join(format!("{lang}.json"));
|
||||
if let Ok(content) = fs::read_to_string(file_path) {
|
||||
if let Ok(json) = serde_json::from_str(&content) {
|
||||
translations.insert(lang.to_string(), json);
|
||||
}
|
||||
if let Ok(content) = fs::read_to_string(file_path)
|
||||
&& let Ok(json) = serde_json::from_str(&content)
|
||||
{
|
||||
translations.insert(lang.to_string(), json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,14 +76,13 @@ pub async fn t(key: &str) -> String {
|
||||
return text.to_string();
|
||||
}
|
||||
|
||||
if current_lang != DEFAULT_LANGUAGE {
|
||||
if let Some(text) = TRANSLATIONS
|
||||
if current_lang != DEFAULT_LANGUAGE
|
||||
&& let Some(text) = TRANSLATIONS
|
||||
.get(DEFAULT_LANGUAGE)
|
||||
.and_then(|trans| trans.get(&key))
|
||||
.and_then(|val| val.as_str())
|
||||
{
|
||||
return text.to_string();
|
||||
}
|
||||
{
|
||||
return text.to_string();
|
||||
}
|
||||
|
||||
key
|
||||
|
||||
@@ -296,52 +296,52 @@ async fn ensure_directories() -> Result<()> {
|
||||
|
||||
/// 初始化配置文件
|
||||
async fn initialize_config_files() -> Result<()> {
|
||||
if let Ok(path) = dirs::clash_path() {
|
||||
if !path.exists() {
|
||||
let template = IClashTemp::template().0;
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created clash config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
if let Ok(path) = dirs::clash_path()
|
||||
&& !path.exists()
|
||||
{
|
||||
let template = IClashTemp::template().0;
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created clash config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
if let Ok(path) = dirs::verge_path() {
|
||||
if !path.exists() {
|
||||
let template = IVerge::template();
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created verge config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
if let Ok(path) = dirs::verge_path()
|
||||
&& !path.exists()
|
||||
{
|
||||
let template = IVerge::template();
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created verge config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
if let Ok(path) = dirs::profiles_path() {
|
||||
if !path.exists() {
|
||||
let template = IProfiles::template();
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created profiles config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
if let Ok(path) = dirs::profiles_path()
|
||||
&& !path.exists()
|
||||
{
|
||||
let template = IProfiles::template();
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Setup,
|
||||
true,
|
||||
"Created profiles config at {:?}",
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
// 验证并修正verge配置
|
||||
@@ -459,7 +459,7 @@ pub async fn init_resources() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn init_scheme() -> Result<()> {
|
||||
use tauri::utils::platform::current_exe;
|
||||
use winreg::{enums::*, RegKey};
|
||||
use winreg::{RegKey, enums::*};
|
||||
|
||||
let app_exe = current_exe()?;
|
||||
let app_exe = dunce::canonicalize(app_exe)?;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use anyhow::Result;
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
use isahc::prelude::*;
|
||||
use isahc::{HttpClient, config::SslOption};
|
||||
use isahc::{
|
||||
config::RedirectPolicy,
|
||||
http::{
|
||||
header::{HeaderMap, HeaderValue, USER_AGENT},
|
||||
StatusCode, Uri,
|
||||
header::{HeaderMap, HeaderValue, USER_AGENT},
|
||||
},
|
||||
};
|
||||
use isahc::{config::SslOption, HttpClient};
|
||||
use std::time::{Duration, Instant};
|
||||
use sysproxy::Sysproxy;
|
||||
use tauri::Url;
|
||||
@@ -88,10 +88,11 @@ impl NetworkManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some((time, _)) = &*last_error_guard {
|
||||
if time.elapsed() < Duration::from_secs(30) && count > 2 {
|
||||
return true;
|
||||
}
|
||||
if let Some((time, _)) = &*last_error_guard
|
||||
&& time.elapsed() < Duration::from_secs(30)
|
||||
&& count > 2
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
@@ -113,7 +114,8 @@ impl NetworkManager {
|
||||
) -> Result<HttpClient> {
|
||||
let proxy_uri_clone = proxy_uri.clone();
|
||||
let headers_clone = default_headers.clone();
|
||||
let client = {
|
||||
|
||||
{
|
||||
let mut builder = HttpClient::builder();
|
||||
|
||||
builder = match proxy_uri_clone {
|
||||
@@ -136,9 +138,7 @@ impl NetworkManager {
|
||||
builder = builder.redirect_policy(RedirectPolicy::Follow);
|
||||
|
||||
Ok(builder.build()?)
|
||||
};
|
||||
|
||||
client
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_request(
|
||||
@@ -200,15 +200,15 @@ impl NetworkManager {
|
||||
let parsed = Url::parse(url)?;
|
||||
let mut extra_headers = HeaderMap::new();
|
||||
|
||||
if !parsed.username().is_empty() {
|
||||
if let Some(pass) = parsed.password() {
|
||||
let auth_str = format!("{}:{}", parsed.username(), pass);
|
||||
let encoded = general_purpose::STANDARD.encode(auth_str);
|
||||
extra_headers.insert(
|
||||
"Authorization",
|
||||
HeaderValue::from_str(&format!("Basic {}", encoded))?,
|
||||
);
|
||||
}
|
||||
if !parsed.username().is_empty()
|
||||
&& let Some(pass) = parsed.password()
|
||||
{
|
||||
let auth_str = format!("{}:{}", parsed.username(), pass);
|
||||
let encoded = general_purpose::STANDARD.encode(auth_str);
|
||||
extra_headers.insert(
|
||||
"Authorization",
|
||||
HeaderValue::from_str(&format!("Basic {}", encoded))?,
|
||||
);
|
||||
}
|
||||
|
||||
let clean_url = {
|
||||
|
||||
@@ -3,7 +3,7 @@ use tauri::AppHandle;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, hotkey::Hotkey, sysopt, tray::Tray, CoreManager, Timer},
|
||||
core::{CoreManager, Timer, handle, hotkey::Hotkey, sysopt, tray::Tray},
|
||||
logging, logging_error,
|
||||
module::lightweight::auto_lightweight_mode_init,
|
||||
process::AsyncHandler,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{Result, bail};
|
||||
use percent_encoding::percent_decode_str;
|
||||
use tauri::Url;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use tokio::sync::Notify;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
utils::{
|
||||
logging::Type,
|
||||
resolve::{
|
||||
ui::{get_ui_ready, update_ui_ready_stage, wait_for_ui_ready, UiReadyStage},
|
||||
ui::{UiReadyStage, get_ui_ready, update_ui_ready_stage, wait_for_ui_ready},
|
||||
window_script::{INITIAL_LOADING_OVERLAY, WINDOW_INITIAL_SCRIPT},
|
||||
},
|
||||
},
|
||||
@@ -34,22 +34,22 @@ fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
|
||||
|
||||
/// 检查是否已存在窗口,如果存在则显示并返回 true
|
||||
fn check_existing_window(is_show: bool) -> Option<bool> {
|
||||
if let Some(app_handle) = handle::Handle::global().app_handle() {
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
|
||||
if is_show {
|
||||
if window.is_minimized().unwrap_or(false) {
|
||||
logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化");
|
||||
let _ = window.unminimize();
|
||||
}
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
handle::Handle::global().set_activation_policy_regular();
|
||||
if let Some(app_handle) = handle::Handle::global().app_handle()
|
||||
&& let Some(window) = app_handle.get_webview_window("main")
|
||||
{
|
||||
logging!(info, Type::Window, true, "主窗口已存在,将显示现有窗口");
|
||||
if is_show {
|
||||
if window.is_minimized().unwrap_or(false) {
|
||||
logging!(info, Type::Window, true, "窗口已最小化,正在取消最小化");
|
||||
let _ = window.unminimize();
|
||||
}
|
||||
return Some(true);
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
handle::Handle::global().set_activation_policy_regular();
|
||||
}
|
||||
return Some(true);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use super::resolve;
|
||||
use crate::{
|
||||
config::{Config, IVerge, DEFAULT_PAC},
|
||||
config::{Config, DEFAULT_PAC, IVerge},
|
||||
logging_error,
|
||||
process::AsyncHandler,
|
||||
utils::logging::Type,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use anyhow::{Result, bail};
|
||||
use port_scanner::local_port_available;
|
||||
use warp::Filter;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user