mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-28 16:30:52 +08:00
feat: Implement configuration caching mechanism and force-refresh feature**
✨ **New Features**: * Added API and frontend support for forcibly refreshing Clash configuration cache * Implemented a configuration cache TTL mechanism (60 seconds) to reduce redundant requests * Introduced `ProxyRequestCache` system to manage backend data caching * Automatically refresh frontend state after core operations to enhance user experience 🚀 **Performance Optimizations**: * Increased Clash configuration refresh interval from 5 seconds to 60 seconds * Force refresh cache after configuration updates to resolve data inconsistency * Automatically trigger state refresh after core switch, start, stop, and restart actions 🔧 **Technical Improvements**: * Removed unused dependencies: `ab_glyph`, `owned_ttf_parser`, `ttf-parser` * Simplified WebSocket dependency management, unified `tungstenite` version * Refactored configuration save validation process, improved merge file handling * Improved error handling and overall user experience
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
- **核心架构升级**:与内核 Mihomo 采用 IPC 通信,不再依赖 Restful API 通信,提升性能和稳定性
|
- **核心架构升级**:与内核 Mihomo 采用 IPC 通信,不再依赖 Restful API 通信,提升性能和稳定性
|
||||||
- **流量监控系统重构**:前端实现全新的增强流量监控系统,支持数据压缩、采样和智能缓存
|
- **流量监控系统重构**:前端实现全新的增强流量监控系统,支持数据压缩、采样和智能缓存
|
||||||
- **数据验证机制**:引入类型安全的数据验证器,确保 API 响应数据的一致性和可靠性
|
- **数据验证机制**:引入类型安全的数据验证器,确保 API 响应数据的一致性和可靠性
|
||||||
|
- **配置缓存架构**:实现智能配置缓存系统,支持后端数据缓存和强制刷新机制
|
||||||
|
|
||||||
### ✨ 新增功能
|
### ✨ 新增功能
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@
|
|||||||
- 引用计数管理器智能收集数据
|
- 引用计数管理器智能收集数据
|
||||||
- 新增流量监控诊断工具与错误边界组件
|
- 新增流量监控诊断工具与错误边界组件
|
||||||
- 多版本画布流量图表,丰富可视化选项
|
- 多版本画布流量图表,丰富可视化选项
|
||||||
|
- 新增强制刷新 Clash 配置/节点缓存功能,提升更新响应速度
|
||||||
|
- 增加代理请求缓存机制,减少重复 API 调用
|
||||||
|
|
||||||
### 🚀 性能优化
|
### 🚀 性能优化
|
||||||
|
|
||||||
@@ -22,6 +25,8 @@
|
|||||||
- 引用计数机制避免不必要的数据收集,提升整体性能
|
- 引用计数机制避免不必要的数据收集,提升整体性能
|
||||||
- 优化流量图表渲染性能,支持大数据量展示
|
- 优化流量图表渲染性能,支持大数据量展示
|
||||||
- 改进前端数据获取和缓存策略
|
- 改进前端数据获取和缓存策略
|
||||||
|
- 实现配置/节点缓存 TTL 机制,减少不必要的配置/节点请求
|
||||||
|
- 改进 Clash 配置/节点刷新间隔,从5秒优化到60秒,减少系统资源消耗
|
||||||
|
|
||||||
### 🐞 修复问题
|
### 🐞 修复问题
|
||||||
|
|
||||||
@@ -30,6 +35,8 @@
|
|||||||
- 增强代理更新的错误处理机制
|
- 增强代理更新的错误处理机制
|
||||||
- 修复 JSON 解析错误处理
|
- 修复 JSON 解析错误处理
|
||||||
- 优化调试日志输出,减少噪音
|
- 优化调试日志输出,减少噪音
|
||||||
|
- 修复配置修改后前端缓存不同步问题
|
||||||
|
- 改进核心启动/停止/重启后的状态刷新机制
|
||||||
|
|
||||||
### 🔧 技术改进
|
### 🔧 技术改进
|
||||||
|
|
||||||
|
|||||||
85
src-tauri/Cargo.lock
generated
85
src-tauri/Cargo.lock
generated
@@ -2,22 +2,6 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ab_glyph"
|
|
||||||
version = "0.2.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d"
|
|
||||||
dependencies = [
|
|
||||||
"ab_glyph_rasterizer",
|
|
||||||
"owned_ttf_parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ab_glyph_rasterizer"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.24.2"
|
version = "0.24.2"
|
||||||
@@ -1125,7 +1109,6 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
|||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph",
|
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1185,8 +1168,6 @@ dependencies = [
|
|||||||
"tauri-plugin-window-state",
|
"tauri-plugin-window-state",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite 0.24.0",
|
|
||||||
"tungstenite 0.27.0",
|
|
||||||
"users",
|
"users",
|
||||||
"warp",
|
"warp",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -4933,15 +4914,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "owned_ttf_parser"
|
|
||||||
version = "0.25.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
|
|
||||||
dependencies = [
|
|
||||||
"ttf-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.18.3"
|
version = "0.18.3"
|
||||||
@@ -7898,19 +7870,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tungstenite 0.21.0",
|
"tungstenite",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-tungstenite"
|
|
||||||
version = "0.24.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
|
|
||||||
dependencies = [
|
|
||||||
"futures-util",
|
|
||||||
"log",
|
|
||||||
"tokio",
|
|
||||||
"tungstenite 0.24.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8274,12 +8234,6 @@ version = "0.2.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ttf-parser"
|
|
||||||
version = "0.25.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tungstenite"
|
name = "tungstenite"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
@@ -8299,41 +8253,6 @@ dependencies = [
|
|||||||
"utf-8",
|
"utf-8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tungstenite"
|
|
||||||
version = "0.24.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"bytes",
|
|
||||||
"data-encoding",
|
|
||||||
"http 1.3.1",
|
|
||||||
"httparse",
|
|
||||||
"log",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"sha1",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
"utf-8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tungstenite"
|
|
||||||
version = "0.27.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"data-encoding",
|
|
||||||
"http 1.3.1",
|
|
||||||
"httparse",
|
|
||||||
"log",
|
|
||||||
"rand 0.9.2",
|
|
||||||
"sha1",
|
|
||||||
"thiserror 2.0.12",
|
|
||||||
"utf-8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typeid"
|
name = "typeid"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@@ -8644,7 +8563,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-tungstenite 0.21.0",
|
"tokio-tungstenite",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
use super::CmdResult;
|
use super::CmdResult;
|
||||||
use crate::{config::*, core::*, feat, ipc::IpcManager, process::AsyncHandler, wrap_err};
|
use crate::{
|
||||||
|
config::*, core::*, feat, ipc::IpcManager, process::AsyncHandler,
|
||||||
|
state::proxy::ProxyRequestCache, wrap_err,
|
||||||
|
};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const CONFIG_REFRESH_INTERVAL: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
/// 复制Clash环境变量
|
/// 复制Clash环境变量
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -66,19 +72,31 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult<Option<String>>
|
|||||||
/// 启动核心
|
/// 启动核心
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn start_core() -> CmdResult {
|
pub async fn start_core() -> CmdResult {
|
||||||
wrap_err!(CoreManager::global().start_core().await)
|
let result = wrap_err!(CoreManager::global().start_core().await);
|
||||||
|
if result.is_ok() {
|
||||||
|
handle::Handle::refresh_clash();
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 关闭核心
|
/// 关闭核心
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn stop_core() -> CmdResult {
|
pub async fn stop_core() -> CmdResult {
|
||||||
wrap_err!(CoreManager::global().stop_core().await)
|
let result = wrap_err!(CoreManager::global().stop_core().await);
|
||||||
|
if result.is_ok() {
|
||||||
|
handle::Handle::refresh_clash();
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 重启核心
|
/// 重启核心
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn restart_core() -> CmdResult {
|
pub async fn restart_core() -> CmdResult {
|
||||||
wrap_err!(CoreManager::global().restart_core().await)
|
let result = wrap_err!(CoreManager::global().restart_core().await);
|
||||||
|
if result.is_ok() {
|
||||||
|
handle::Handle::refresh_clash();
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取代理延迟
|
/// 获取代理延迟
|
||||||
@@ -277,7 +295,24 @@ pub async fn get_clash_version() -> CmdResult<serde_json::Value> {
|
|||||||
/// 获取Clash配置
|
/// 获取Clash配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_clash_config() -> CmdResult<serde_json::Value> {
|
pub async fn get_clash_config() -> CmdResult<serde_json::Value> {
|
||||||
wrap_err!(IpcManager::global().get_config().await)
|
let manager = IpcManager::global();
|
||||||
|
let cache = ProxyRequestCache::global();
|
||||||
|
let key = ProxyRequestCache::make_key("clash_config", "default");
|
||||||
|
let value = cache
|
||||||
|
.get_or_fetch(key, CONFIG_REFRESH_INTERVAL, || async {
|
||||||
|
manager.get_config().await.expect("fetch failed")
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
Ok((*value).clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 强制刷新Clash配置缓存
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn force_refresh_clash_config() -> CmdResult<serde_json::Value> {
|
||||||
|
let cache = ProxyRequestCache::global();
|
||||||
|
let key = ProxyRequestCache::make_key("clash_config", "default");
|
||||||
|
cache.map.remove(&key);
|
||||||
|
get_clash_config().await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新地理数据
|
/// 更新地理数据
|
||||||
|
|||||||
@@ -61,14 +61,20 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
|||||||
"[cmd配置save] merge文件语法验证通过"
|
"[cmd配置save] merge文件语法验证通过"
|
||||||
);
|
);
|
||||||
// 成功后尝试更新整体配置
|
// 成功后尝试更新整体配置
|
||||||
if let Err(e) = CoreManager::global().update_config().await {
|
match CoreManager::global().update_config().await {
|
||||||
logging!(
|
Ok(_) => {
|
||||||
warn,
|
// 配置更新成功,刷新前端
|
||||||
Type::Config,
|
handle::Handle::refresh_clash();
|
||||||
true,
|
}
|
||||||
"[cmd配置save] 更新整体配置时发生错误: {}",
|
Err(e) => {
|
||||||
e
|
logging!(
|
||||||
);
|
warn,
|
||||||
|
Type::Config,
|
||||||
|
true,
|
||||||
|
"[cmd配置save] 更新整体配置时发生错误: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ pub fn run() {
|
|||||||
cmd::validate_dns_config,
|
cmd::validate_dns_config,
|
||||||
cmd::get_clash_version,
|
cmd::get_clash_version,
|
||||||
cmd::get_clash_config,
|
cmd::get_clash_config,
|
||||||
|
cmd::force_refresh_clash_config,
|
||||||
cmd::update_geo_data,
|
cmd::update_geo_data,
|
||||||
cmd::upgrade_clash_core,
|
cmd::upgrade_clash_core,
|
||||||
cmd::get_clash_rules,
|
cmd::get_clash_rules,
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ import {
|
|||||||
ListItemText,
|
ListItemText,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { changeClashCore, restartCore } from "@/services/cmds";
|
import { changeClashCore, restartCore } from "@/services/cmds";
|
||||||
import { closeAllConnections, upgradeCore } from "@/services/cmds";
|
import {
|
||||||
|
closeAllConnections,
|
||||||
|
upgradeCore,
|
||||||
|
forceRefreshClashConfig,
|
||||||
|
} from "@/services/cmds";
|
||||||
import { showNotice } from "@/services/noticeService";
|
import { showNotice } from "@/services/noticeService";
|
||||||
|
|
||||||
const VALID_CORE = [
|
const VALID_CORE = [
|
||||||
@@ -58,7 +62,9 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutateVerge();
|
mutateVerge();
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
|
// 核心切换后强制刷新配置缓存
|
||||||
|
await forceRefreshClashConfig();
|
||||||
mutate("getClashConfig");
|
mutate("getClashConfig");
|
||||||
mutate("getVersion");
|
mutate("getVersion");
|
||||||
setChangingCore(null);
|
setChangingCore(null);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
getClashInfo,
|
getClashInfo,
|
||||||
patchClashConfig,
|
patchClashConfig,
|
||||||
getRuntimeConfig,
|
getRuntimeConfig,
|
||||||
|
forceRefreshClashConfig,
|
||||||
} from "@/services/cmds";
|
} from "@/services/cmds";
|
||||||
|
|
||||||
export const useClash = () => {
|
export const useClash = () => {
|
||||||
@@ -121,6 +122,8 @@ export const useClashInfo = () => {
|
|||||||
|
|
||||||
await patchClashConfig(patch);
|
await patchClashConfig(patch);
|
||||||
mutateInfo();
|
mutateInfo();
|
||||||
|
// 配置修改后强制刷新缓存
|
||||||
|
await forceRefreshClashConfig();
|
||||||
mutate("getClashConfig");
|
mutate("getClashConfig");
|
||||||
// IPC调用不需要刷新axios实例
|
// IPC调用不需要刷新axios实例
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { List, Paper, ThemeProvider, SvgIcon } from "@mui/material";
|
|||||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
import { routers } from "./_routers";
|
import { routers } from "./_routers";
|
||||||
import { getAxios } from "@/services/api";
|
import { getAxios } from "@/services/api";
|
||||||
|
import { forceRefreshClashConfig } from "@/services/cmds";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import LogoSvg from "@/assets/image/logo.svg?react";
|
import LogoSvg from "@/assets/image/logo.svg?react";
|
||||||
import iconLight from "@/assets/image/icon_light.svg?react";
|
import iconLight from "@/assets/image/icon_light.svg?react";
|
||||||
@@ -192,6 +193,8 @@ const Layout = () => {
|
|||||||
const listeners = [
|
const listeners = [
|
||||||
addListener("verge://refresh-clash-config", async () => {
|
addListener("verge://refresh-clash-config", async () => {
|
||||||
await getAxios(true);
|
await getAxios(true);
|
||||||
|
// 后端配置变更事件触发,强制刷新配置缓存
|
||||||
|
await forceRefreshClashConfig();
|
||||||
mutate("getProxies");
|
mutate("getProxies");
|
||||||
mutate("getVersion");
|
mutate("getVersion");
|
||||||
mutate("getClashConfig");
|
mutate("getClashConfig");
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const AppDataProvider = ({
|
|||||||
"getClashConfig",
|
"getClashConfig",
|
||||||
getClashConfig,
|
getClashConfig,
|
||||||
{
|
{
|
||||||
refreshInterval: 5000,
|
refreshInterval: 60000, // 60秒刷新间隔,减少频繁请求
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
suspense: false,
|
suspense: false,
|
||||||
errorRetryCount: 3,
|
errorRetryCount: 3,
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ export async function getClashConfig() {
|
|||||||
return invoke<IConfigData>("get_clash_config");
|
return invoke<IConfigData>("get_clash_config");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function forceRefreshClashConfig() {
|
||||||
|
return invoke<IConfigData>("force_refresh_clash_config");
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateGeoData() {
|
export async function updateGeoData() {
|
||||||
return invoke<void>("update_geo_data");
|
return invoke<void>("update_geo_data");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user