Merge branch 'dev' into chore/i18n
This commit is contained in:
4
.github/workflows/autobuild.yml
vendored
4
.github/workflows/autobuild.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
|
||||
### Windows (不再支持Win7)
|
||||
#### 正常版本(推荐)
|
||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup_windows.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup.exe)
|
||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup_windows.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup_windows.exe)
|
||||
|
||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_fixed_webview2-setup.exe) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64_fixed_webview2-setup.exe)
|
||||
@@ -578,7 +578,7 @@ jobs:
|
||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_amd64_linux.deb) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64.deb) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_armhf.deb)
|
||||
|
||||
#### RPM包(Redhat系) 使用 dnf ./路径 安装
|
||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.x86_64_linux.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.armhfp.rpm)
|
||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.x86_64_linux.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.armhfp.rpm)
|
||||
|
||||
### FAQ
|
||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## v2.4.3
|
||||
|
||||
感谢 @Slinetrac, @oomeow 以及 @Lythrilla 的出色贡献
|
||||
感谢 @Slinetrac, @oomeow, @Lythrilla, @Dragon1573 的出色贡献
|
||||
|
||||
### 🐞 修复问题
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
- 修复 macOS 从 Dock 栏退出轻量模式状态不同步
|
||||
- 修复 Linux 系统主题切换不生效
|
||||
- 修复 `允许自动更新` 字段使手动订阅刷新失效
|
||||
- 修复轻量模式托盘状态不同步
|
||||
|
||||
<details>
|
||||
<summary><strong> ✨ 新增功能 </strong></summary>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
"@tauri-apps/cli": "2.9.2",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^24.9.2",
|
||||
"@types/node": "^24.10.0",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"@vitejs/plugin-legacy": "^7.2.1",
|
||||
|
||||
48
pnpm-lock.yaml
generated
48
pnpm-lock.yaml
generated
@@ -154,8 +154,8 @@ importers:
|
||||
specifier: ^4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: ^24.9.2
|
||||
version: 24.9.2
|
||||
specifier: ^24.10.0
|
||||
version: 24.10.0
|
||||
'@types/react':
|
||||
specifier: 19.2.2
|
||||
version: 19.2.2
|
||||
@@ -164,10 +164,10 @@ importers:
|
||||
version: 19.2.2(@types/react@19.2.2)
|
||||
'@vitejs/plugin-legacy':
|
||||
specifier: ^7.2.1
|
||||
version: 7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 4.2.0(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
adm-zip:
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.16
|
||||
@@ -248,16 +248,16 @@ importers:
|
||||
version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
vite:
|
||||
specifier: ^7.1.12
|
||||
version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
version: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-monaco-editor-esm:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2(monaco-editor@0.54.0)
|
||||
vite-plugin-svgr:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
vitest:
|
||||
specifier: ^4.0.6
|
||||
version: 4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
version: 4.0.6(@types/debug@4.1.12)(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1821,8 +1821,8 @@ packages:
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==}
|
||||
'@types/node@24.10.0':
|
||||
resolution: {integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -5982,7 +5982,7 @@ snapshots:
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
'@types/node@24.10.0':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
@@ -6160,7 +6160,7 @@ snapshots:
|
||||
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
|
||||
optional: true
|
||||
|
||||
'@vitejs/plugin-legacy@7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitejs/plugin-legacy@7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.4
|
||||
'@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4)
|
||||
@@ -6175,15 +6175,15 @@ snapshots:
|
||||
regenerator-runtime: 0.14.1
|
||||
systemjs: 6.15.1
|
||||
terser: 5.44.0
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.43
|
||||
'@swc/core': 1.14.0
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
@@ -6196,13 +6196,13 @@ snapshots:
|
||||
chai: 6.2.0
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.6(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitest/mocker@4.0.6(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.6
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.19
|
||||
optionalDependencies:
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
'@vitest/pretty-format@4.0.6':
|
||||
dependencies:
|
||||
@@ -8844,18 +8844,18 @@ snapshots:
|
||||
dependencies:
|
||||
monaco-editor: 0.54.0
|
||||
|
||||
vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.46.2)
|
||||
'@svgr/core': 8.1.0(typescript@5.9.3)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1):
|
||||
vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -8864,17 +8864,17 @@ snapshots:
|
||||
rollup: 4.46.2
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.9.2
|
||||
'@types/node': 24.10.0
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
sass: 1.93.3
|
||||
terser: 5.44.0
|
||||
yaml: 2.8.1
|
||||
|
||||
vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1):
|
||||
vitest@4.0.6(@types/debug@4.1.12)(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.6
|
||||
'@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitest/mocker': 4.0.6(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitest/pretty-format': 4.0.6
|
||||
'@vitest/runner': 4.0.6
|
||||
'@vitest/snapshot': 4.0.6
|
||||
@@ -8891,11 +8891,11 @@ snapshots:
|
||||
tinyexec: 0.3.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.3)(terser@5.44.0)(yaml@2.8.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.12
|
||||
'@types/node': 24.9.2
|
||||
'@types/node': 24.10.0
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
|
||||
7
src-tauri/Cargo.lock
generated
7
src-tauri/Cargo.lock
generated
@@ -152,6 +152,12 @@ dependencies = [
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
@@ -1093,6 +1099,7 @@ version = "2.4.3"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
"backoff",
|
||||
"base64 0.22.1",
|
||||
|
||||
@@ -86,6 +86,7 @@ smartstring = { version = "1.0.1", features = ["serde"] }
|
||||
clash_verge_service_ipc = { version = "2.0.21", features = [
|
||||
"client",
|
||||
], git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
||||
arc-swap = "1.7.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
|
||||
@@ -15,68 +15,19 @@ use crate::{
|
||||
ret_err,
|
||||
utils::{dirs, help, logging::Type},
|
||||
};
|
||||
use scopeguard::defer;
|
||||
use smartstring::alias::String;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
// 全局请求序列号跟踪,用于避免队列化执行
|
||||
static CURRENT_REQUEST_SEQUENCE: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
static CURRENT_SWITCHING_PROFILE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_profiles() -> CmdResult<IProfiles> {
|
||||
// 策略1: 尝试快速获取latest数据
|
||||
let latest_result = tokio::time::timeout(Duration::from_millis(500), async {
|
||||
let profiles = Config::profiles().await;
|
||||
let latest = profiles.latest_ref();
|
||||
IProfiles {
|
||||
current: latest.current.clone(),
|
||||
items: latest.items.clone(),
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
match latest_result {
|
||||
Ok(profiles) => {
|
||||
logging!(info, Type::Cmd, "快速获取配置列表成功");
|
||||
return Ok(profiles);
|
||||
}
|
||||
Err(_) => {
|
||||
logging!(warn, Type::Cmd, "快速获取配置超时(500ms)");
|
||||
}
|
||||
}
|
||||
|
||||
// 策略2: 如果快速获取失败,尝试获取data()
|
||||
let data_result = tokio::time::timeout(Duration::from_secs(2), async {
|
||||
let profiles = Config::profiles().await;
|
||||
let data = profiles.latest_ref();
|
||||
IProfiles {
|
||||
current: data.current.clone(),
|
||||
items: data.items.clone(),
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
match data_result {
|
||||
Ok(profiles) => {
|
||||
logging!(info, Type::Cmd, "获取draft配置列表成功");
|
||||
return Ok(profiles);
|
||||
}
|
||||
Err(join_err) => {
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"获取draft配置任务失败或超时: {}",
|
||||
join_err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 策略3: fallback,尝试重新创建配置
|
||||
logging!(warn, Type::Cmd, "所有获取配置策略都失败,尝试fallback");
|
||||
|
||||
Ok(IProfiles::new().await)
|
||||
logging!(debug, Type::Cmd, "获取配置文件列表");
|
||||
let draft = Config::profiles().await;
|
||||
let latest = draft.latest_ref();
|
||||
Ok((**latest).clone())
|
||||
}
|
||||
|
||||
/// 增强配置文件
|
||||
@@ -332,7 +283,7 @@ async fn restore_previous_profile(prev_profile: String) -> CmdResult<()> {
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.patch_config(&restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
crate::process::AsyncHandler::spawn(|| async move {
|
||||
@@ -344,26 +295,7 @@ async fn restore_previous_profile(prev_profile: String) -> CmdResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_success(current_sequence: u64, current_value: Option<String>) -> CmdResult<bool> {
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"内核操作后发现更新的请求 (序列号: {} < {}),忽略当前结果",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"配置更新成功,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
async fn handle_success(current_value: Option<String>) -> CmdResult<bool> {
|
||||
Config::profiles().await.apply();
|
||||
handle::Handle::refresh_clash();
|
||||
|
||||
@@ -380,17 +312,10 @@ async fn handle_success(current_sequence: u64, current_value: Option<String>) ->
|
||||
}
|
||||
|
||||
if let Some(current) = ¤t_value {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"向前端发送配置变更事件: {}, 序列号: {}",
|
||||
current,
|
||||
current_sequence
|
||||
);
|
||||
logging!(info, Type::Cmd, "向前端发送配置变更事件: {}", current,);
|
||||
handle::Handle::notify_profile_changed(current.clone());
|
||||
}
|
||||
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -404,53 +329,31 @@ async fn handle_validation_failure(
|
||||
restore_previous_profile(prev_profile).await?;
|
||||
}
|
||||
handle::Handle::notice_message("config_validate::error", error_msg);
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn handle_update_error<E: std::fmt::Display>(e: E, current_sequence: u64) -> CmdResult<bool> {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Cmd,
|
||||
"更新过程发生错误: {}, 序列号: {}",
|
||||
e,
|
||||
current_sequence
|
||||
);
|
||||
async fn handle_update_error<E: std::fmt::Display>(e: E) -> CmdResult<bool> {
|
||||
logging!(warn, Type::Cmd, "更新过程发生错误: {}", e,);
|
||||
Config::profiles().await.discard();
|
||||
handle::Handle::notice_message("config_validate::boot_error", e.to_string());
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn handle_timeout(current_profile: Option<String>, current_sequence: u64) -> CmdResult<bool> {
|
||||
async fn handle_timeout(current_profile: Option<String>) -> CmdResult<bool> {
|
||||
let timeout_msg = "配置更新超时(30秒),可能是配置验证或核心通信阻塞";
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"{}, 序列号: {}",
|
||||
timeout_msg,
|
||||
current_sequence
|
||||
);
|
||||
logging!(error, Type::Cmd, "{}", timeout_msg);
|
||||
Config::profiles().await.discard();
|
||||
if let Some(prev_profile) = current_profile {
|
||||
restore_previous_profile(prev_profile).await?;
|
||||
}
|
||||
handle::Handle::notice_message("config_validate::timeout", timeout_msg);
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn perform_config_update(
|
||||
current_sequence: u64,
|
||||
current_value: Option<String>,
|
||||
current_profile: Option<String>,
|
||||
) -> CmdResult<bool> {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"开始内核配置更新,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
let update_result = tokio::time::timeout(
|
||||
Duration::from_secs(30),
|
||||
CoreManager::global().update_config(),
|
||||
@@ -458,46 +361,36 @@ async fn perform_config_update(
|
||||
.await;
|
||||
|
||||
match update_result {
|
||||
Ok(Ok((true, _))) => handle_success(current_sequence, current_value).await,
|
||||
Ok(Ok((true, _))) => handle_success(current_value).await,
|
||||
Ok(Ok((false, error_msg))) => handle_validation_failure(error_msg, current_profile).await,
|
||||
Ok(Err(e)) => handle_update_error(e, current_sequence).await,
|
||||
Err(_) => handle_timeout(current_profile, current_sequence).await,
|
||||
Ok(Err(e)) => handle_update_error(e).await,
|
||||
Err(_) => handle_timeout(current_profile).await,
|
||||
}
|
||||
}
|
||||
|
||||
/// 修改profiles的配置
|
||||
#[tauri::command]
|
||||
pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
if CURRENT_SWITCHING_PROFILE.load(Ordering::SeqCst) {
|
||||
if CURRENT_SWITCHING_PROFILE
|
||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
logging!(info, Type::Cmd, "当前正在切换配置,放弃请求");
|
||||
return Ok(false);
|
||||
return Err("switch_in_progress".into());
|
||||
}
|
||||
CURRENT_SWITCHING_PROFILE.store(true, Ordering::SeqCst);
|
||||
|
||||
// 为当前请求分配序列号
|
||||
let current_sequence = CURRENT_REQUEST_SEQUENCE.fetch_add(1, Ordering::SeqCst) + 1;
|
||||
defer! {
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::Release);
|
||||
}
|
||||
let target_profile = profiles.current.clone();
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"开始修改配置文件,请求序列号: {}, 目标profile: {:?}",
|
||||
current_sequence,
|
||||
"开始修改配置文件,目标profile: {:?}",
|
||||
target_profile
|
||||
);
|
||||
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"获取锁后发现更新的请求 (序列号: {} < {}),放弃当前请求",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 保存当前配置,以便在验证失败时恢复
|
||||
let current_profile = Config::profiles().await.latest_ref().current.clone();
|
||||
logging!(info, Type::Cmd, "当前配置: {:?}", current_profile);
|
||||
@@ -507,50 +400,13 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
&& current_profile.as_ref() != Some(new_profile)
|
||||
&& validate_new_profile(new_profile).await.is_err()
|
||||
{
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 检查请求有效性
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"在核心操作前发现更新的请求 (序列号: {} < {}),放弃当前请求",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 更新profiles配置
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"正在更新配置草稿,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
|
||||
let _ = Config::profiles().await.draft_mut().patch_config(&profiles);
|
||||
let current_value = profiles.current.clone();
|
||||
|
||||
let _ = Config::profiles().await.draft_mut().patch_config(profiles);
|
||||
|
||||
// 在调用内核前再次验证请求有效性
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"在内核交互前发现更新的请求 (序列号: {} < {}),放弃当前请求",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
perform_config_update(current_sequence, current_value, current_profile).await
|
||||
perform_config_update(current_value, current_profile).await
|
||||
}
|
||||
|
||||
/// 根据profile name修改profiles
|
||||
|
||||
@@ -69,23 +69,16 @@ impl IProfiles {
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
Self::template()
|
||||
Self::default()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
Self::template()
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn template() -> Self {
|
||||
Self {
|
||||
items: Some(vec![]),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save_file(&self) -> Result<()> {
|
||||
help::save_yaml(
|
||||
&dirs::profiles_path()?,
|
||||
@@ -96,17 +89,17 @@ impl IProfiles {
|
||||
}
|
||||
|
||||
/// 只修改current,valid和chain
|
||||
pub fn patch_config(&mut self, patch: IProfiles) -> Result<()> {
|
||||
pub fn patch_config(&mut self, patch: &IProfiles) -> Result<()> {
|
||||
if self.items.is_none() {
|
||||
self.items = Some(vec![]);
|
||||
}
|
||||
|
||||
if let Some(current) = patch.current
|
||||
if let Some(current) = &patch.current
|
||||
&& let Some(items) = self.items.as_ref()
|
||||
{
|
||||
let some_uid = Some(current);
|
||||
if items.iter().any(|e| e.uid == some_uid) {
|
||||
self.current = some_uid;
|
||||
if items.iter().any(|e| e.uid.as_ref() == some_uid) {
|
||||
self.current = some_uid.cloned();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::{
|
||||
utils::{dirs, logging::Type},
|
||||
};
|
||||
use anyhow::Error;
|
||||
use arc_swap::{ArcSwap, ArcSwapOption};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use reqwest_dav::list_cmd::{ListEntity, ListFile};
|
||||
use smartstring::alias::String;
|
||||
use std::{
|
||||
@@ -56,24 +56,24 @@ impl Operation {
|
||||
}
|
||||
|
||||
pub struct WebDavClient {
|
||||
config: Arc<Mutex<Option<WebDavConfig>>>,
|
||||
clients: Arc<Mutex<HashMap<Operation, reqwest_dav::Client>>>,
|
||||
config: Arc<ArcSwapOption<WebDavConfig>>,
|
||||
clients: Arc<ArcSwap<HashMap<Operation, reqwest_dav::Client>>>,
|
||||
}
|
||||
|
||||
impl WebDavClient {
|
||||
pub fn global() -> &'static WebDavClient {
|
||||
static WEBDAV_CLIENT: OnceCell<WebDavClient> = OnceCell::new();
|
||||
WEBDAV_CLIENT.get_or_init(|| WebDavClient {
|
||||
config: Arc::new(Mutex::new(None)),
|
||||
clients: Arc::new(Mutex::new(HashMap::new())),
|
||||
config: Arc::new(ArcSwapOption::new(None)),
|
||||
clients: Arc::new(ArcSwap::new(Arc::new(HashMap::new()))),
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_client(&self, op: Operation) -> Result<reqwest_dav::Client, Error> {
|
||||
// 先尝试从缓存获取
|
||||
{
|
||||
let clients = self.clients.lock();
|
||||
if let Some(client) = clients.get(&op) {
|
||||
let clients_map = self.clients.load();
|
||||
if let Some(client) = clients_map.get(&op) {
|
||||
return Ok(client.clone());
|
||||
}
|
||||
}
|
||||
@@ -81,10 +81,10 @@ impl WebDavClient {
|
||||
// 获取或创建配置
|
||||
let config = {
|
||||
// 首先检查是否已有配置
|
||||
let existing_config = self.config.lock().as_ref().cloned();
|
||||
let existing_config = self.config.load();
|
||||
|
||||
if let Some(cfg) = existing_config {
|
||||
cfg
|
||||
if let Some(cfg_arc) = existing_config.clone() {
|
||||
(*cfg_arc).clone()
|
||||
} else {
|
||||
// 释放锁后获取异步配置
|
||||
let verge = Config::verge().await.latest_ref().clone();
|
||||
@@ -106,8 +106,8 @@ impl WebDavClient {
|
||||
password: verge.webdav_password.unwrap_or_default(),
|
||||
};
|
||||
|
||||
// 重新获取锁并存储配置
|
||||
*self.config.lock() = Some(config.clone());
|
||||
// 存储配置到 ArcSwapOption
|
||||
self.config.store(Some(Arc::new(config.clone())));
|
||||
config
|
||||
}
|
||||
};
|
||||
@@ -161,18 +161,19 @@ impl WebDavClient {
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存客户端
|
||||
// 缓存客户端(替换 Arc<Mutex<HashMap<...>>> 的写法)
|
||||
{
|
||||
let mut clients = self.clients.lock();
|
||||
clients.insert(op, client.clone());
|
||||
let mut map = (**self.clients.load()).clone();
|
||||
map.insert(op, client.clone());
|
||||
self.clients.store(map.into());
|
||||
}
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
*self.config.lock() = None;
|
||||
self.clients.lock().clear();
|
||||
self.config.store(None);
|
||||
self.clients.store(Arc::new(HashMap::new()));
|
||||
}
|
||||
|
||||
pub async fn upload(&self, file_path: PathBuf, file_name: String) -> Result<(), Error> {
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
singleton_with_logging, utils::logging::Type,
|
||||
};
|
||||
use anyhow::{Result, bail};
|
||||
use parking_lot::Mutex;
|
||||
use arc_swap::ArcSwap;
|
||||
use smartstring::alias::String;
|
||||
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
|
||||
use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, ShortcutState};
|
||||
@@ -93,13 +93,13 @@ impl SystemHotkey {
|
||||
}
|
||||
|
||||
pub struct Hotkey {
|
||||
current: Arc<Mutex<Vec<String>>>,
|
||||
current: ArcSwap<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Hotkey {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
current: Arc::new(Mutex::new(Vec::new())),
|
||||
current: ArcSwap::new(Arc::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,9 +272,9 @@ impl Hotkey {
|
||||
singleton_with_logging!(Hotkey, INSTANCE, "Hotkey");
|
||||
|
||||
impl Hotkey {
|
||||
pub async fn init(&self) -> Result<()> {
|
||||
pub async fn init(&self, skip: bool) -> Result<()> {
|
||||
let verge = Config::verge().await;
|
||||
let enable_global_hotkey = verge.latest_ref().enable_global_hotkey.unwrap_or(true);
|
||||
let enable_global_hotkey = !skip && verge.latest_ref().enable_global_hotkey.unwrap_or(true);
|
||||
|
||||
logging!(
|
||||
debug,
|
||||
@@ -283,10 +283,6 @@ impl Hotkey {
|
||||
enable_global_hotkey
|
||||
);
|
||||
|
||||
if !enable_global_hotkey {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Extract hotkeys data before async operations
|
||||
let hotkeys = verge.latest_ref().hotkeys.as_ref().cloned();
|
||||
|
||||
@@ -344,7 +340,7 @@ impl Hotkey {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.current.lock().clone_from(&hotkeys);
|
||||
self.current.store(Arc::new(hotkeys));
|
||||
} else {
|
||||
logging!(debug, Type::Hotkey, "No hotkeys configured");
|
||||
}
|
||||
@@ -375,8 +371,8 @@ impl Hotkey {
|
||||
|
||||
pub async fn update(&self, new_hotkeys: Vec<String>) -> Result<()> {
|
||||
// Extract current hotkeys before async operations
|
||||
let current_hotkeys = self.current.lock().clone();
|
||||
let old_map = Self::get_map_from_vec(¤t_hotkeys);
|
||||
let current_hotkeys = &*self.current.load();
|
||||
let old_map = Self::get_map_from_vec(current_hotkeys);
|
||||
let new_map = Self::get_map_from_vec(&new_hotkeys);
|
||||
|
||||
let (del, add) = Self::get_diff(old_map, new_map);
|
||||
@@ -390,7 +386,7 @@ impl Hotkey {
|
||||
}
|
||||
|
||||
// Update the current hotkeys after all async operations
|
||||
*self.current.lock() = new_hotkeys;
|
||||
self.current.store(Arc::new(new_hotkeys));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -39,25 +39,20 @@ impl CoreManager {
|
||||
return Ok((true, String::new()));
|
||||
}
|
||||
|
||||
let _permit = self
|
||||
.update_semaphore
|
||||
.try_acquire()
|
||||
.map_err(|_| anyhow!("Config update already in progress"))?;
|
||||
|
||||
self.perform_config_update().await
|
||||
}
|
||||
|
||||
fn should_update_config(&self) -> Result<bool> {
|
||||
let now = Instant::now();
|
||||
let mut last = self.last_update.lock();
|
||||
let last = self.get_last_update();
|
||||
|
||||
if let Some(last_time) = *last
|
||||
&& now.duration_since(last_time) < timing::CONFIG_UPDATE_DEBOUNCE
|
||||
if let Some(last_time) = last
|
||||
&& now.duration_since(*last_time) < timing::CONFIG_UPDATE_DEBOUNCE
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
*last = Some(now);
|
||||
self.set_last_update(now);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@ mod lifecycle;
|
||||
mod state;
|
||||
|
||||
use anyhow::Result;
|
||||
use parking_lot::Mutex;
|
||||
use arc_swap::{ArcSwap, ArcSwapOption};
|
||||
use std::{fmt, sync::Arc, time::Instant};
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
use crate::process::CommandChildGuard;
|
||||
use crate::singleton_lazy;
|
||||
@@ -29,22 +28,21 @@ impl fmt::Display for RunningMode {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CoreManager {
|
||||
state: Arc<Mutex<State>>,
|
||||
update_semaphore: Arc<Semaphore>,
|
||||
last_update: Arc<Mutex<Option<Instant>>>,
|
||||
state: ArcSwap<State>,
|
||||
last_update: ArcSwapOption<Instant>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct State {
|
||||
running_mode: Arc<RunningMode>,
|
||||
child_sidecar: Option<CommandChildGuard>,
|
||||
running_mode: ArcSwap<RunningMode>,
|
||||
child_sidecar: ArcSwapOption<CommandChildGuard>,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
running_mode: Arc::new(RunningMode::NotRunning),
|
||||
child_sidecar: None,
|
||||
running_mode: ArcSwap::new(Arc::new(RunningMode::NotRunning)),
|
||||
child_sidecar: ArcSwapOption::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,24 +50,41 @@ impl Default for State {
|
||||
impl Default for CoreManager {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
state: Arc::new(Mutex::new(State::default())),
|
||||
update_semaphore: Arc::new(Semaphore::new(1)),
|
||||
last_update: Arc::new(Mutex::new(None)),
|
||||
state: ArcSwap::new(Arc::new(State::default())),
|
||||
last_update: ArcSwapOption::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CoreManager {
|
||||
pub fn get_running_mode(&self) -> Arc<RunningMode> {
|
||||
Arc::clone(&self.state.lock().running_mode)
|
||||
Arc::clone(&self.state.load().running_mode.load())
|
||||
}
|
||||
|
||||
pub fn take_child_sidecar(&self) -> Option<CommandChildGuard> {
|
||||
self.state
|
||||
.load()
|
||||
.child_sidecar
|
||||
.swap(None)
|
||||
.and_then(|arc| Arc::try_unwrap(arc).ok())
|
||||
}
|
||||
|
||||
pub fn get_last_update(&self) -> Option<Arc<Instant>> {
|
||||
self.last_update.load_full()
|
||||
}
|
||||
|
||||
pub fn set_running_mode(&self, mode: RunningMode) {
|
||||
self.state.lock().running_mode = Arc::new(mode);
|
||||
let state = self.state.load();
|
||||
state.running_mode.store(Arc::new(mode));
|
||||
}
|
||||
|
||||
pub fn set_running_child_sidecar(&self, child: CommandChildGuard) {
|
||||
self.state.lock().child_sidecar = Some(child);
|
||||
let state = self.state.load();
|
||||
state.child_sidecar.store(Some(Arc::new(child)));
|
||||
}
|
||||
|
||||
pub fn set_last_update(&self, time: Instant) {
|
||||
self.last_update.store(Some(Arc::new(time)));
|
||||
}
|
||||
|
||||
pub async fn init(&self) -> Result<()> {
|
||||
|
||||
@@ -93,8 +93,7 @@ impl CoreManager {
|
||||
defer! {
|
||||
self.set_running_mode(RunningMode::NotRunning);
|
||||
}
|
||||
let mut state = self.state.lock();
|
||||
if let Some(child) = state.child_sidecar.take() {
|
||||
if let Some(child) = self.take_child_sidecar() {
|
||||
let pid = child.pid();
|
||||
drop(child);
|
||||
logging!(trace, Type::Core, "Sidecar stopped (PID: {:?})", pid);
|
||||
|
||||
@@ -241,11 +241,15 @@ pub async fn restore_local_backup(filename: String) -> Result<()> {
|
||||
return Err(anyhow!("Backup file not found: {}", filename));
|
||||
}
|
||||
|
||||
let verge = Config::verge().await;
|
||||
let verge_data = verge.latest_ref().clone();
|
||||
let webdav_url = verge_data.webdav_url.clone();
|
||||
let webdav_username = verge_data.webdav_username.clone();
|
||||
let webdav_password = verge_data.webdav_password.clone();
|
||||
let (webdav_url, webdav_username, webdav_password) = {
|
||||
let verge = Config::verge().await;
|
||||
let verge = verge.latest_ref();
|
||||
(
|
||||
verge.webdav_url.clone(),
|
||||
verge.webdav_username.clone(),
|
||||
verge.webdav_password.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
let file = AsyncHandler::spawn_blocking(move || std::fs::File::open(&target_path)).await??;
|
||||
let mut zip = zip::ZipArchive::new(file)?;
|
||||
|
||||
@@ -334,10 +334,7 @@ pub fn run() {
|
||||
.register_system_hotkey(SystemHotkey::CmdW)
|
||||
.await;
|
||||
}
|
||||
|
||||
if !is_enable_global_hotkey {
|
||||
let _ = hotkey::Hotkey::global().init().await;
|
||||
}
|
||||
let _ = hotkey::Hotkey::global().init(true).await;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -358,8 +355,18 @@ pub fn run() {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use crate::core::hotkey::SystemHotkey;
|
||||
let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ);
|
||||
let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW);
|
||||
AsyncHandler::spawn(move || async move {
|
||||
let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ);
|
||||
let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW);
|
||||
let is_enable_global_hotkey = Config::verge()
|
||||
.await
|
||||
.latest_ref()
|
||||
.enable_global_hotkey
|
||||
.unwrap_or(true);
|
||||
if !is_enable_global_hotkey {
|
||||
let _ = hotkey::Hotkey::global().reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::{handle, timer::Timer},
|
||||
core::{handle, timer::Timer, tray::Tray},
|
||||
log_err, logging,
|
||||
process::AsyncHandler,
|
||||
utils::logging::Type,
|
||||
@@ -78,6 +78,12 @@ pub fn is_in_lightweight_mode() -> bool {
|
||||
get_state() == LightweightState::In
|
||||
}
|
||||
|
||||
async fn refresh_lightweight_tray_state() {
|
||||
if let Err(err) = Tray::global().update_tray_display().await {
|
||||
logging!(warn, Type::Lightweight, "更新托盘轻量模式状态失败: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn auto_lightweight_boot() -> Result<()> {
|
||||
let verge_config = Config::verge().await;
|
||||
let enable_auto = verge_config
|
||||
@@ -130,11 +136,13 @@ pub fn disable_auto_light_weight_mode() {
|
||||
pub async fn entry_lightweight_mode() -> bool {
|
||||
if !try_transition(LightweightState::Normal, LightweightState::In) {
|
||||
logging!(info, Type::Lightweight, "无需进入轻量模式,跳过调用");
|
||||
refresh_lightweight_tray_state().await;
|
||||
return false;
|
||||
}
|
||||
record_state_and_log(LightweightState::In);
|
||||
WindowManager::destroy_main_window();
|
||||
let _ = cancel_light_weight_timer();
|
||||
refresh_lightweight_tray_state().await;
|
||||
true
|
||||
}
|
||||
|
||||
@@ -145,12 +153,14 @@ pub async fn exit_lightweight_mode() -> bool {
|
||||
Type::Lightweight,
|
||||
"轻量模式不在退出条件(可能已退出或正在退出),跳过调用"
|
||||
);
|
||||
refresh_lightweight_tray_state().await;
|
||||
return false;
|
||||
}
|
||||
record_state_and_log(LightweightState::Exiting);
|
||||
WindowManager::show_main_window().await;
|
||||
let _ = cancel_light_weight_timer();
|
||||
record_state_and_log(LightweightState::Normal);
|
||||
refresh_lightweight_tray_state().await;
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ async fn initialize_config_files() -> Result<()> {
|
||||
if let Ok(path) = dirs::profiles_path()
|
||||
&& !path.exists()
|
||||
{
|
||||
let template = IProfiles::template();
|
||||
let template = IProfiles::default();
|
||||
help::save_yaml(&path, &template, Some("# Clash Verge"))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
|
||||
|
||||
@@ -120,7 +120,7 @@ pub(super) async fn init_timer() {
|
||||
}
|
||||
|
||||
pub(super) async fn init_hotkey() {
|
||||
logging_error!(Type::Setup, Hotkey::global().init().await);
|
||||
logging_error!(Type::Setup, Hotkey::global().init(false).await);
|
||||
}
|
||||
|
||||
pub(super) async fn init_auto_lightweight_boot() {
|
||||
|
||||
1
src/types/types.d.ts
vendored
1
src/types/types.d.ts
vendored
@@ -280,7 +280,6 @@ interface IProfileOption {
|
||||
|
||||
interface IProfilesConfig {
|
||||
current?: string;
|
||||
valid?: string[];
|
||||
items?: IProfileItem[];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user