mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-04 06:02:08 +08:00
refactor(config): share patch macro and profiles helpers
IVerge::patch_config, IProfiles::patch_item and PrfOption::merge each hand-rolled the same copy-Some-overwrite pattern; they now share one patch_opt_field macro (the or-else merge form is field-for-field equivalent for Option fields). The four profiles *_safe wrappers that inlined Config::profiles().with_data_modify boilerplate delegate to a with_profiles_edit helper, and record/forget_selected_node share the current-item lookup prelude via current_item_mut.
This commit is contained in:
@@ -14,6 +14,15 @@ mod verge;
|
||||
pub(crate) use self::config::Config;
|
||||
pub use self::{clash::*, encrypt::*, mixed_port::*, prfitem::*, profiles::*, verge::*};
|
||||
|
||||
macro_rules! patch_opt_field {
|
||||
($lv:expr, $rv:expr, $key:tt) => {
|
||||
if ($rv.$key).is_some() {
|
||||
$lv.$key = $rv.$key.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use patch_opt_field;
|
||||
|
||||
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use super::patch_opt_field;
|
||||
|
||||
use crate::{
|
||||
config::profiles,
|
||||
utils::{
|
||||
@@ -131,19 +133,18 @@ impl PrfOption {
|
||||
match (one, other) {
|
||||
(Some(a_ref), Some(b_ref)) => {
|
||||
let mut result = a_ref.clone();
|
||||
result.user_agent = b_ref.user_agent.clone().or(result.user_agent);
|
||||
result.with_proxy = b_ref.with_proxy.or(result.with_proxy);
|
||||
result.self_proxy = b_ref.self_proxy.or(result.self_proxy);
|
||||
result.danger_accept_invalid_certs =
|
||||
b_ref.danger_accept_invalid_certs.or(result.danger_accept_invalid_certs);
|
||||
result.allow_auto_update = b_ref.allow_auto_update.or(result.allow_auto_update);
|
||||
result.update_interval = b_ref.update_interval.or(result.update_interval);
|
||||
result.merge = b_ref.merge.clone().or(result.merge);
|
||||
result.script = b_ref.script.clone().or(result.script);
|
||||
result.rules = b_ref.rules.clone().or(result.rules);
|
||||
result.proxies = b_ref.proxies.clone().or(result.proxies);
|
||||
result.groups = b_ref.groups.clone().or(result.groups);
|
||||
result.timeout_seconds = b_ref.timeout_seconds.or(result.timeout_seconds);
|
||||
patch_opt_field!(result, b_ref, user_agent);
|
||||
patch_opt_field!(result, b_ref, with_proxy);
|
||||
patch_opt_field!(result, b_ref, self_proxy);
|
||||
patch_opt_field!(result, b_ref, danger_accept_invalid_certs);
|
||||
patch_opt_field!(result, b_ref, allow_auto_update);
|
||||
patch_opt_field!(result, b_ref, update_interval);
|
||||
patch_opt_field!(result, b_ref, merge);
|
||||
patch_opt_field!(result, b_ref, script);
|
||||
patch_opt_field!(result, b_ref, rules);
|
||||
patch_opt_field!(result, b_ref, proxies);
|
||||
patch_opt_field!(result, b_ref, groups);
|
||||
patch_opt_field!(result, b_ref, timeout_seconds);
|
||||
Some(result)
|
||||
}
|
||||
(Some(a_ref), None) => Some(a_ref.clone()),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
PrfOption,
|
||||
PrfOption, patch_opt_field,
|
||||
prfitem::{PrfItem, PrfSelected, normalize_profile_home_url},
|
||||
};
|
||||
use crate::core::notify::{Refresh, announce};
|
||||
@@ -86,14 +86,6 @@ impl ProfileDeletePlan {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! patch {
|
||||
($lv: expr, $rv: expr, $key: tt) => {
|
||||
if ($rv.$key).is_some() {
|
||||
$lv.$key = $rv.$key.to_owned();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl IProfiles {
|
||||
fn take_item_file_by_uid(items: &mut Vec<PrfItem>, target_uid: Option<&str>) -> Option<String> {
|
||||
let index = items.iter().position(|item| item.uid.as_deref() == target_uid)?;
|
||||
@@ -244,15 +236,15 @@ impl IProfiles {
|
||||
|
||||
for each in items.iter_mut() {
|
||||
if each.uid.as_deref() == Some(uid) {
|
||||
patch!(each, item, itype);
|
||||
patch!(each, item, name);
|
||||
patch!(each, item, desc);
|
||||
patch!(each, item, file);
|
||||
patch!(each, item, url);
|
||||
patch!(each, item, selected);
|
||||
patch!(each, item, extra);
|
||||
patch!(each, item, updated);
|
||||
patch!(each, item, option);
|
||||
patch_opt_field!(each, item, itype);
|
||||
patch_opt_field!(each, item, name);
|
||||
patch_opt_field!(each, item, desc);
|
||||
patch_opt_field!(each, item, file);
|
||||
patch_opt_field!(each, item, url);
|
||||
patch_opt_field!(each, item, selected);
|
||||
patch_opt_field!(each, item, extra);
|
||||
patch_opt_field!(each, item, updated);
|
||||
patch_opt_field!(each, item, option);
|
||||
|
||||
self.items = Some(items);
|
||||
return self.save_file().await;
|
||||
@@ -420,6 +412,21 @@ pub(crate) async fn profiles_append_item_with_filedata_safe(item: &PrfItem, file
|
||||
profiles_append_item_safe(item).await
|
||||
}
|
||||
|
||||
/// Applies `edit` to the committed profiles; commits only when the edit succeeds.
|
||||
async fn with_profiles_edit<F, Fut>(edit: F) -> Result<()>
|
||||
where
|
||||
F: FnOnce(IProfiles) -> Fut + Send,
|
||||
Fut: std::future::Future<Output = Result<IProfiles>> + Send,
|
||||
{
|
||||
Config::profiles()
|
||||
.await
|
||||
.with_data_modify(|profiles| async move {
|
||||
let profiles = edit(profiles).await?;
|
||||
Ok((profiles, ()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn profiles_append_item_safe(item: &mut PrfItem) -> Result<()> {
|
||||
let profiles = Config::profiles().await;
|
||||
profiles_append_item_to_safe(&profiles, item).await
|
||||
@@ -435,43 +442,19 @@ pub(super) async fn profiles_append_item_to_safe(profiles: &Draft<IProfiles>, it
|
||||
}
|
||||
|
||||
pub(crate) async fn profiles_patch_item_safe(index: &str, item: &PrfItem) -> Result<()> {
|
||||
Config::profiles()
|
||||
.await
|
||||
.with_data_modify(|mut profiles| async move {
|
||||
profiles.patch_item(index, item).await?;
|
||||
Ok((profiles, ()))
|
||||
})
|
||||
.await
|
||||
with_profiles_edit(|mut profiles| async move { profiles.patch_item(index, item).await.map(|_| profiles) }).await
|
||||
}
|
||||
|
||||
pub(crate) async fn profiles_reorder_safe(active_id: &str, over_id: &str) -> Result<()> {
|
||||
Config::profiles()
|
||||
.await
|
||||
.with_data_modify(|mut profiles| async move {
|
||||
profiles.reorder(active_id, over_id).await?;
|
||||
Ok((profiles, ()))
|
||||
})
|
||||
.await
|
||||
with_profiles_edit(|mut profiles| async move { profiles.reorder(active_id, over_id).await.map(|_| profiles) }).await
|
||||
}
|
||||
|
||||
pub(crate) async fn profiles_save_file_safe() -> Result<()> {
|
||||
Config::profiles()
|
||||
.await
|
||||
.with_data_modify(|profiles| async move {
|
||||
profiles.save_file().await?;
|
||||
Ok((profiles, ()))
|
||||
})
|
||||
.await
|
||||
with_profiles_edit(|profiles| async move { profiles.save_file().await.map(|_| profiles) }).await
|
||||
}
|
||||
|
||||
pub(crate) async fn profiles_update_item_safe(index: &str, item: &mut PrfItem) -> Result<()> {
|
||||
Config::profiles()
|
||||
.await
|
||||
.with_data_modify(|mut profiles| async move {
|
||||
profiles.update_item(index, item).await?;
|
||||
Ok((profiles, ()))
|
||||
})
|
||||
.await
|
||||
with_profiles_edit(|mut profiles| async move { profiles.update_item(index, item).await.map(|_| profiles) }).await
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@@ -713,19 +696,21 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn current_item_mut(profiles: &mut IProfiles) -> Option<&mut PrfItem> {
|
||||
let current = profiles.current.clone()?;
|
||||
profiles
|
||||
.items
|
||||
.as_mut()?
|
||||
.iter_mut()
|
||||
.find(|item| item.uid.as_ref() == Some(¤t))
|
||||
}
|
||||
|
||||
/// Records a backend-made selection so the next core start restores it.
|
||||
pub(crate) async fn record_selected_node(group_name: &str, node: &str) -> Result<()> {
|
||||
let group_name = String::from(group_name);
|
||||
let node = String::from(node);
|
||||
persist_selected_update(true, move |mut profiles| async move {
|
||||
let Some(current) = profiles.current.clone() else {
|
||||
return Ok((profiles, false));
|
||||
};
|
||||
let Some(item) = profiles
|
||||
.items
|
||||
.as_mut()
|
||||
.and_then(|items| items.iter_mut().find(|item| item.uid.as_ref() == Some(¤t)))
|
||||
else {
|
||||
let Some(item) = current_item_mut(&mut profiles) else {
|
||||
return Ok((profiles, false));
|
||||
};
|
||||
|
||||
@@ -760,14 +745,7 @@ fn remove_selected_node(selected: &mut Vec<PrfSelected>, group_name: &str) -> bo
|
||||
|
||||
pub(crate) async fn forget_selected_node(group_name: &str) -> Result<()> {
|
||||
persist_selected_update(true, move |mut profiles| async move {
|
||||
let Some(current) = profiles.current.clone() else {
|
||||
return Ok((profiles, false));
|
||||
};
|
||||
let Some(item) = profiles
|
||||
.items
|
||||
.as_mut()
|
||||
.and_then(|items| items.iter_mut().find(|item| item.uid.as_ref() == Some(¤t)))
|
||||
else {
|
||||
let Some(item) = current_item_mut(&mut profiles) else {
|
||||
return Ok((profiles, false));
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::config::Config;
|
||||
use crate::{
|
||||
config::{DEFAULT_PAC, deserialize_encrypted, serialize_encrypted},
|
||||
config::{DEFAULT_PAC, deserialize_encrypted, patch_opt_field, serialize_encrypted},
|
||||
constants::network,
|
||||
utils::{dirs, help},
|
||||
};
|
||||
@@ -432,98 +432,90 @@ impl IVerge {
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn patch_config(&mut self, patch: &Self) {
|
||||
macro_rules! patch {
|
||||
($key: tt) => {
|
||||
if patch.$key.is_some() {
|
||||
self.$key = patch.$key.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
patch_opt_field!(self, patch, app_log_level);
|
||||
patch_opt_field!(self, patch, app_log_max_size);
|
||||
patch_opt_field!(self, patch, app_log_max_count);
|
||||
|
||||
patch!(app_log_level);
|
||||
patch!(app_log_max_size);
|
||||
patch!(app_log_max_count);
|
||||
|
||||
patch!(language);
|
||||
patch!(theme_mode);
|
||||
patch!(tray_event);
|
||||
patch!(env_type);
|
||||
patch!(start_page);
|
||||
patch!(startup_script);
|
||||
patch!(traffic_graph);
|
||||
patch!(enable_memory_usage);
|
||||
patch!(enable_group_icon);
|
||||
patch!(pause_render_traffic_stats_on_blur);
|
||||
patch_opt_field!(self, patch, language);
|
||||
patch_opt_field!(self, patch, theme_mode);
|
||||
patch_opt_field!(self, patch, tray_event);
|
||||
patch_opt_field!(self, patch, env_type);
|
||||
patch_opt_field!(self, patch, start_page);
|
||||
patch_opt_field!(self, patch, startup_script);
|
||||
patch_opt_field!(self, patch, traffic_graph);
|
||||
patch_opt_field!(self, patch, enable_memory_usage);
|
||||
patch_opt_field!(self, patch, enable_group_icon);
|
||||
patch_opt_field!(self, patch, pause_render_traffic_stats_on_blur);
|
||||
#[cfg(target_os = "macos")]
|
||||
patch!(tray_icon);
|
||||
patch!(menu_icon);
|
||||
patch!(menu_order);
|
||||
patch!(proxy_group_tools_position);
|
||||
patch!(notice_position);
|
||||
patch!(collapse_navbar);
|
||||
patch!(common_tray_icon);
|
||||
patch!(sysproxy_tray_icon);
|
||||
patch!(tun_tray_icon);
|
||||
patch_opt_field!(self, patch, tray_icon);
|
||||
patch_opt_field!(self, patch, menu_icon);
|
||||
patch_opt_field!(self, patch, menu_order);
|
||||
patch_opt_field!(self, patch, proxy_group_tools_position);
|
||||
patch_opt_field!(self, patch, notice_position);
|
||||
patch_opt_field!(self, patch, collapse_navbar);
|
||||
patch_opt_field!(self, patch, common_tray_icon);
|
||||
patch_opt_field!(self, patch, sysproxy_tray_icon);
|
||||
patch_opt_field!(self, patch, tun_tray_icon);
|
||||
|
||||
patch!(enable_tun_mode);
|
||||
patch!(enable_auto_launch);
|
||||
patch!(enable_silent_start);
|
||||
patch!(enable_hover_jump_navigator);
|
||||
patch!(hover_jump_navigator_delay);
|
||||
patch_opt_field!(self, patch, enable_tun_mode);
|
||||
patch_opt_field!(self, patch, enable_auto_launch);
|
||||
patch_opt_field!(self, patch, enable_silent_start);
|
||||
patch_opt_field!(self, patch, enable_hover_jump_navigator);
|
||||
patch_opt_field!(self, patch, hover_jump_navigator_delay);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
patch!(verge_redir_port);
|
||||
patch_opt_field!(self, patch, verge_redir_port);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
patch!(verge_redir_enabled);
|
||||
patch_opt_field!(self, patch, verge_redir_enabled);
|
||||
#[cfg(target_os = "linux")]
|
||||
patch!(verge_tproxy_port);
|
||||
patch_opt_field!(self, patch, verge_tproxy_port);
|
||||
#[cfg(target_os = "linux")]
|
||||
patch!(verge_tproxy_enabled);
|
||||
patch!(verge_mixed_port);
|
||||
patch!(verge_socks_port);
|
||||
patch!(verge_socks_enabled);
|
||||
patch!(verge_port);
|
||||
patch!(verge_http_enabled);
|
||||
patch!(enable_system_proxy);
|
||||
patch!(enable_proxy_guard);
|
||||
patch!(enable_bypass_check);
|
||||
patch!(use_default_bypass);
|
||||
patch!(system_proxy_bypass);
|
||||
patch!(proxy_guard_duration);
|
||||
patch!(proxy_auto_config);
|
||||
patch!(pac_file_content);
|
||||
patch!(proxy_host);
|
||||
patch!(theme_setting);
|
||||
patch!(web_ui_list);
|
||||
patch!(clash_core);
|
||||
patch!(hotkeys);
|
||||
patch!(enable_global_hotkey);
|
||||
patch_opt_field!(self, patch, verge_tproxy_enabled);
|
||||
patch_opt_field!(self, patch, verge_mixed_port);
|
||||
patch_opt_field!(self, patch, verge_socks_port);
|
||||
patch_opt_field!(self, patch, verge_socks_enabled);
|
||||
patch_opt_field!(self, patch, verge_port);
|
||||
patch_opt_field!(self, patch, verge_http_enabled);
|
||||
patch_opt_field!(self, patch, enable_system_proxy);
|
||||
patch_opt_field!(self, patch, enable_proxy_guard);
|
||||
patch_opt_field!(self, patch, enable_bypass_check);
|
||||
patch_opt_field!(self, patch, use_default_bypass);
|
||||
patch_opt_field!(self, patch, system_proxy_bypass);
|
||||
patch_opt_field!(self, patch, proxy_guard_duration);
|
||||
patch_opt_field!(self, patch, proxy_auto_config);
|
||||
patch_opt_field!(self, patch, pac_file_content);
|
||||
patch_opt_field!(self, patch, proxy_host);
|
||||
patch_opt_field!(self, patch, theme_setting);
|
||||
patch_opt_field!(self, patch, web_ui_list);
|
||||
patch_opt_field!(self, patch, clash_core);
|
||||
patch_opt_field!(self, patch, hotkeys);
|
||||
patch_opt_field!(self, patch, enable_global_hotkey);
|
||||
|
||||
patch!(auto_close_connection);
|
||||
patch!(auto_check_update);
|
||||
patch!(default_latency_test);
|
||||
patch!(default_latency_timeout);
|
||||
patch!(enable_auto_delay_detection);
|
||||
patch!(auto_delay_detection_interval_minutes);
|
||||
patch!(enable_builtin_enhanced);
|
||||
patch!(proxy_layout_column);
|
||||
patch!(test_list);
|
||||
patch!(auto_log_clean);
|
||||
patch!(enable_auto_backup_schedule);
|
||||
patch!(auto_backup_interval_hours);
|
||||
patch!(auto_backup_on_change);
|
||||
patch_opt_field!(self, patch, auto_close_connection);
|
||||
patch_opt_field!(self, patch, auto_check_update);
|
||||
patch_opt_field!(self, patch, default_latency_test);
|
||||
patch_opt_field!(self, patch, default_latency_timeout);
|
||||
patch_opt_field!(self, patch, enable_auto_delay_detection);
|
||||
patch_opt_field!(self, patch, auto_delay_detection_interval_minutes);
|
||||
patch_opt_field!(self, patch, enable_builtin_enhanced);
|
||||
patch_opt_field!(self, patch, proxy_layout_column);
|
||||
patch_opt_field!(self, patch, test_list);
|
||||
patch_opt_field!(self, patch, auto_log_clean);
|
||||
patch_opt_field!(self, patch, enable_auto_backup_schedule);
|
||||
patch_opt_field!(self, patch, auto_backup_interval_hours);
|
||||
patch_opt_field!(self, patch, auto_backup_on_change);
|
||||
|
||||
patch!(webdav_url);
|
||||
patch!(webdav_username);
|
||||
patch!(webdav_password);
|
||||
patch_opt_field!(self, patch, webdav_url);
|
||||
patch_opt_field!(self, patch, webdav_username);
|
||||
patch_opt_field!(self, patch, webdav_password);
|
||||
#[cfg(target_os = "macos")]
|
||||
patch!(enable_tray_speed);
|
||||
patch!(tray_proxy_groups_display_mode);
|
||||
patch!(tray_inline_outbound_modes);
|
||||
patch!(enable_auto_light_weight_mode);
|
||||
patch!(auto_light_weight_minutes);
|
||||
patch!(enable_dns_settings);
|
||||
patch!(home_cards);
|
||||
patch!(enable_external_controller);
|
||||
patch_opt_field!(self, patch, enable_tray_speed);
|
||||
patch_opt_field!(self, patch, tray_proxy_groups_display_mode);
|
||||
patch_opt_field!(self, patch, tray_inline_outbound_modes);
|
||||
patch_opt_field!(self, patch, enable_auto_light_weight_mode);
|
||||
patch_opt_field!(self, patch, auto_light_weight_minutes);
|
||||
patch_opt_field!(self, patch, enable_dns_settings);
|
||||
patch_opt_field!(self, patch, home_cards);
|
||||
patch_opt_field!(self, patch, enable_external_controller);
|
||||
}
|
||||
|
||||
pub fn get_log_level(&self) -> LevelFilter {
|
||||
|
||||
Reference in New Issue
Block a user