refactor(Draft): Replace latest() with latest_ref() and data() with data_mut() in multiple files for improved mutability handling and consistency across the codebase (#3987)
* feat: add benchmarking for draft operations and new draft management structure * Refactor Config Access: Replace `latest()` with `latest_ref()` and `data()` with `data_mut()` in multiple files for improved mutability handling and consistency across the codebase. * refactor: remove DraftNew implementation and related benchmarks for cleaner codebase
This commit is contained in:
157
src-tauri/Cargo.lock
generated
157
src-tauri/Cargo.lock
generated
@@ -119,6 +119,18 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anes"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
@@ -959,6 +971,12 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cast"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.27"
|
version = "1.2.27"
|
||||||
@@ -1024,6 +1042,33 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@@ -1034,6 +1079,31 @@ dependencies = [
|
|||||||
"inout",
|
"inout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@@ -1044,6 +1114,7 @@ dependencies = [
|
|||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"boa_engine",
|
"boa_engine",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"criterion",
|
||||||
"dashmap 7.0.0-rc2",
|
"dashmap 7.0.0-rc2",
|
||||||
"deelevate",
|
"deelevate",
|
||||||
"delay_timer",
|
"delay_timer",
|
||||||
@@ -1314,6 +1385,39 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bf7af66b0989381bd0be551bd7cc91912a655a58c6918420c9527b1fd8b4679"
|
||||||
|
dependencies = [
|
||||||
|
"anes",
|
||||||
|
"cast",
|
||||||
|
"ciborium",
|
||||||
|
"clap",
|
||||||
|
"criterion-plot",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"num-traits",
|
||||||
|
"oorandom",
|
||||||
|
"plotters",
|
||||||
|
"rayon",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tinytemplate",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion-plot"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||||
|
dependencies = [
|
||||||
|
"cast",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cron_clock"
|
name = "cron_clock"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -3470,6 +3574,15 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -4608,6 +4721,12 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oorandom"
|
||||||
|
version = "11.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -5077,6 +5196,34 @@ dependencies = [
|
|||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"plotters-backend",
|
||||||
|
"plotters-svg",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-backend"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-svg"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||||
|
dependencies = [
|
||||||
|
"plotters-backend",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.16"
|
version = "0.17.16"
|
||||||
@@ -7524,6 +7671,16 @@ dependencies = [
|
|||||||
"zerovec 0.11.2",
|
"zerovec 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinytemplate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|||||||
@@ -139,7 +139,12 @@ name = "app_lib"
|
|||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
criterion = "0.6.0"
|
||||||
tempfile = "3.20.0"
|
tempfile = "3.20.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["src_crates/crate_mihomo_api"]
|
members = ["src_crates/crate_mihomo_api"]
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "draft_benchmark"
|
||||||
|
harness = false
|
||||||
|
|||||||
91
src-tauri/benches/draft_benchmark.rs
Normal file
91
src-tauri/benches/draft_benchmark.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
use std::hint::black_box;
|
||||||
|
|
||||||
|
// 业务模型 & Draft
|
||||||
|
use app_lib::config::Draft as DraftNew;
|
||||||
|
use app_lib::config::IVerge;
|
||||||
|
|
||||||
|
// fn bench_apply_old(c: &mut Criterion) {
|
||||||
|
// c.bench_function("apply_draft_old", |b| {
|
||||||
|
// b.iter(|| {
|
||||||
|
// let verge = Box::new(IVerge {
|
||||||
|
// enable_auto_launch: Some(true),
|
||||||
|
// enable_tun_mode: Some(false),
|
||||||
|
// ..Default::default()
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let draft = DraftOld::from(black_box(verge));
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let mut d = draft.draft_mut();
|
||||||
|
// d.enable_auto_launch = Some(false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let _ = draft.apply();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn bench_discard_old(c: &mut Criterion) {
|
||||||
|
// c.bench_function("discard_draft_old", |b| {
|
||||||
|
// b.iter(|| {
|
||||||
|
// let verge = Box::new(IVerge::default());
|
||||||
|
// let draft = DraftOld::from(black_box(verge));
|
||||||
|
|
||||||
|
// {
|
||||||
|
// let mut d = draft.draft_mut();
|
||||||
|
// d.enable_auto_launch = Some(false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let _ = draft.discard();
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// 基准:修改草稿并 apply()
|
||||||
|
fn bench_apply_new(c: &mut Criterion) {
|
||||||
|
c.bench_function("apply_draft_new", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let verge = Box::new(IVerge {
|
||||||
|
enable_auto_launch: Some(true),
|
||||||
|
enable_tun_mode: Some(false),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let draft = DraftNew::from(black_box(verge));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = draft.apply();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 基准:修改草稿并 discard()
|
||||||
|
fn bench_discard_new(c: &mut Criterion) {
|
||||||
|
c.bench_function("discard_draft_new", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let verge = Box::new(IVerge::default());
|
||||||
|
let draft = DraftNew::from(black_box(verge));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = draft.discard();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(
|
||||||
|
benches,
|
||||||
|
// bench_apply_old,
|
||||||
|
// bench_discard_old,
|
||||||
|
bench_apply_new,
|
||||||
|
bench_discard_new
|
||||||
|
);
|
||||||
|
criterion_main!(benches);
|
||||||
@@ -14,7 +14,7 @@ pub fn copy_clash_env() -> CmdResult {
|
|||||||
/// 获取Clash信息
|
/// 获取Clash信息
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_clash_info() -> CmdResult<ClashInfo> {
|
pub fn get_clash_info() -> CmdResult<ClashInfo> {
|
||||||
Ok(Config::clash().latest().get_client_info())
|
Ok(Config::clash().latest_ref().get_client_info())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 修改Clash配置
|
/// 修改Clash配置
|
||||||
@@ -173,7 +173,7 @@ pub fn apply_dns_config(apply: bool) -> CmdResult {
|
|||||||
// 重新生成配置,确保DNS配置被正确应用
|
// 重新生成配置,确保DNS配置被正确应用
|
||||||
// 这里不调用patch_clash以避免将DNS配置写入config.yaml
|
// 这里不调用patch_clash以避免将DNS配置写入config.yaml
|
||||||
Config::runtime()
|
Config::runtime()
|
||||||
.latest()
|
.draft_mut()
|
||||||
.patch_config(patch_config.clone());
|
.patch_config(patch_config.clone());
|
||||||
|
|
||||||
// 首先重新生成配置
|
// 首先重新生成配置
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub async fn get_profiles() -> CmdResult<IProfiles> {
|
|||||||
Duration::from_millis(500),
|
Duration::from_millis(500),
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let latest = profiles.latest();
|
let latest = profiles.latest_ref();
|
||||||
IProfiles {
|
IProfiles {
|
||||||
current: latest.current.clone(),
|
current: latest.current.clone(),
|
||||||
items: latest.items.clone(),
|
items: latest.items.clone(),
|
||||||
@@ -66,7 +66,7 @@ pub async fn get_profiles() -> CmdResult<IProfiles> {
|
|||||||
Duration::from_secs(2),
|
Duration::from_secs(2),
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let data = profiles.data();
|
let data = profiles.latest_ref();
|
||||||
IProfiles {
|
IProfiles {
|
||||||
current: data.current.clone(),
|
current: data.current.clone(),
|
||||||
items: data.items.clone(),
|
items: data.items.clone(),
|
||||||
@@ -130,20 +130,20 @@ pub async fn enhance_profiles() -> CmdResult {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
|
pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
|
||||||
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
|
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
|
||||||
wrap_err!(Config::profiles().data().append_item(item))
|
wrap_err!(Config::profiles().data_mut().append_item(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重新排序配置文件
|
/// 重新排序配置文件
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
|
pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
|
||||||
wrap_err!(Config::profiles().data().reorder(active_id, over_id))
|
wrap_err!(Config::profiles().data_mut().reorder(active_id, over_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 创建配置文件
|
/// 创建配置文件
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
|
pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
|
||||||
let item = wrap_err!(PrfItem::from(item, file_data).await)?;
|
let item = wrap_err!(PrfItem::from(item, file_data).await)?;
|
||||||
wrap_err!(Config::profiles().data().append_item(item))
|
wrap_err!(Config::profiles().data_mut().append_item(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新配置文件
|
/// 更新配置文件
|
||||||
@@ -155,10 +155,10 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
|
|||||||
/// 删除配置文件
|
/// 删除配置文件
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn delete_profile(index: String) -> CmdResult {
|
pub async fn delete_profile(index: String) -> CmdResult {
|
||||||
let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
|
let should_update = wrap_err!({ Config::profiles().data_mut().delete_item(index) })?;
|
||||||
|
|
||||||
// 删除后自动清理冗余文件
|
// 删除后自动清理冗余文件
|
||||||
let _ = Config::profiles().latest().auto_cleanup();
|
let _ = Config::profiles().latest_ref().auto_cleanup();
|
||||||
|
|
||||||
if should_update {
|
if should_update {
|
||||||
wrap_err!(CoreManager::global().update_config().await)?;
|
wrap_err!(CoreManager::global().update_config().await)?;
|
||||||
@@ -226,7 +226,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存当前配置,以便在验证失败时恢复
|
// 保存当前配置,以便在验证失败时恢复
|
||||||
let current_profile = Config::profiles().latest().current.clone();
|
let current_profile = Config::profiles().latest_ref().current.clone();
|
||||||
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
|
logging!(info, Type::Cmd, true, "当前配置: {:?}", current_profile);
|
||||||
|
|
||||||
// 如果要切换配置,先检查目标配置文件是否有语法错误
|
// 如果要切换配置,先检查目标配置文件是否有语法错误
|
||||||
@@ -237,7 +237,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
// 获取目标配置文件路径
|
// 获取目标配置文件路径
|
||||||
let config_file_result = {
|
let config_file_result = {
|
||||||
let profiles_config = Config::profiles();
|
let profiles_config = Config::profiles();
|
||||||
let profiles_data = profiles_config.latest();
|
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 {
|
||||||
@@ -375,7 +375,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
|
|
||||||
let current_value = profiles.current.clone();
|
let current_value = profiles.current.clone();
|
||||||
|
|
||||||
let _ = Config::profiles().draft().patch_config(profiles);
|
let _ = Config::profiles().draft_mut().patch_config(profiles);
|
||||||
|
|
||||||
// 在调用内核前再次验证请求有效性
|
// 在调用内核前再次验证请求有效性
|
||||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||||
@@ -451,7 +451,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存配置文件
|
// 保存配置文件
|
||||||
if let Err(e) = Config::profiles().data().save_file() {
|
if let Err(e) = Config::profiles().data_mut().save_file() {
|
||||||
log::warn!(target: "app", "异步保存配置文件失败: {e}");
|
log::warn!(target: "app", "异步保存配置文件失败: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -490,11 +490,15 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
items: None,
|
items: None,
|
||||||
};
|
};
|
||||||
// 静默恢复,不触发验证
|
// 静默恢复,不触发验证
|
||||||
wrap_err!({ Config::profiles().draft().patch_config(restore_profiles) })?;
|
wrap_err!({
|
||||||
|
Config::profiles()
|
||||||
|
.draft_mut()
|
||||||
|
.patch_config(restore_profiles)
|
||||||
|
})?;
|
||||||
Config::profiles().apply();
|
Config::profiles().apply();
|
||||||
|
|
||||||
crate::process::AsyncHandler::spawn(|| async move {
|
crate::process::AsyncHandler::spawn(|| async move {
|
||||||
if let Err(e) = Config::profiles().data().save_file() {
|
if let Err(e) = Config::profiles().data_mut().save_file() {
|
||||||
log::warn!(target: "app", "异步保存恢复配置文件失败: {e}");
|
log::warn!(target: "app", "异步保存恢复配置文件失败: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -551,7 +555,11 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
|||||||
current: Some(prev_profile),
|
current: Some(prev_profile),
|
||||||
items: None,
|
items: None,
|
||||||
};
|
};
|
||||||
wrap_err!({ Config::profiles().draft().patch_config(restore_profiles) })?;
|
wrap_err!({
|
||||||
|
Config::profiles()
|
||||||
|
.draft_mut()
|
||||||
|
.patch_config(restore_profiles)
|
||||||
|
})?;
|
||||||
Config::profiles().apply();
|
Config::profiles().apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +592,7 @@ pub async fn patch_profiles_config_by_profile_index(
|
|||||||
pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
||||||
// 保存修改前检查是否有更新 update_interval
|
// 保存修改前检查是否有更新 update_interval
|
||||||
let update_interval_changed =
|
let update_interval_changed =
|
||||||
if let Ok(old_profile) = Config::profiles().latest().get_item(&index) {
|
if let Ok(old_profile) = Config::profiles().latest_ref().get_item(&index) {
|
||||||
let old_interval = old_profile.option.as_ref().and_then(|o| o.update_interval);
|
let old_interval = old_profile.option.as_ref().and_then(|o| o.update_interval);
|
||||||
let new_interval = profile.option.as_ref().and_then(|o| o.update_interval);
|
let new_interval = profile.option.as_ref().and_then(|o| o.update_interval);
|
||||||
old_interval != new_interval
|
old_interval != new_interval
|
||||||
@@ -593,7 +601,9 @@ pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 保存修改
|
// 保存修改
|
||||||
wrap_err!(Config::profiles().data().patch_item(index.clone(), profile))?;
|
wrap_err!(Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.patch_item(index.clone(), profile))?;
|
||||||
|
|
||||||
// 如果更新间隔变更,异步刷新定时器
|
// 如果更新间隔变更,异步刷新定时器
|
||||||
if update_interval_changed {
|
if update_interval_changed {
|
||||||
@@ -616,7 +626,7 @@ pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
|
pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
|
||||||
let file = {
|
let file = {
|
||||||
wrap_err!(Config::profiles().latest().get_item(&index))?
|
wrap_err!(Config::profiles().latest_ref().get_item(&index))?
|
||||||
.file
|
.file
|
||||||
.clone()
|
.clone()
|
||||||
.ok_or("the file field is null")
|
.ok_or("the file field is null")
|
||||||
@@ -634,7 +644,7 @@ pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn read_profile_file(index: String) -> CmdResult<String> {
|
pub fn read_profile_file(index: String) -> CmdResult<String> {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest_ref();
|
||||||
let item = wrap_err!(profiles.get_item(&index))?;
|
let item = wrap_err!(profiles.get_item(&index))?;
|
||||||
let data = wrap_err!(item.read_file())?;
|
let data = wrap_err!(item.read_file())?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ use std::collections::HashMap;
|
|||||||
/// 获取运行时配置
|
/// 获取运行时配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
|
pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
|
||||||
Ok(Config::runtime().latest().config.clone())
|
Ok(Config::runtime().latest_ref().config.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取运行时YAML配置
|
/// 获取运行时YAML配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_runtime_yaml() -> CmdResult<String> {
|
pub fn get_runtime_yaml() -> CmdResult<String> {
|
||||||
let runtime = Config::runtime();
|
let runtime = Config::runtime();
|
||||||
let runtime = runtime.latest();
|
let runtime = runtime.latest_ref();
|
||||||
let config = runtime.config.as_ref();
|
let config = runtime.config.as_ref();
|
||||||
wrap_err!(config
|
wrap_err!(config
|
||||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||||
@@ -26,11 +26,11 @@ pub fn get_runtime_yaml() -> CmdResult<String> {
|
|||||||
/// 获取运行时存在的键
|
/// 获取运行时存在的键
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
|
pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
|
||||||
Ok(Config::runtime().latest().exists_keys.clone())
|
Ok(Config::runtime().latest_ref().exists_keys.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取运行时日志
|
/// 获取运行时日志
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
|
pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
|
||||||
Ok(Config::runtime().latest().chain_logs.clone())
|
Ok(Config::runtime().latest_ref().chain_logs.clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
|||||||
// 在异步操作前完成所有文件操作
|
// 在异步操作前完成所有文件操作
|
||||||
let (file_path, original_content, is_merge_file) = {
|
let (file_path, original_content, is_merge_file) = {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles_guard = profiles.latest();
|
let profiles_guard = profiles.latest_ref();
|
||||||
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
||||||
// 确定是否为merge类型文件
|
// 确定是否为merge类型文件
|
||||||
let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge");
|
let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge");
|
||||||
|
|||||||
@@ -4,12 +4,9 @@ use crate::{config::*, feat, wrap_err};
|
|||||||
/// 获取Verge配置
|
/// 获取Verge配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_verge_config() -> CmdResult<IVergeResponse> {
|
pub fn get_verge_config() -> CmdResult<IVergeResponse> {
|
||||||
let verge_data = {
|
let verge = Config::verge();
|
||||||
let verge = Config::verge();
|
let verge_data = verge.latest_ref().clone();
|
||||||
let data = verge.data();
|
Ok(IVergeResponse::from(*verge_data))
|
||||||
(**data).clone()
|
|
||||||
};
|
|
||||||
Ok(IVergeResponse::from(verge_data))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 修改Verge配置
|
/// 修改Verge配置
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ pub async fn save_webdav_config(url: String, username: String, password: String)
|
|||||||
webdav_password: Some(password),
|
webdav_password: Some(password),
|
||||||
..IVerge::default()
|
..IVerge::default()
|
||||||
};
|
};
|
||||||
Config::verge().draft().patch_config(patch.clone());
|
Config::verge().draft_mut().patch_config(patch.clone());
|
||||||
Config::verge().apply();
|
Config::verge().apply();
|
||||||
Config::verge()
|
Config::verge()
|
||||||
.data()
|
.latest_ref()
|
||||||
.save_file()
|
.save_file()
|
||||||
.map_err(|err| err.to_string())?;
|
.map_err(|err| err.to_string())?;
|
||||||
core::backup::WebDavClient::global().reset();
|
core::backup::WebDavClient::global().reset();
|
||||||
|
|||||||
@@ -52,20 +52,24 @@ impl Config {
|
|||||||
/// 初始化订阅
|
/// 初始化订阅
|
||||||
pub async fn init_config() -> Result<()> {
|
pub async fn init_config() -> Result<()> {
|
||||||
if Self::profiles()
|
if Self::profiles()
|
||||||
.data()
|
.latest_ref()
|
||||||
.get_item(&"Merge".to_string())
|
.get_item(&"Merge".to_string())
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
let merge_item = PrfItem::from_merge(Some("Merge".to_string()))?;
|
let merge_item = PrfItem::from_merge(Some("Merge".to_string()))?;
|
||||||
Self::profiles().data().append_item(merge_item.clone())?;
|
Self::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(merge_item.clone())?;
|
||||||
}
|
}
|
||||||
if Self::profiles()
|
if Self::profiles()
|
||||||
.data()
|
.latest_ref()
|
||||||
.get_item(&"Script".to_string())
|
.get_item(&"Script".to_string())
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
let script_item = PrfItem::from_script(Some("Script".to_string()))?;
|
let script_item = PrfItem::from_script(Some("Script".to_string()))?;
|
||||||
Self::profiles().data().append_item(script_item.clone())?;
|
Self::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(script_item.clone())?;
|
||||||
}
|
}
|
||||||
// 生成运行时配置
|
// 生成运行时配置
|
||||||
if let Err(err) = Self::generate().await {
|
if let Err(err) = Self::generate().await {
|
||||||
@@ -135,7 +139,7 @@ impl Config {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let runtime = Config::runtime();
|
let runtime = Config::runtime();
|
||||||
let runtime = runtime.latest();
|
let runtime = runtime.latest_ref();
|
||||||
let config = runtime
|
let config = runtime
|
||||||
.config
|
.config
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -149,7 +153,7 @@ impl Config {
|
|||||||
pub async fn generate() -> Result<()> {
|
pub async fn generate() -> Result<()> {
|
||||||
let (config, exists_keys, logs) = enhance::enhance().await;
|
let (config, exists_keys, logs) = enhance::enhance().await;
|
||||||
|
|
||||||
*Config::runtime().draft() = Box::new(IRuntime {
|
*Config::runtime().draft_mut() = Box::new(IRuntime {
|
||||||
config: Some(config),
|
config: Some(config),
|
||||||
exists_keys,
|
exists_keys,
|
||||||
chain_logs: logs,
|
chain_logs: logs,
|
||||||
|
|||||||
@@ -1,135 +1,147 @@
|
|||||||
use super::{IClashTemp, IProfiles, IRuntime, IVerge};
|
|
||||||
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::{
|
||||||
|
MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard,
|
||||||
|
RwLockUpgradableReadGuard, RwLockWriteGuard,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Draft<T: Clone + ToOwned> {
|
pub struct Draft<T: Clone + ToOwned> {
|
||||||
inner: Arc<Mutex<(T, Option<T>)>>,
|
inner: Arc<RwLock<(T, Option<T>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! draft_define {
|
impl<T: Clone + ToOwned> From<T> for Draft<T> {
|
||||||
($id: ident) => {
|
fn from(data: T) -> Self {
|
||||||
impl From<$id> for Draft<$id> {
|
Self {
|
||||||
fn from(data: $id) -> Self {
|
inner: Arc::new(RwLock::new((data, None))),
|
||||||
Draft {
|
|
||||||
inner: Arc::new(Mutex::new((data, None))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
impl Draft<Box<$id>> {
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn data(&self) -> MappedMutexGuard<Box<$id>> {
|
|
||||||
MutexGuard::map(self.inner.lock(), |guard| &mut guard.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn latest(&self) -> MappedMutexGuard<Box<$id>> {
|
|
||||||
MutexGuard::map(self.inner.lock(), |inner| {
|
|
||||||
if inner.1.is_none() {
|
|
||||||
&mut inner.0
|
|
||||||
} else {
|
|
||||||
inner.1.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draft(&self) -> MappedMutexGuard<Box<$id>> {
|
|
||||||
MutexGuard::map(self.inner.lock(), |inner| {
|
|
||||||
if inner.1.is_none() {
|
|
||||||
inner.1 = Some(inner.0.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
inner.1.as_mut().unwrap()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply(&self) -> Option<Box<$id>> {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
|
|
||||||
match inner.1.take() {
|
|
||||||
Some(draft) => {
|
|
||||||
let old_value = inner.0.to_owned();
|
|
||||||
inner.0 = draft.to_owned();
|
|
||||||
Some(old_value)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn discard(&self) -> Option<Box<$id>> {
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.1.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Box<$id>> for Draft<Box<$id>> {
|
|
||||||
fn from(data: Box<$id>) -> Self {
|
|
||||||
Draft {
|
|
||||||
inner: Arc::new(Mutex::new((data, None))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draft_define!(IClash);
|
/// Implements draft management for `Box<T>`, allowing for safe concurrent editing and committing of draft data.
|
||||||
draft_define!(IClashTemp);
|
/// # Type Parameters
|
||||||
draft_define!(IProfiles);
|
/// - `T`: The underlying data type, which must implement `Clone` and `ToOwned`.
|
||||||
draft_define!(IRuntime);
|
///
|
||||||
draft_define!(IVerge);
|
/// # Methods
|
||||||
|
/// - `data_mut`: Returns a mutable reference to the committed data.
|
||||||
|
/// - `data_ref`: Returns an immutable reference to the committed data.
|
||||||
|
/// - `draft_mut`: Creates or retrieves a mutable reference to the draft data, cloning the committed data if no draft exists.
|
||||||
|
/// - `latest_ref`: Returns an immutable reference to the draft data if it exists, otherwise to the committed data.
|
||||||
|
/// - `apply`: Commits the draft data, replacing the committed data and returning the old committed value if a draft existed.
|
||||||
|
/// - `discard`: Discards the draft data and returns it if it existed.
|
||||||
|
impl<T: Clone + ToOwned> Draft<Box<T>> {
|
||||||
|
/// 可写正式数据
|
||||||
|
pub fn data_mut(&self) -> MappedRwLockWriteGuard<'_, Box<T>> {
|
||||||
|
RwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 返回正式数据的只读视图(不包含草稿)
|
||||||
|
pub fn data_ref(&self) -> MappedRwLockReadGuard<'_, Box<T>> {
|
||||||
|
RwLockReadGuard::map(self.inner.read(), |inner| &inner.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 创建或获取草稿并返回可写引用
|
||||||
|
pub fn draft_mut(&self) -> MappedRwLockWriteGuard<'_, Box<T>> {
|
||||||
|
let guard = self.inner.upgradable_read();
|
||||||
|
if guard.1.is_none() {
|
||||||
|
let mut guard = RwLockUpgradableReadGuard::upgrade(guard);
|
||||||
|
guard.1 = Some(guard.0.clone());
|
||||||
|
return RwLockWriteGuard::map(guard, |inner| inner.1.as_mut().unwrap());
|
||||||
|
}
|
||||||
|
// 已存在草稿,升级为写锁映射
|
||||||
|
RwLockWriteGuard::map(RwLockUpgradableReadGuard::upgrade(guard), |inner| {
|
||||||
|
inner.1.as_mut().unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 零拷贝只读视图:返回草稿(若存在)或正式值
|
||||||
|
pub fn latest_ref(&self) -> MappedRwLockReadGuard<'_, Box<T>> {
|
||||||
|
RwLockReadGuard::map(self.inner.read(), |inner| {
|
||||||
|
inner.1.as_ref().unwrap_or(&inner.0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 提交草稿,返回旧正式数据
|
||||||
|
pub fn apply(&self) -> Option<Box<T>> {
|
||||||
|
let mut inner = self.inner.write();
|
||||||
|
inner
|
||||||
|
.1
|
||||||
|
.take()
|
||||||
|
.map(|draft| std::mem::replace(&mut inner.0, draft))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 丢弃草稿,返回被丢弃的草稿
|
||||||
|
pub fn discard(&self) -> Option<Box<T>> {
|
||||||
|
self.inner.write().1.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_draft_box() {
|
fn test_draft_box() {
|
||||||
|
use super::IVerge;
|
||||||
|
|
||||||
|
// 1. 创建 Draft<Box<IVerge>>
|
||||||
let verge = Box::new(IVerge {
|
let verge = Box::new(IVerge {
|
||||||
enable_auto_launch: Some(true),
|
enable_auto_launch: Some(true),
|
||||||
enable_tun_mode: Some(false),
|
enable_tun_mode: Some(false),
|
||||||
..IVerge::default()
|
..IVerge::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
let draft = Draft::from(verge);
|
let draft = Draft::from(verge);
|
||||||
|
|
||||||
assert_eq!(draft.data().enable_auto_launch, Some(true));
|
// 2. 读取正式数据(data_mut)
|
||||||
assert_eq!(draft.data().enable_tun_mode, Some(false));
|
|
||||||
|
|
||||||
assert_eq!(draft.draft().enable_auto_launch, Some(true));
|
|
||||||
assert_eq!(draft.draft().enable_tun_mode, Some(false));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut d = draft.draft();
|
let data = draft.data_mut();
|
||||||
|
assert_eq!(data.enable_auto_launch, Some(true));
|
||||||
|
assert_eq!(data.enable_tun_mode, Some(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 初次获取草稿(draft_mut 会自动 clone 一份)
|
||||||
|
{
|
||||||
|
let draft_view = draft.draft_mut();
|
||||||
|
assert_eq!(draft_view.enable_auto_launch, Some(true));
|
||||||
|
assert_eq!(draft_view.enable_tun_mode, Some(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 修改草稿
|
||||||
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
d.enable_auto_launch = Some(false);
|
d.enable_auto_launch = Some(false);
|
||||||
d.enable_tun_mode = Some(true);
|
d.enable_tun_mode = Some(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(draft.data().enable_auto_launch, Some(true));
|
// 正式数据未变
|
||||||
assert_eq!(draft.data().enable_tun_mode, Some(false));
|
assert_eq!(draft.data_mut().enable_auto_launch, Some(true));
|
||||||
|
assert_eq!(draft.data_mut().enable_tun_mode, Some(false));
|
||||||
assert_eq!(draft.draft().enable_auto_launch, Some(false));
|
|
||||||
assert_eq!(draft.draft().enable_tun_mode, Some(true));
|
|
||||||
|
|
||||||
assert_eq!(draft.latest().enable_auto_launch, Some(false));
|
|
||||||
assert_eq!(draft.latest().enable_tun_mode, Some(true));
|
|
||||||
|
|
||||||
assert!(draft.apply().is_some());
|
|
||||||
assert!(draft.apply().is_none());
|
|
||||||
|
|
||||||
assert_eq!(draft.data().enable_auto_launch, Some(false));
|
|
||||||
assert_eq!(draft.data().enable_tun_mode, Some(true));
|
|
||||||
|
|
||||||
assert_eq!(draft.draft().enable_auto_launch, Some(false));
|
|
||||||
assert_eq!(draft.draft().enable_tun_mode, Some(true));
|
|
||||||
|
|
||||||
|
// 草稿已变
|
||||||
{
|
{
|
||||||
let mut d = draft.draft();
|
let latest = draft.latest_ref();
|
||||||
d.enable_auto_launch = Some(true);
|
assert_eq!(latest.enable_auto_launch, Some(false));
|
||||||
|
assert_eq!(latest.enable_tun_mode, Some(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(draft.data().enable_auto_launch, Some(false));
|
// 5. 提交草稿
|
||||||
assert_eq!(draft.draft().enable_auto_launch, Some(true));
|
assert!(draft.apply().is_some()); // 第一次提交应有返回
|
||||||
|
assert!(draft.apply().is_none()); // 第二次提交返回 None
|
||||||
|
|
||||||
assert!(draft.discard().is_some());
|
// 正式数据已更新
|
||||||
|
{
|
||||||
|
let data = draft.data_mut();
|
||||||
|
assert_eq!(data.enable_auto_launch, Some(false));
|
||||||
|
assert_eq!(data.enable_tun_mode, Some(true));
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(draft.data().enable_auto_launch, Some(false));
|
// 6. 新建并修改下一轮草稿
|
||||||
assert!(draft.discard().is_none());
|
{
|
||||||
|
let mut d = draft.draft_mut();
|
||||||
|
d.enable_auto_launch = Some(true);
|
||||||
|
}
|
||||||
|
assert_eq!(draft.draft_mut().enable_auto_launch, Some(true));
|
||||||
|
|
||||||
assert_eq!(draft.draft().enable_auto_launch, Some(false));
|
// 7. 丢弃草稿
|
||||||
|
assert!(draft.discard().is_some()); // 第一次丢弃返回 Some
|
||||||
|
assert!(draft.discard().is_none()); // 再次丢弃返回 None
|
||||||
|
|
||||||
|
// 8. 草稿已被丢弃,新的 draft_mut() 会重新 clone
|
||||||
|
assert_eq!(draft.draft_mut().enable_auto_launch, Some(false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,29 +186,37 @@ impl PrfItem {
|
|||||||
|
|
||||||
if merge.is_none() {
|
if merge.is_none() {
|
||||||
let merge_item = PrfItem::from_merge(None)?;
|
let merge_item = PrfItem::from_merge(None)?;
|
||||||
Config::profiles().data().append_item(merge_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(merge_item.clone())?;
|
||||||
merge = merge_item.uid;
|
merge = merge_item.uid;
|
||||||
}
|
}
|
||||||
if script.is_none() {
|
if script.is_none() {
|
||||||
let script_item = PrfItem::from_script(None)?;
|
let script_item = PrfItem::from_script(None)?;
|
||||||
Config::profiles().data().append_item(script_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(script_item.clone())?;
|
||||||
script = script_item.uid;
|
script = script_item.uid;
|
||||||
}
|
}
|
||||||
if rules.is_none() {
|
if rules.is_none() {
|
||||||
let rules_item = PrfItem::from_rules()?;
|
let rules_item = PrfItem::from_rules()?;
|
||||||
Config::profiles().data().append_item(rules_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(rules_item.clone())?;
|
||||||
rules = rules_item.uid;
|
rules = rules_item.uid;
|
||||||
}
|
}
|
||||||
if proxies.is_none() {
|
if proxies.is_none() {
|
||||||
let proxies_item = PrfItem::from_proxies()?;
|
let proxies_item = PrfItem::from_proxies()?;
|
||||||
Config::profiles()
|
Config::profiles()
|
||||||
.data()
|
.data_mut()
|
||||||
.append_item(proxies_item.clone())?;
|
.append_item(proxies_item.clone())?;
|
||||||
proxies = proxies_item.uid;
|
proxies = proxies_item.uid;
|
||||||
}
|
}
|
||||||
if groups.is_none() {
|
if groups.is_none() {
|
||||||
let groups_item = PrfItem::from_groups()?;
|
let groups_item = PrfItem::from_groups()?;
|
||||||
Config::profiles().data().append_item(groups_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(groups_item.clone())?;
|
||||||
groups = groups_item.uid;
|
groups = groups_item.uid;
|
||||||
}
|
}
|
||||||
Ok(PrfItem {
|
Ok(PrfItem {
|
||||||
@@ -366,29 +374,37 @@ impl PrfItem {
|
|||||||
|
|
||||||
if merge.is_none() {
|
if merge.is_none() {
|
||||||
let merge_item = PrfItem::from_merge(None)?;
|
let merge_item = PrfItem::from_merge(None)?;
|
||||||
Config::profiles().data().append_item(merge_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(merge_item.clone())?;
|
||||||
merge = merge_item.uid;
|
merge = merge_item.uid;
|
||||||
}
|
}
|
||||||
if script.is_none() {
|
if script.is_none() {
|
||||||
let script_item = PrfItem::from_script(None)?;
|
let script_item = PrfItem::from_script(None)?;
|
||||||
Config::profiles().data().append_item(script_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(script_item.clone())?;
|
||||||
script = script_item.uid;
|
script = script_item.uid;
|
||||||
}
|
}
|
||||||
if rules.is_none() {
|
if rules.is_none() {
|
||||||
let rules_item = PrfItem::from_rules()?;
|
let rules_item = PrfItem::from_rules()?;
|
||||||
Config::profiles().data().append_item(rules_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(rules_item.clone())?;
|
||||||
rules = rules_item.uid;
|
rules = rules_item.uid;
|
||||||
}
|
}
|
||||||
if proxies.is_none() {
|
if proxies.is_none() {
|
||||||
let proxies_item = PrfItem::from_proxies()?;
|
let proxies_item = PrfItem::from_proxies()?;
|
||||||
Config::profiles()
|
Config::profiles()
|
||||||
.data()
|
.data_mut()
|
||||||
.append_item(proxies_item.clone())?;
|
.append_item(proxies_item.clone())?;
|
||||||
proxies = proxies_item.uid;
|
proxies = proxies_item.uid;
|
||||||
}
|
}
|
||||||
if groups.is_none() {
|
if groups.is_none() {
|
||||||
let groups_item = PrfItem::from_groups()?;
|
let groups_item = PrfItem::from_groups()?;
|
||||||
Config::profiles().data().append_item(groups_item.clone())?;
|
Config::profiles()
|
||||||
|
.data_mut()
|
||||||
|
.append_item(groups_item.clone())?;
|
||||||
groups = groups_item.uid;
|
groups = groups_item.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ impl IVerge {
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
let config_draft = Config::verge();
|
let config_draft = Config::verge();
|
||||||
*config_draft.draft() = Box::new(updated_config.clone());
|
*config_draft.draft_mut() = Box::new(updated_config.clone());
|
||||||
config_draft.apply();
|
config_draft.apply();
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ impl WebDavClient {
|
|||||||
if let Some(cfg) = lock.as_ref() {
|
if let Some(cfg) = lock.as_ref() {
|
||||||
cfg.clone()
|
cfg.clone()
|
||||||
} else {
|
} else {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest_ref().clone();
|
||||||
if verge.webdav_url.is_none()
|
if verge.webdav_url.is_none()
|
||||||
|| verge.webdav_username.is_none()
|
|| verge.webdav_username.is_none()
|
||||||
|| verge.webdav_password.is_none()
|
|| verge.webdav_password.is_none()
|
||||||
|
|||||||
@@ -138,14 +138,14 @@ impl CoreManager {
|
|||||||
/// 使用默认配置
|
/// 使用默认配置
|
||||||
pub async fn use_default_config(&self, msg_type: &str, msg_content: &str) -> Result<()> {
|
pub async fn use_default_config(&self, msg_type: &str, msg_content: &str) -> Result<()> {
|
||||||
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
|
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
|
||||||
*Config::runtime().draft() = Box::new(IRuntime {
|
*Config::runtime().draft_mut() = Box::new(IRuntime {
|
||||||
config: Some(Config::clash().latest().0.clone()),
|
config: Some(Config::clash().latest_ref().0.clone()),
|
||||||
exists_keys: vec![],
|
exists_keys: vec![],
|
||||||
chain_logs: Default::default(),
|
chain_logs: Default::default(),
|
||||||
});
|
});
|
||||||
help::save_yaml(
|
help::save_yaml(
|
||||||
&runtime_path,
|
&runtime_path,
|
||||||
&Config::clash().latest().0,
|
&Config::clash().latest_ref().0,
|
||||||
Some("# Clash Verge Runtime"),
|
Some("# Clash Verge Runtime"),
|
||||||
)?;
|
)?;
|
||||||
handle::Handle::notice_message(msg_type, msg_content);
|
handle::Handle::notice_message(msg_type, msg_content);
|
||||||
@@ -247,7 +247,7 @@ impl CoreManager {
|
|||||||
config_path
|
config_path
|
||||||
);
|
);
|
||||||
|
|
||||||
let clash_core = Config::verge().latest().get_valid_clash_core();
|
let clash_core = Config::verge().latest_ref().get_valid_clash_core();
|
||||||
logging!(info, Type::Config, true, "使用内核: {}", clash_core);
|
logging!(info, Type::Config, true, "使用内核: {}", clash_core);
|
||||||
|
|
||||||
let app_handle = handle::Handle::global().app_handle().unwrap();
|
let app_handle = handle::Handle::global().app_handle().unwrap();
|
||||||
@@ -739,7 +739,7 @@ impl CoreManager {
|
|||||||
let app_handle = handle::Handle::global()
|
let app_handle = handle::Handle::global()
|
||||||
.app_handle()
|
.app_handle()
|
||||||
.ok_or(anyhow::anyhow!("failed to get app handle"))?;
|
.ok_or(anyhow::anyhow!("failed to get app handle"))?;
|
||||||
let clash_core = Config::verge().latest().get_valid_clash_core();
|
let clash_core = Config::verge().latest_ref().get_valid_clash_core();
|
||||||
let config_dir = dirs::app_home_dir()?;
|
let config_dir = dirs::app_home_dir()?;
|
||||||
|
|
||||||
let service_log_dir = dirs::app_home_dir()?.join("logs").join("service");
|
let service_log_dir = dirs::app_home_dir()?.join("logs").join("service");
|
||||||
@@ -1114,9 +1114,9 @@ impl CoreManager {
|
|||||||
return Err(error_message);
|
return Err(error_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::verge().draft().clash_core = clash_core.clone();
|
Config::verge().draft_mut().clash_core = clash_core.clone();
|
||||||
Config::verge().apply();
|
Config::verge().apply();
|
||||||
logging_error!(Type::Core, true, Config::verge().latest().save_file());
|
logging_error!(Type::Core, true, Config::verge().latest_ref().save_file());
|
||||||
|
|
||||||
let run_path = Config::generate_file(ConfigType::Run).map_err(|e| {
|
let run_path = Config::generate_file(ConfigType::Run).map_err(|e| {
|
||||||
let msg = e.to_string();
|
let msg = e.to_string();
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ impl EventDrivenProxyManager {
|
|||||||
fn get_proxy_config() -> ProxyConfig {
|
fn get_proxy_config() -> ProxyConfig {
|
||||||
let (sys_enabled, pac_enabled, guard_enabled) = {
|
let (sys_enabled, pac_enabled, guard_enabled) = {
|
||||||
let verge_config = Config::verge();
|
let verge_config = Config::verge();
|
||||||
let verge = verge_config.latest();
|
let verge = verge_config.latest_ref();
|
||||||
(
|
(
|
||||||
verge.enable_system_proxy.unwrap_or(false),
|
verge.enable_system_proxy.unwrap_or(false),
|
||||||
verge.proxy_auto_config.unwrap_or(false),
|
verge.proxy_auto_config.unwrap_or(false),
|
||||||
@@ -445,7 +445,7 @@ impl EventDrivenProxyManager {
|
|||||||
fn get_expected_pac_config() -> Autoproxy {
|
fn get_expected_pac_config() -> Autoproxy {
|
||||||
let proxy_host = {
|
let proxy_host = {
|
||||||
let verge_config = Config::verge();
|
let verge_config = Config::verge();
|
||||||
let verge = verge_config.latest();
|
let verge = verge_config.latest_ref();
|
||||||
verge
|
verge
|
||||||
.proxy_host
|
.proxy_host
|
||||||
.clone()
|
.clone()
|
||||||
@@ -459,19 +459,15 @@ impl EventDrivenProxyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_expected_sys_proxy() -> Sysproxy {
|
fn get_expected_sys_proxy() -> Sysproxy {
|
||||||
let (verge_mixed_port, proxy_host) = {
|
let verge_config = Config::verge();
|
||||||
let verge_config = Config::verge();
|
let verge = verge_config.latest_ref();
|
||||||
let verge = verge_config.latest();
|
let port = verge
|
||||||
(
|
.verge_mixed_port
|
||||||
verge.verge_mixed_port,
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
verge
|
let proxy_host = verge
|
||||||
.proxy_host
|
.proxy_host
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "127.0.0.1".to_string()),
|
.unwrap_or_else(|| "127.0.0.1".to_string());
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let port = verge_mixed_port.unwrap_or_else(|| Config::clash().data().get_mixed_port());
|
|
||||||
|
|
||||||
Sysproxy {
|
Sysproxy {
|
||||||
enable: true,
|
enable: true,
|
||||||
@@ -484,7 +480,7 @@ impl EventDrivenProxyManager {
|
|||||||
fn get_bypass_config() -> String {
|
fn get_bypass_config() -> String {
|
||||||
let (use_default, custom_bypass) = {
|
let (use_default, custom_bypass) = {
|
||||||
let verge_config = Config::verge();
|
let verge_config = Config::verge();
|
||||||
let verge = verge_config.latest();
|
let verge = verge_config.latest_ref();
|
||||||
(
|
(
|
||||||
verge.use_default_bypass.unwrap_or(true),
|
verge.use_default_bypass.unwrap_or(true),
|
||||||
verge.system_proxy_bypass.clone().unwrap_or_default(),
|
verge.system_proxy_bypass.clone().unwrap_or_default(),
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl Hotkey {
|
|||||||
|
|
||||||
pub fn init(&self) -> Result<()> {
|
pub fn init(&self) -> Result<()> {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let enable_global_hotkey = verge.latest().enable_global_hotkey.unwrap_or(true);
|
let enable_global_hotkey = verge.latest_ref().enable_global_hotkey.unwrap_or(true);
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
@@ -39,7 +39,7 @@ impl Hotkey {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hotkeys) = verge.latest().hotkeys.as_ref() {
|
if let Some(hotkeys) = verge.latest_ref().hotkeys.as_ref() {
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
Type::Hotkey,
|
Type::Hotkey,
|
||||||
@@ -252,7 +252,7 @@ impl Hotkey {
|
|||||||
logging!(debug, Type::Hotkey, "Executing function directly");
|
logging!(debug, Type::Hotkey, "Executing function directly");
|
||||||
|
|
||||||
let is_enable_global_hotkey = Config::verge()
|
let is_enable_global_hotkey = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.enable_global_hotkey
|
.enable_global_hotkey
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub struct ServiceState {
|
|||||||
impl ServiceState {
|
impl ServiceState {
|
||||||
// 获取当前的服务状态
|
// 获取当前的服务状态
|
||||||
pub fn get() -> Self {
|
pub fn get() -> Self {
|
||||||
if let Some(state) = Config::verge().latest().service_state.clone() {
|
if let Some(state) = Config::verge().latest_ref().service_state.clone() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
Self::default()
|
Self::default()
|
||||||
@@ -41,11 +41,11 @@ impl ServiceState {
|
|||||||
// 保存服务状态
|
// 保存服务状态
|
||||||
pub fn save(&self) -> Result<()> {
|
pub fn save(&self) -> Result<()> {
|
||||||
let config = Config::verge();
|
let config = Config::verge();
|
||||||
let mut latest = config.latest().clone();
|
let mut latest = config.latest_ref().clone();
|
||||||
latest.service_state = Some(self.clone());
|
latest.service_state = Some(self.clone());
|
||||||
*config.draft() = latest;
|
*config.draft_mut() = latest;
|
||||||
config.apply();
|
config.apply();
|
||||||
let result = config.latest().save_file();
|
let result = config.latest_ref().save_file();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +741,7 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
|||||||
log::info!(target:"app", "尝试使用现有服务启动核心 (IPC)");
|
log::info!(target:"app", "尝试使用现有服务启动核心 (IPC)");
|
||||||
// logging!(info, Type::Service, true, "尝试使用现有服务启动核心");
|
// logging!(info, Type::Service, true, "尝试使用现有服务启动核心");
|
||||||
|
|
||||||
let clash_core = Config::verge().latest().get_valid_clash_core();
|
let clash_core = Config::verge().latest_ref().get_valid_clash_core();
|
||||||
|
|
||||||
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||||
let clash_bin = format!("{clash_core}{bin_ext}");
|
let clash_bin = format!("{clash_core}{bin_ext}");
|
||||||
|
|||||||
@@ -29,10 +29,13 @@ 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>";
|
"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>";
|
||||||
|
|
||||||
fn get_bypass() -> String {
|
fn get_bypass() -> String {
|
||||||
let use_default = Config::verge().latest().use_default_bypass.unwrap_or(true);
|
let use_default = Config::verge()
|
||||||
|
.latest_ref()
|
||||||
|
.use_default_bypass
|
||||||
|
.unwrap_or(true);
|
||||||
let res = {
|
let res = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
verge.system_proxy_bypass.clone()
|
verge.system_proxy_bypass.clone()
|
||||||
};
|
};
|
||||||
let custom_bypass = match res {
|
let custom_bypass = match res {
|
||||||
@@ -72,14 +75,14 @@ impl Sysopt {
|
|||||||
let _lock = self.update_sysproxy.lock().await;
|
let _lock = self.update_sysproxy.lock().await;
|
||||||
|
|
||||||
let port = Config::verge()
|
let port = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
let pac_port = IVerge::get_singleton_port();
|
let pac_port = IVerge::get_singleton_port();
|
||||||
|
|
||||||
let (sys_enable, pac_enable, proxy_host) = {
|
let (sys_enable, pac_enable, proxy_host) = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
(
|
(
|
||||||
verge.enable_system_proxy.unwrap_or(false),
|
verge.enable_system_proxy.unwrap_or(false),
|
||||||
verge.proxy_auto_config.unwrap_or(false),
|
verge.proxy_auto_config.unwrap_or(false),
|
||||||
@@ -239,7 +242,7 @@ impl Sysopt {
|
|||||||
|
|
||||||
/// update the startup
|
/// update the startup
|
||||||
pub fn update_launch(&self) -> Result<()> {
|
pub fn update_launch(&self) -> Result<()> {
|
||||||
let enable_auto_launch = { Config::verge().latest().enable_auto_launch };
|
let enable_auto_launch = { Config::verge().latest_ref().enable_auto_launch };
|
||||||
let is_enable = enable_auto_launch.unwrap_or(false);
|
let is_enable = enable_auto_launch.unwrap_or(false);
|
||||||
logging!(info, true, "Setting auto-launch state to: {:?}", is_enable);
|
logging!(info, true, "Setting auto-launch state to: {:?}", is_enable);
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ impl Timer {
|
|||||||
let cur_timestamp = chrono::Local::now().timestamp();
|
let cur_timestamp = chrono::Local::now().timestamp();
|
||||||
|
|
||||||
// Collect profiles that need immediate update
|
// Collect profiles that need immediate update
|
||||||
let profiles_to_update = if let Some(items) = Config::profiles().latest().get_items() {
|
let profiles_to_update = if let Some(items) = Config::profiles().latest_ref().get_items() {
|
||||||
items
|
items
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|item| {
|
.filter_map(|item| {
|
||||||
@@ -229,7 +229,7 @@ impl Timer {
|
|||||||
fn gen_map(&self) -> HashMap<String, u64> {
|
fn gen_map(&self) -> HashMap<String, u64> {
|
||||||
let mut new_map = HashMap::new();
|
let mut new_map = HashMap::new();
|
||||||
|
|
||||||
if let Some(items) = Config::profiles().latest().get_items() {
|
if let Some(items) = Config::profiles().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() {
|
||||||
if let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) {
|
if let (Some(interval), Some(uid)) = (option.update_interval, &item.uid) {
|
||||||
@@ -376,7 +376,7 @@ impl Timer {
|
|||||||
|
|
||||||
// Get the profile updated timestamp
|
// Get the profile updated timestamp
|
||||||
let profiles_config = Config::profiles();
|
let profiles_config = Config::profiles();
|
||||||
let profiles = profiles_config.latest();
|
let profiles = profiles_config.latest_ref();
|
||||||
let items = match profiles.get_items() {
|
let items = match profiles.get_items() {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => {
|
None => {
|
||||||
@@ -438,7 +438,7 @@ impl Timer {
|
|||||||
match tokio::time::timeout(std::time::Duration::from_secs(40), async {
|
match tokio::time::timeout(std::time::Duration::from_secs(40), async {
|
||||||
Self::emit_update_event(&uid, true);
|
Self::emit_update_event(&uid, true);
|
||||||
|
|
||||||
let is_current = Config::profiles().latest().current.as_ref() == Some(&uid);
|
let is_current = Config::profiles().latest_ref().current.as_ref() == Some(&uid);
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Timer,
|
Type::Timer,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ pub struct Tray {
|
|||||||
|
|
||||||
impl TrayState {
|
impl TrayState {
|
||||||
pub fn get_common_tray_icon() -> (bool, Vec<u8>) {
|
pub fn get_common_tray_icon() -> (bool, Vec<u8>) {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().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 {
|
||||||
if let Some(common_icon_path) = find_target_icons("common").unwrap() {
|
if let Some(common_icon_path) = find_target_icons("common").unwrap() {
|
||||||
@@ -100,7 +100,7 @@ impl TrayState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) {
|
pub fn get_sysproxy_tray_icon() -> (bool, Vec<u8>) {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().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 {
|
||||||
if let Some(sysproxy_icon_path) = find_target_icons("sysproxy").unwrap() {
|
if let Some(sysproxy_icon_path) = find_target_icons("sysproxy").unwrap() {
|
||||||
@@ -134,7 +134,7 @@ impl TrayState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tun_tray_icon() -> (bool, Vec<u8>) {
|
pub fn get_tun_tray_icon() -> (bool, Vec<u8>) {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().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 {
|
||||||
if let Some(tun_icon_path) = find_target_icons("tun").unwrap() {
|
if let Some(tun_icon_path) = find_target_icons("tun").unwrap() {
|
||||||
@@ -191,7 +191,7 @@ impl Tray {
|
|||||||
/// 更新托盘点击行为
|
/// 更新托盘点击行为
|
||||||
pub fn update_click_behavior(&self) -> Result<()> {
|
pub fn update_click_behavior(&self) -> Result<()> {
|
||||||
let app_handle = handle::Handle::global().app_handle().unwrap();
|
let app_handle = handle::Handle::global().app_handle().unwrap();
|
||||||
let tray_event = { Config::verge().latest().tray_event.clone() };
|
let tray_event = { Config::verge().latest_ref().tray_event.clone() };
|
||||||
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
||||||
let tray = app_handle.tray_by_id("main").unwrap();
|
let tray = app_handle.tray_by_id("main").unwrap();
|
||||||
match tray_event.as_str() {
|
match tray_event.as_str() {
|
||||||
@@ -251,12 +251,12 @@ impl Tray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_menu_internal(&self, app_handle: &AppHandle) -> Result<()> {
|
fn update_menu_internal(&self, app_handle: &AppHandle) -> Result<()> {
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest_ref().clone();
|
||||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
let mode = {
|
let mode = {
|
||||||
Config::clash()
|
Config::clash()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.0
|
.0
|
||||||
.get("mode")
|
.get("mode")
|
||||||
.map(|val| val.as_str().unwrap_or("rule"))
|
.map(|val| val.as_str().unwrap_or("rule"))
|
||||||
@@ -264,7 +264,7 @@ impl Tray {
|
|||||||
.to_owned()
|
.to_owned()
|
||||||
};
|
};
|
||||||
let profile_uid_and_name = Config::profiles()
|
let profile_uid_and_name = Config::profiles()
|
||||||
.data()
|
.data_mut()
|
||||||
.all_profile_uid_and_name()
|
.all_profile_uid_and_name()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let is_lightweight_mode = is_in_lightweight_mode();
|
let is_lightweight_mode = is_in_lightweight_mode();
|
||||||
@@ -308,7 +308,7 @@ impl Tray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest_ref().clone();
|
||||||
let system_mode = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
let system_mode = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ impl Tray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest_ref().clone();
|
||||||
let system_mode = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
let system_mode = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ impl Tray {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let verge = Config::verge().latest().clone();
|
let verge = Config::verge().latest_ref().clone();
|
||||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ impl Tray {
|
|||||||
|
|
||||||
let mut current_profile_name = "None".to_string();
|
let mut current_profile_name = "None".to_string();
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest_ref();
|
||||||
if let Some(current_profile_uid) = profiles.get_current() {
|
if let Some(current_profile_uid) = profiles.get_current() {
|
||||||
if let Ok(profile) = profiles.get_item(¤t_profile_uid) {
|
if let Ok(profile) = profiles.get_item(¤t_profile_uid) {
|
||||||
current_profile_name = match &profile.name {
|
current_profile_name = match &profile.name {
|
||||||
@@ -461,7 +461,7 @@ impl Tray {
|
|||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||||
{
|
{
|
||||||
let tray_event = { Config::verge().latest().tray_event.clone() };
|
let tray_event = { Config::verge().latest_ref().tray_event.clone() };
|
||||||
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
||||||
if tray_event.as_str() != "tray_menu" {
|
if tray_event.as_str() != "tray_menu" {
|
||||||
builder = builder.show_menu_on_left_click(false);
|
builder = builder.show_menu_on_left_click(false);
|
||||||
@@ -471,7 +471,7 @@ impl Tray {
|
|||||||
let tray = builder.build(app_handle)?;
|
let tray = builder.build(app_handle)?;
|
||||||
|
|
||||||
tray.on_tray_icon_event(|_, event| {
|
tray.on_tray_icon_event(|_, event| {
|
||||||
let tray_event = { Config::verge().latest().tray_event.clone() };
|
let tray_event = { Config::verge().latest_ref().tray_event.clone() };
|
||||||
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
||||||
log::debug!(target: "app","tray event: {tray_event:?}");
|
log::debug!(target: "app","tray event: {tray_event:?}");
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ fn create_tray_menu(
|
|||||||
let version = VERSION.get().unwrap_or(&unknown_version);
|
let version = VERSION.get().unwrap_or(&unknown_version);
|
||||||
|
|
||||||
let hotkeys = Config::verge()
|
let hotkeys = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.hotkeys
|
.hotkeys
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|h| {
|
.map(|h| {
|
||||||
@@ -554,7 +554,7 @@ fn create_tray_menu(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(profile_uid, profile_name)| {
|
.map(|(profile_uid, profile_name)| {
|
||||||
let is_current_profile = Config::profiles()
|
let is_current_profile = Config::profiles()
|
||||||
.data()
|
.data_mut()
|
||||||
.is_current_profile_index(profile_uid.to_string());
|
.is_current_profile_index(profile_uid.to_string());
|
||||||
CheckMenuItem::with_id(
|
CheckMenuItem::with_id(
|
||||||
app_handle,
|
app_handle,
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ type ResultLog = Vec<(String, String)>;
|
|||||||
/// 返回最终订阅、该订阅包含的键、和script执行的结果
|
/// 返回最终订阅、该订阅包含的键、和script执行的结果
|
||||||
pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||||
// config.yaml 的订阅
|
// config.yaml 的订阅
|
||||||
let clash_config = { Config::clash().latest().0.clone() };
|
let clash_config = { Config::clash().latest_ref().0.clone() };
|
||||||
|
|
||||||
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled, enable_dns_settings) = {
|
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled, enable_dns_settings) = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
(
|
(
|
||||||
Some(verge.get_valid_clash_core()),
|
Some(verge.get_valid_clash_core()),
|
||||||
verge.enable_tun_mode.unwrap_or(false),
|
verge.enable_tun_mode.unwrap_or(false),
|
||||||
@@ -33,13 +33,13 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
|||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let redir_enabled = {
|
let redir_enabled = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
verge.verge_redir_enabled.unwrap_or(false)
|
verge.verge_redir_enabled.unwrap_or(false)
|
||||||
};
|
};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let tproxy_enabled = {
|
let tproxy_enabled = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
verge.verge_tproxy_enabled.unwrap_or(false)
|
verge.verge_tproxy_enabled.unwrap_or(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
|||||||
profile_name,
|
profile_name,
|
||||||
) = {
|
) = {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest_ref();
|
||||||
|
|
||||||
let current = profiles.current_mapping().unwrap_or_default();
|
let current = profiles.current_mapping().unwrap_or_default();
|
||||||
let merge = profiles
|
let merge = profiles
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub async fn delete_webdav_backup(filename: String) -> Result<()> {
|
|||||||
/// Restore WebDAV backup
|
/// Restore WebDAV backup
|
||||||
pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge_data = verge.data().clone();
|
let verge_data = verge.latest_ref().clone();
|
||||||
let webdav_url = verge_data.webdav_url.clone();
|
let webdav_url = verge_data.webdav_url.clone();
|
||||||
let webdav_username = verge_data.webdav_username.clone();
|
let webdav_username = verge_data.webdav_username.clone();
|
||||||
let webdav_password = verge_data.webdav_password.clone();
|
let webdav_password = verge_data.webdav_password.clone();
|
||||||
|
|||||||
@@ -68,16 +68,16 @@ pub fn change_clash_mode(mode: String) {
|
|||||||
match MihomoManager::global().patch_configs(json_value).await {
|
match MihomoManager::global().patch_configs(json_value).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// 更新订阅
|
// 更新订阅
|
||||||
Config::clash().data().patch_config(mapping);
|
Config::clash().data_mut().patch_config(mapping);
|
||||||
|
|
||||||
if Config::clash().data().save_config().is_ok() {
|
if Config::clash().data_mut().save_config().is_ok() {
|
||||||
handle::Handle::refresh_clash();
|
handle::Handle::refresh_clash();
|
||||||
logging_error!(Type::Tray, true, tray::Tray::global().update_menu());
|
logging_error!(Type::Tray, true, tray::Tray::global().update_menu());
|
||||||
logging_error!(Type::Tray, true, tray::Tray::global().update_icon(None));
|
logging_error!(Type::Tray, true, tray::Tray::global().update_icon(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_auto_close_connection = Config::verge()
|
let is_auto_close_connection = Config::verge()
|
||||||
.data()
|
.data_mut()
|
||||||
.auto_close_connection
|
.auto_close_connection
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if is_auto_close_connection {
|
if is_auto_close_connection {
|
||||||
@@ -94,7 +94,10 @@ pub async fn test_delay(url: String) -> anyhow::Result<u32> {
|
|||||||
use crate::utils::network::{NetworkManager, ProxyType};
|
use crate::utils::network::{NetworkManager, ProxyType};
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
|
|
||||||
let tun_mode = Config::verge().latest().enable_tun_mode.unwrap_or(false);
|
let tun_mode = Config::verge()
|
||||||
|
.latest_ref()
|
||||||
|
.enable_tun_mode
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
// 如果是TUN模式,不使用代理,否则使用自身代理
|
// 如果是TUN模式,不使用代理,否则使用自身代理
|
||||||
let proxy_type = if !tun_mode {
|
let proxy_type = if !tun_mode {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use serde_yaml::Mapping;
|
|||||||
|
|
||||||
/// Patch Clash configuration
|
/// Patch Clash configuration
|
||||||
pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
||||||
Config::clash().draft().patch_config(patch.clone());
|
Config::clash().draft_mut().patch_config(patch.clone());
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
// 激活订阅
|
// 激活订阅
|
||||||
@@ -22,7 +22,7 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
|||||||
logging_error!(Type::Tray, true, tray::Tray::global().update_menu());
|
logging_error!(Type::Tray, true, tray::Tray::global().update_menu());
|
||||||
logging_error!(Type::Tray, true, tray::Tray::global().update_icon(None));
|
logging_error!(Type::Tray, true, tray::Tray::global().update_icon(None));
|
||||||
}
|
}
|
||||||
Config::runtime().latest().patch_config(patch);
|
Config::runtime().draft_mut().patch_config(patch);
|
||||||
CoreManager::global().update_config().await?;
|
CoreManager::global().update_config().await?;
|
||||||
}
|
}
|
||||||
handle::Handle::refresh_clash();
|
handle::Handle::refresh_clash();
|
||||||
@@ -31,7 +31,7 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
|||||||
match res {
|
match res {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
Config::clash().apply();
|
Config::clash().apply();
|
||||||
Config::clash().data().save_config()?;
|
Config::clash().data_mut().save_config()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -60,7 +60,7 @@ enum UpdateFlags {
|
|||||||
|
|
||||||
/// Patch Verge configuration
|
/// Patch Verge configuration
|
||||||
pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
|
pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
|
||||||
Config::verge().draft().patch_config(patch.clone());
|
Config::verge().draft_mut().patch_config(patch.clone());
|
||||||
|
|
||||||
let tun_mode = patch.enable_tun_mode;
|
let tun_mode = patch.enable_tun_mode;
|
||||||
let auto_launch = patch.enable_auto_launch;
|
let auto_launch = patch.enable_auto_launch;
|
||||||
@@ -175,7 +175,7 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
|
|||||||
handle::Handle::refresh_clash();
|
handle::Handle::refresh_clash();
|
||||||
}
|
}
|
||||||
if (update_flags & (UpdateFlags::VergeConfig as i32)) != 0 {
|
if (update_flags & (UpdateFlags::VergeConfig as i32)) != 0 {
|
||||||
Config::verge().draft().enable_global_hotkey = enable_global_hotkey;
|
Config::verge().draft_mut().enable_global_hotkey = enable_global_hotkey;
|
||||||
handle::Handle::refresh_verge();
|
handle::Handle::refresh_verge();
|
||||||
}
|
}
|
||||||
if (update_flags & (UpdateFlags::Launch as i32)) != 0 {
|
if (update_flags & (UpdateFlags::Launch as i32)) != 0 {
|
||||||
@@ -213,7 +213,7 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
|
|||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
Config::verge().apply();
|
Config::verge().apply();
|
||||||
if !not_save_file {
|
if !not_save_file {
|
||||||
Config::verge().data().save_file()?;
|
Config::verge().data_mut().save_file()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub async fn update_profile(
|
|||||||
|
|
||||||
let url_opt = {
|
let url_opt = {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles = profiles.latest();
|
let profiles = profiles.latest_ref();
|
||||||
let item = profiles.get_item(&uid)?;
|
let item = profiles.get_item(&uid)?;
|
||||||
let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote");
|
let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote");
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ pub async fn update_profile(
|
|||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
log::info!(target: "app", "[订阅更新] 更新订阅配置成功");
|
log::info!(target: "app", "[订阅更新] 更新订阅配置成功");
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let mut profiles = profiles.latest();
|
let mut profiles = profiles.draft_mut();
|
||||||
profiles.update_item(uid.clone(), item)?;
|
profiles.update_item(uid.clone(), item)?;
|
||||||
|
|
||||||
let is_current = Some(uid.clone()) == profiles.get_current();
|
let is_current = Some(uid.clone()) == profiles.get_current();
|
||||||
@@ -102,7 +102,7 @@ pub async fn update_profile(
|
|||||||
|
|
||||||
// 更新到配置
|
// 更新到配置
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let mut profiles = profiles.latest();
|
let mut profiles = profiles.draft_mut();
|
||||||
profiles.update_item(uid.clone(), item.clone())?;
|
profiles.update_item(uid.clone(), item.clone())?;
|
||||||
|
|
||||||
// 获取配置名称用于通知
|
// 获取配置名称用于通知
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ use tauri_plugin_clipboard_manager::ClipboardExt;
|
|||||||
|
|
||||||
/// Toggle system proxy on/off
|
/// Toggle system proxy on/off
|
||||||
pub fn toggle_system_proxy() {
|
pub fn toggle_system_proxy() {
|
||||||
let enable = Config::verge().draft().enable_system_proxy;
|
let enable = Config::verge().draft_mut().enable_system_proxy;
|
||||||
let enable = enable.unwrap_or(false);
|
let enable = enable.unwrap_or(false);
|
||||||
let auto_close_connection = Config::verge()
|
let auto_close_connection = Config::verge()
|
||||||
.data()
|
.data_mut()
|
||||||
.auto_close_connection
|
.auto_close_connection
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ pub fn toggle_system_proxy() {
|
|||||||
|
|
||||||
/// Toggle TUN mode on/off
|
/// Toggle TUN mode on/off
|
||||||
pub fn toggle_tun_mode(not_save_file: Option<bool>) {
|
pub fn toggle_tun_mode(not_save_file: Option<bool>) {
|
||||||
let enable = Config::verge().data().enable_tun_mode;
|
let enable = Config::verge().data_mut().enable_tun_mode;
|
||||||
let enable = enable.unwrap_or(false);
|
let enable = enable.unwrap_or(false);
|
||||||
|
|
||||||
AsyncHandler::spawn(async move || {
|
AsyncHandler::spawn(async move || {
|
||||||
@@ -67,19 +67,24 @@ pub fn copy_clash_env() {
|
|||||||
// 从环境变量获取IP地址,如果没有则从配置中获取 proxy_host,默认为 127.0.0.1
|
// 从环境变量获取IP地址,如果没有则从配置中获取 proxy_host,默认为 127.0.0.1
|
||||||
let clash_verge_rev_ip = env::var("CLASH_VERGE_REV_IP").unwrap_or_else(|_| {
|
let clash_verge_rev_ip = env::var("CLASH_VERGE_REV_IP").unwrap_or_else(|_| {
|
||||||
Config::verge()
|
Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.proxy_host
|
.proxy_host
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "127.0.0.1".to_string())
|
.unwrap_or_else(|| "127.0.0.1".to_string())
|
||||||
});
|
});
|
||||||
|
|
||||||
let app_handle = handle::Handle::global().app_handle().unwrap();
|
let app_handle = handle::Handle::global().app_handle().unwrap();
|
||||||
let port = { Config::verge().latest().verge_mixed_port.unwrap_or(7897) };
|
let port = {
|
||||||
|
Config::verge()
|
||||||
|
.latest_ref()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(7897)
|
||||||
|
};
|
||||||
let http_proxy = format!("http://{clash_verge_rev_ip}:{port}");
|
let http_proxy = format!("http://{clash_verge_rev_ip}:{port}");
|
||||||
let socks5_proxy = format!("socks5://{clash_verge_rev_ip}:{port}");
|
let socks5_proxy = format!("socks5://{clash_verge_rev_ip}:{port}");
|
||||||
|
|
||||||
let cliboard = app_handle.clipboard();
|
let cliboard = app_handle.clipboard();
|
||||||
let env_type = { Config::verge().latest().env_type.clone() };
|
let env_type = { Config::verge().latest_ref().env_type.clone() };
|
||||||
let env_type = match env_type {
|
let env_type = match env_type {
|
||||||
Some(env_type) => env_type,
|
Some(env_type) => env_type,
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ async fn clean_async() -> bool {
|
|||||||
|
|
||||||
// 1. 处理TUN模式
|
// 1. 处理TUN模式
|
||||||
let tun_task = async {
|
let tun_task = async {
|
||||||
if Config::verge().data().enable_tun_mode.unwrap_or(false) {
|
if Config::verge().data_mut().enable_tun_mode.unwrap_or(false) {
|
||||||
let disable_tun = serde_json::json!({
|
let disable_tun = serde_json::json!({
|
||||||
"tun": {
|
"tun": {
|
||||||
"enable": false
|
"enable": false
|
||||||
@@ -240,7 +240,7 @@ pub fn hide() {
|
|||||||
use crate::module::lightweight::add_light_weight_timer;
|
use crate::module::lightweight::add_light_weight_timer;
|
||||||
|
|
||||||
let enable_auto_light_weight_mode = Config::verge()
|
let enable_auto_light_weight_mode = Config::verge()
|
||||||
.data()
|
.data_mut()
|
||||||
.enable_auto_light_weight_mode
|
.enable_auto_light_weight_mode
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod cmd;
|
mod cmd;
|
||||||
mod config;
|
pub mod config;
|
||||||
mod core;
|
mod core;
|
||||||
mod enhance;
|
mod enhance;
|
||||||
mod feat;
|
mod feat;
|
||||||
@@ -401,7 +401,7 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
let is_enable_global_hotkey = Config::verge()
|
let is_enable_global_hotkey = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.enable_global_hotkey
|
.enable_global_hotkey
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
if !is_enable_global_hotkey {
|
if !is_enable_global_hotkey {
|
||||||
@@ -425,7 +425,7 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
let is_enable_global_hotkey = Config::verge()
|
let is_enable_global_hotkey = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.enable_global_hotkey
|
.enable_global_hotkey
|
||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
if !is_enable_global_hotkey {
|
if !is_enable_global_hotkey {
|
||||||
|
|||||||
@@ -36,9 +36,12 @@ where
|
|||||||
|
|
||||||
pub fn run_once_auto_lightweight() {
|
pub fn run_once_auto_lightweight() {
|
||||||
LightWeightState::default().run_once_time(|| {
|
LightWeightState::default().run_once_time(|| {
|
||||||
let is_silent_start = Config::verge().data().enable_silent_start.unwrap_or(false);
|
let is_silent_start = Config::verge()
|
||||||
|
.latest_ref()
|
||||||
|
.enable_silent_start
|
||||||
|
.unwrap_or(false);
|
||||||
let enable_auto = Config::verge()
|
let enable_auto = Config::verge()
|
||||||
.data()
|
.data_mut()
|
||||||
.enable_auto_light_weight_mode
|
.enable_auto_light_weight_mode
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if enable_auto && is_silent_start {
|
if enable_auto && is_silent_start {
|
||||||
@@ -62,8 +65,9 @@ pub fn run_once_auto_lightweight() {
|
|||||||
pub fn auto_lightweight_mode_init() {
|
pub fn auto_lightweight_mode_init() {
|
||||||
if let Some(app_handle) = handle::Handle::global().app_handle() {
|
if let Some(app_handle) = handle::Handle::global().app_handle() {
|
||||||
let _ = app_handle.state::<Mutex<LightWeightState>>();
|
let _ = app_handle.state::<Mutex<LightWeightState>>();
|
||||||
let is_silent_start = { Config::verge().data().enable_silent_start }.unwrap_or(false);
|
let is_silent_start = { Config::verge().latest_ref().enable_silent_start }.unwrap_or(false);
|
||||||
let enable_auto = { Config::verge().data().enable_auto_light_weight_mode }.unwrap_or(false);
|
let enable_auto =
|
||||||
|
{ Config::verge().latest_ref().enable_auto_light_weight_mode }.unwrap_or(false);
|
||||||
|
|
||||||
if enable_auto && !is_silent_start {
|
if enable_auto && !is_silent_start {
|
||||||
logging!(
|
logging!(
|
||||||
@@ -225,7 +229,7 @@ fn cancel_window_close_listener() {
|
|||||||
fn setup_light_weight_timer() -> Result<()> {
|
fn setup_light_weight_timer() -> Result<()> {
|
||||||
Timer::global().init()?;
|
Timer::global().init()?;
|
||||||
let once_by_minutes = Config::verge()
|
let once_by_minutes = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.auto_light_weight_minutes
|
.auto_light_weight_minutes
|
||||||
.unwrap_or(10);
|
.unwrap_or(10);
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl MihomoManager {
|
|||||||
|
|
||||||
impl MihomoManager {
|
impl MihomoManager {
|
||||||
pub fn get_clash_client_info() -> Option<(String, HeaderMap)> {
|
pub fn get_clash_client_info() -> Option<(String, HeaderMap)> {
|
||||||
let client = { Config::clash().data().get_client_info() };
|
let client = { Config::clash().latest_ref().get_client_info() };
|
||||||
let server = format!("http://{}", client.server);
|
let server = format!("http://{}", client.server);
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert("Content-Type", "application/json".parse().unwrap());
|
headers.insert("Content-Type", "application/json".parse().unwrap());
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ fn get_system_language() -> String {
|
|||||||
|
|
||||||
pub fn t(key: &str) -> String {
|
pub fn t(key: &str) -> String {
|
||||||
let current_lang = Config::verge()
|
let current_lang = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.language
|
.language
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ fn init_log() -> Result<()> {
|
|||||||
let _ = fs::create_dir_all(&log_dir);
|
let _ = fs::create_dir_all(&log_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
let log_level = Config::verge().data().get_log_level();
|
let log_level = Config::verge().latest_ref().get_log_level();
|
||||||
if log_level == LevelFilter::Off {
|
if log_level == LevelFilter::Off {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ pub fn delete_log() -> Result<()> {
|
|||||||
|
|
||||||
let auto_log_clean = {
|
let auto_log_clean = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.data();
|
let verge = verge.latest_ref();
|
||||||
verge.auto_log_clean.unwrap_or(0)
|
verge.auto_log_clean.unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ pub async fn startup_script() -> Result<()> {
|
|||||||
|
|
||||||
let script_path = {
|
let script_path = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest_ref();
|
||||||
verge.startup_script.clone().unwrap_or("".to_string())
|
verge.startup_script.clone().unwrap_or("".to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -141,9 +141,9 @@ impl NetworkManager {
|
|||||||
|
|
||||||
if client_guard.is_none() {
|
if client_guard.is_none() {
|
||||||
let port = Config::verge()
|
let port = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
|
|
||||||
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
||||||
|
|
||||||
@@ -279,9 +279,9 @@ impl NetworkManager {
|
|||||||
}
|
}
|
||||||
ProxyType::Localhost => {
|
ProxyType::Localhost => {
|
||||||
let port = Config::verge()
|
let port = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
|
|
||||||
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
||||||
|
|
||||||
|
|||||||
@@ -118,9 +118,9 @@ pub async fn find_unused_port() -> Result<u16> {
|
|||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let port = Config::verge()
|
let port = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
log::warn!(target: "app", "use default port: {port}");
|
log::warn!(target: "app", "use default port: {port}");
|
||||||
Ok(port)
|
Ok(port)
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ pub async fn resolve_setup_async(app_handle: &AppHandle) {
|
|||||||
// 启动时清理冗余的 Profile 文件
|
// 启动时清理冗余的 Profile 文件
|
||||||
logging!(info, Type::Setup, true, "清理冗余的Profile文件...");
|
logging!(info, Type::Setup, true, "清理冗余的Profile文件...");
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
if let Err(e) = profiles.latest().auto_cleanup() {
|
if let Err(e) = profiles.latest_ref().auto_cleanup() {
|
||||||
logging!(warn, Type::Setup, true, "启动时清理Profile文件失败: {}", e);
|
logging!(warn, Type::Setup, true, "启动时清理Profile文件失败: {}", e);
|
||||||
} else {
|
} else {
|
||||||
logging!(info, Type::Setup, true, "启动时Profile文件清理完成");
|
logging!(info, Type::Setup, true, "启动时Profile文件清理完成");
|
||||||
@@ -204,7 +204,7 @@ pub async fn resolve_setup_async(app_handle: &AppHandle) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 创建窗口
|
// 创建窗口
|
||||||
let is_silent_start = { Config::verge().data().enable_silent_start }.unwrap_or(false);
|
let is_silent_start = { Config::verge().latest_ref().enable_silent_start }.unwrap_or(false);
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
if is_silent_start {
|
if is_silent_start {
|
||||||
@@ -574,7 +574,7 @@ pub async fn resolve_scheme(param: String) -> Result<()> {
|
|||||||
match PrfItem::from_url(url.as_ref(), name, None, None).await {
|
match PrfItem::from_url(url.as_ref(), name, None, None).await {
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
let uid = item.uid.clone().unwrap();
|
let uid = item.uid.clone().unwrap();
|
||||||
let _ = wrap_err!(Config::profiles().data().append_item(item));
|
let _ = wrap_err!(Config::profiles().data_mut().append_item(item));
|
||||||
handle::Handle::notice_message("import_sub_url::ok", uid);
|
handle::Handle::notice_message("import_sub_url::ok", uid);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -592,12 +592,15 @@ pub async fn resolve_scheme(param: String) -> Result<()> {
|
|||||||
async fn resolve_random_port_config() -> Result<()> {
|
async fn resolve_random_port_config() -> Result<()> {
|
||||||
let verge_config = Config::verge();
|
let verge_config = Config::verge();
|
||||||
let clash_config = Config::clash();
|
let clash_config = Config::clash();
|
||||||
let enable_random_port = verge_config.latest().enable_random_port.unwrap_or(false);
|
let enable_random_port = verge_config
|
||||||
|
.latest_ref()
|
||||||
|
.enable_random_port
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
let default_port = verge_config
|
let default_port = verge_config
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(clash_config.data().get_mixed_port());
|
.unwrap_or(clash_config.latest_ref().get_mixed_port());
|
||||||
|
|
||||||
let port = if enable_random_port {
|
let port = if enable_random_port {
|
||||||
find_unused_port().await.unwrap_or(default_port)
|
find_unused_port().await.unwrap_or(default_port)
|
||||||
@@ -609,7 +612,7 @@ async fn resolve_random_port_config() -> Result<()> {
|
|||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let verge_config_accessor = Config::verge();
|
let verge_config_accessor = Config::verge();
|
||||||
let mut verge_data = verge_config_accessor.data();
|
let mut verge_data = verge_config_accessor.data_mut();
|
||||||
verge_data.patch_config(IVerge {
|
verge_data.patch_config(IVerge {
|
||||||
verge_mixed_port: Some(port_to_save),
|
verge_mixed_port: Some(port_to_save),
|
||||||
..IVerge::default()
|
..IVerge::default()
|
||||||
@@ -620,7 +623,7 @@ async fn resolve_random_port_config() -> Result<()> {
|
|||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let clash_config_accessor = Config::clash(); // Extend lifetime of the accessor
|
let clash_config_accessor = Config::clash(); // Extend lifetime of the accessor
|
||||||
let mut clash_data = clash_config_accessor.data(); // Access within blocking task, made mutable
|
let mut clash_data = clash_config_accessor.data_mut(); // Access within blocking task, made mutable
|
||||||
let mut mapping = Mapping::new();
|
let mut mapping = Mapping::new();
|
||||||
mapping.insert("mixed-port".into(), port_to_save.into());
|
mapping.insert("mixed-port".into(), port_to_save.into());
|
||||||
clash_data.patch_config(mapping);
|
clash_data.patch_config(mapping);
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ pub fn embed_server() {
|
|||||||
|
|
||||||
let pac = warp::path!("commands" / "pac").map(move || {
|
let pac = warp::path!("commands" / "pac").map(move || {
|
||||||
let content = Config::verge()
|
let content = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.pac_file_content
|
.pac_file_content
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or(DEFAULT_PAC.to_string());
|
.unwrap_or(DEFAULT_PAC.to_string());
|
||||||
let port = Config::verge()
|
let port = Config::verge()
|
||||||
.latest()
|
.latest_ref()
|
||||||
.verge_mixed_port
|
.verge_mixed_port
|
||||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
.unwrap_or(Config::clash().latest_ref().get_mixed_port());
|
||||||
let content = content.replace("%mixed-port%", &format!("{port}"));
|
let content = content.replace("%mixed-port%", &format!("{port}"));
|
||||||
warp::http::Response::builder()
|
warp::http::Response::builder()
|
||||||
.header("Content-Type", "application/x-ns-proxy-autoconfig")
|
.header("Content-Type", "application/x-ns-proxy-autoconfig")
|
||||||
|
|||||||
Reference in New Issue
Block a user