Compare commits

..

4 Commits

10 changed files with 366 additions and 240 deletions

View File

@@ -1,4 +1,4 @@
## v2.2.1 ## v2.2.2
**发行代号:拓** **发行代号:拓**
@@ -6,8 +6,24 @@
代号释义: 本次发布在功能上的大幅扩展。新首页设计为用户带来全新交互体验DNS 覆写功能增强网络控制能力解锁测试页面助力内容访问自由度提升轻量模式提供灵活使用选择。此外macOS 应用菜单集成、sidecar 模式、诊断信息导出等新特性进一步丰富了软件的适用场景。这些新增功能显著拓宽了 Clash Verge 的功能边界,为用户提供了更强大的工具和可能性。 代号释义: 本次发布在功能上的大幅扩展。新首页设计为用户带来全新交互体验DNS 覆写功能增强网络控制能力解锁测试页面助力内容访问自由度提升轻量模式提供灵活使用选择。此外macOS 应用菜单集成、sidecar 模式、诊断信息导出等新特性进一步丰富了软件的适用场景。这些新增功能显著拓宽了 Clash Verge 的功能边界,为用户提供了更强大的工具和可能性。
2.2.1 相对于 2.2.0(已下架不在提供) #### 已知问题
修复了: - 仅在Ubuntu 22.04/24.04Fedora 41 **Gnome桌面环境** 做过简单测试不保证其他其他Linux发行版可用将在未来做进一步适配和调优
### 2.2.2 相对于 2.2.1(已下架不在提供)
#### 修复了:
- 弹黑框的问题(原因是服务崩溃触发重装机制)
- MacOS进入轻量模式以后影藏Dock图标
- 增加轻量模式缺失的tray翻译
- Linux下的窗口边框被削掉的问题
#### 新增了:
- 加强服务检测和重装逻辑
- 增强内核与服务保活机制
- 增加服务模式下的僵尸进程清理机制
- 新增当服务模式多次尝试失败后自动回退至用户空间模式
### 2.2.1 相对于 2.2.0(已下架不在提供)
#### 修复了:
1. **首页** 1. **首页**
- 修复 Direct 模式首页无法渲染 - 修复 Direct 模式首页无法渲染
- 修复 首页启用轻量模式导致 ClashVergeRev 从托盘退出 - 修复 首页启用轻量模式导致 ClashVergeRev 从托盘退出
@@ -23,7 +39,7 @@
4. **轻量模式** 4. **轻量模式**
- 修复 MacOS 轻量模式下 Dock 栏图标无法隐藏。 - 修复 MacOS 轻量模式下 Dock 栏图标无法隐藏。
新增了: #### 新增了:
1. **首页** 1. **首页**
- 首页文本过长自动截断 - 首页文本过长自动截断
2. **轻量模式** 2. **轻量模式**
@@ -37,7 +53,7 @@
--- ---
## v2.2.0(已下架不在提供) ## 2.2.0(已下架不在提供)
#### 新增功能 #### 新增功能
1. **首页** 1. **首页**
@@ -78,6 +94,7 @@
- 修复 macOS tray图标错位到左上角的问题。 - 修复 macOS tray图标错位到左上角的问题。
- 修复 Windows/Linux 运行时崩溃。 - 修复 Windows/Linux 运行时崩溃。
- 修复 Win10 阴影和边框问题。 - 修复 Win10 阴影和边框问题。
- 修复 升级或重装后开机自启状态检测和同步问题。
2. **构建** 2. **构建**
- 修复构建失败问题。 - 修复构建失败问题。

View File

@@ -1,6 +1,6 @@
{ {
"name": "clash-verge", "name": "clash-verge",
"version": "2.2.1", "version": "2.2.2",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"scripts": { "scripts": {
"dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev -- --profile fast-dev", "dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev -- --profile fast-dev",

View File

@@ -8,8 +8,8 @@ const UPDATE_JSON_FILE = "update.json";
const UPDATE_JSON_PROXY = "update-proxy.json"; const UPDATE_JSON_PROXY = "update-proxy.json";
// Add alpha update JSON filenames // Add alpha update JSON filenames
const ALPHA_TAG_NAME = "updater-alpha"; const ALPHA_TAG_NAME = "updater-alpha";
const ALPHA_UPDATE_JSON_FILE = "update-alpha.json"; const ALPHA_UPDATE_JSON_FILE = "update.json";
const ALPHA_UPDATE_JSON_PROXY = "update-alpha-proxy.json"; const ALPHA_UPDATE_JSON_PROXY = "update-proxy.json";
/// generate update.json /// generate update.json
/// upload to update tag's release asset /// upload to update tag's release asset
@@ -78,224 +78,235 @@ async function resolveUpdater() {
async function processRelease(github, options, tag, isAlpha) { async function processRelease(github, options, tag, isAlpha) {
if (!tag) return; if (!tag) return;
const { data: release } = await github.rest.repos.getReleaseByTag({
...options,
tag: tag.name,
});
const updateData = {
name: tag.name,
notes: await resolveUpdateLog(tag.name).catch(() =>
resolveUpdateLogDefault().catch(() => "No changelog available"),
),
pub_date: new Date().toISOString(),
platforms: {
win64: { signature: "", url: "" }, // compatible with older formats
linux: { signature: "", url: "" }, // compatible with older formats
darwin: { signature: "", url: "" }, // compatible with older formats
"darwin-aarch64": { signature: "", url: "" },
"darwin-intel": { signature: "", url: "" },
"darwin-x86_64": { signature: "", url: "" },
"linux-x86_64": { signature: "", url: "" },
"linux-x86": { signature: "", url: "" },
"linux-i686": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"linux-armv7": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
const promises = release.assets.map(async (asset) => {
const { name, browser_download_url } = asset;
// Process all the platform URL and signature data
// win64 url
if (name.endsWith("x64-setup.exe")) {
updateData.platforms.win64.url = browser_download_url;
updateData.platforms["windows-x86_64"].url = browser_download_url;
}
// win64 signature
if (name.endsWith("x64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.win64.signature = sig;
updateData.platforms["windows-x86_64"].signature = sig;
}
// win32 url
if (name.endsWith("x86-setup.exe")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x86-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
if (name.endsWith("arm64-setup.exe")) {
updateData.platforms["windows-aarch64"].url = browser_download_url;
}
// win arm signature
if (name.endsWith("arm64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-aarch64"].signature = sig;
}
// darwin url (intel)
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
updateData.platforms.darwin.url = browser_download_url;
updateData.platforms["darwin-intel"].url = browser_download_url;
updateData.platforms["darwin-x86_64"].url = browser_download_url;
}
// darwin signature (intel)
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.darwin.signature = sig;
updateData.platforms["darwin-intel"].signature = sig;
updateData.platforms["darwin-x86_64"].signature = sig;
}
// darwin url (aarch)
if (name.endsWith("aarch64.app.tar.gz")) {
updateData.platforms["darwin-aarch64"].url = browser_download_url;
// 使linux可以检查更新
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// darwin signature (aarch)
if (name.endsWith("aarch64.app.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["darwin-aarch64"].signature = sig;
updateData.platforms.linux.signature = sig;
updateData.platforms["linux-x86_64"].signature = sig;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].signature = sig;
updateData.platforms["linux-armv7"].signature = sig;
}
});
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
// delete the null field
Object.entries(updateData.platforms).forEach(([key, value]) => {
if (!value.url) {
console.log(`[Error]: failed to parse release for "${key}"`);
delete updateData.platforms[key];
}
});
// Generate a proxy update file for accelerated GitHub resources
const updateDataNew = JSON.parse(JSON.stringify(updateData));
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
"https://download.clashverge.dev/" + value.url;
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
}
});
// Get the appropriate updater release based on isAlpha flag
const releaseTag = isAlpha ? ALPHA_TAG_NAME : UPDATE_TAG_NAME;
console.log(
`Processing ${isAlpha ? "alpha" : "stable"} release:`,
releaseTag,
);
try { try {
let updateRelease; const { data: release } = await github.rest.repos.getReleaseByTag({
...options,
tag: tag.name,
});
const updateData = {
name: tag.name,
notes: await resolveUpdateLog(tag.name).catch(() =>
resolveUpdateLogDefault().catch(() => "No changelog available"),
),
pub_date: new Date().toISOString(),
platforms: {
win64: { signature: "", url: "" }, // compatible with older formats
linux: { signature: "", url: "" }, // compatible with older formats
darwin: { signature: "", url: "" }, // compatible with older formats
"darwin-aarch64": { signature: "", url: "" },
"darwin-intel": { signature: "", url: "" },
"darwin-x86_64": { signature: "", url: "" },
"linux-x86_64": { signature: "", url: "" },
"linux-x86": { signature: "", url: "" },
"linux-i686": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"linux-armv7": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-aarch64": { signature: "", url: "" },
"windows-x86": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
const promises = release.assets.map(async (asset) => {
const { name, browser_download_url } = asset;
// Process all the platform URL and signature data
// win64 url
if (name.endsWith("x64-setup.exe")) {
updateData.platforms.win64.url = browser_download_url;
updateData.platforms["windows-x86_64"].url = browser_download_url;
}
// win64 signature
if (name.endsWith("x64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.win64.signature = sig;
updateData.platforms["windows-x86_64"].signature = sig;
}
// win32 url
if (name.endsWith("x86-setup.exe")) {
updateData.platforms["windows-x86"].url = browser_download_url;
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (name.endsWith("x86-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-x86"].signature = sig;
updateData.platforms["windows-i686"].signature = sig;
}
// win arm url
if (name.endsWith("arm64-setup.exe")) {
updateData.platforms["windows-aarch64"].url = browser_download_url;
}
// win arm signature
if (name.endsWith("arm64-setup.exe.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-aarch64"].signature = sig;
}
// darwin url (intel)
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
updateData.platforms.darwin.url = browser_download_url;
updateData.platforms["darwin-intel"].url = browser_download_url;
updateData.platforms["darwin-x86_64"].url = browser_download_url;
}
// darwin signature (intel)
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.darwin.signature = sig;
updateData.platforms["darwin-intel"].signature = sig;
updateData.platforms["darwin-x86_64"].signature = sig;
}
// darwin url (aarch)
if (name.endsWith("aarch64.app.tar.gz")) {
updateData.platforms["darwin-aarch64"].url = browser_download_url;
// 使linux可以检查更新
updateData.platforms.linux.url = browser_download_url;
updateData.platforms["linux-x86_64"].url = browser_download_url;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].url = browser_download_url;
updateData.platforms["linux-armv7"].url = browser_download_url;
}
// darwin signature (aarch)
if (name.endsWith("aarch64.app.tar.gz.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["darwin-aarch64"].signature = sig;
updateData.platforms.linux.signature = sig;
updateData.platforms["linux-x86_64"].signature = sig;
updateData.platforms["linux-x86"].url = browser_download_url;
updateData.platforms["linux-i686"].url = browser_download_url;
updateData.platforms["linux-aarch64"].signature = sig;
updateData.platforms["linux-armv7"].signature = sig;
}
});
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
// delete the null field
Object.entries(updateData.platforms).forEach(([key, value]) => {
if (!value.url) {
console.log(`[Error]: failed to parse release for "${key}"`);
delete updateData.platforms[key];
}
});
// Generate a proxy update file for accelerated GitHub resources
const updateDataNew = JSON.parse(JSON.stringify(updateData));
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
if (value.url) {
updateDataNew.platforms[key].url =
"https://download.clashverge.dev/" + value.url;
} else {
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
}
});
// Get the appropriate updater release based on isAlpha flag
const releaseTag = isAlpha ? ALPHA_TAG_NAME : UPDATE_TAG_NAME;
console.log(
`Processing ${isAlpha ? "alpha" : "stable"} release:`,
releaseTag,
);
try { try {
// Try to get the existing release let updateRelease;
const response = await github.rest.repos.getReleaseByTag({
try {
// Try to get the existing release
const response = await github.rest.repos.getReleaseByTag({
...options,
tag: releaseTag,
});
updateRelease = response.data;
console.log(
`Found existing ${releaseTag} release with ID: ${updateRelease.id}`,
);
} catch (error) {
// If release doesn't exist, create it
if (error.status === 404) {
console.log(
`Release with tag ${releaseTag} not found, creating new release...`,
);
const createResponse = await github.rest.repos.createRelease({
...options,
tag_name: releaseTag,
name: isAlpha
? "Auto-update Alpha Channel"
: "Auto-update Stable Channel",
body: `This release contains the update information for ${isAlpha ? "alpha" : "stable"} channel.`,
prerelease: isAlpha,
});
updateRelease = createResponse.data;
console.log(
`Created new ${releaseTag} release with ID: ${updateRelease.id}`,
);
} else {
// If it's another error, throw it
throw error;
}
}
// File names based on release type
const jsonFile = isAlpha ? ALPHA_UPDATE_JSON_FILE : UPDATE_JSON_FILE;
const proxyFile = isAlpha ? ALPHA_UPDATE_JSON_PROXY : UPDATE_JSON_PROXY;
// Delete existing assets with these names
for (let asset of updateRelease.assets) {
if (asset.name === jsonFile) {
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: asset.id,
});
}
if (asset.name === proxyFile) {
await github.rest.repos
.deleteReleaseAsset({ ...options, asset_id: asset.id })
.catch(console.error); // do not break the pipeline
}
}
// Upload new assets
await github.rest.repos.uploadReleaseAsset({
...options, ...options,
tag: releaseTag, release_id: updateRelease.id,
name: jsonFile,
data: JSON.stringify(updateData, null, 2),
}); });
updateRelease = response.data;
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: proxyFile,
data: JSON.stringify(updateDataNew, null, 2),
});
console.log( console.log(
`Found existing ${releaseTag} release with ID: ${updateRelease.id}`, `Successfully uploaded ${isAlpha ? "alpha" : "stable"} update files to ${releaseTag}`,
); );
} catch (error) { } catch (error) {
// If release doesn't exist, create it console.error(
if (error.status === 404) { `Failed to process ${isAlpha ? "alpha" : "stable"} release:`,
console.log( error.message,
`Release with tag ${releaseTag} not found, creating new release...`, );
);
const createResponse = await github.rest.repos.createRelease({
...options,
tag_name: releaseTag,
name: isAlpha
? "Auto-update Alpha Channel"
: "Auto-update Stable Channel",
body: `This release contains the update information for ${isAlpha ? "alpha" : "stable"} channel.`,
prerelease: isAlpha,
});
updateRelease = createResponse.data;
console.log(
`Created new ${releaseTag} release with ID: ${updateRelease.id}`,
);
} else {
// If it's another error, throw it
throw error;
}
} }
// File names based on release type
const jsonFile = isAlpha ? ALPHA_UPDATE_JSON_FILE : UPDATE_JSON_FILE;
const proxyFile = isAlpha ? ALPHA_UPDATE_JSON_PROXY : UPDATE_JSON_PROXY;
// Delete existing assets with these names
for (let asset of updateRelease.assets) {
if (asset.name === jsonFile) {
await github.rest.repos.deleteReleaseAsset({
...options,
asset_id: asset.id,
});
}
if (asset.name === proxyFile) {
await github.rest.repos
.deleteReleaseAsset({ ...options, asset_id: asset.id })
.catch(console.error); // do not break the pipeline
}
}
// Upload new assets
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: jsonFile,
data: JSON.stringify(updateData, null, 2),
});
await github.rest.repos.uploadReleaseAsset({
...options,
release_id: updateRelease.id,
name: proxyFile,
data: JSON.stringify(updateDataNew, null, 2),
});
console.log(
`Successfully uploaded ${isAlpha ? "alpha" : "stable"} update files to ${releaseTag}`,
);
} catch (error) { } catch (error) {
console.error( if (error.status === 404) {
`Failed to process ${isAlpha ? "alpha" : "stable"} release:`, console.log(`Release not found for tag: ${tag.name}, skipping...`);
error.message, } else {
); console.error(
`Failed to get release for tag: ${tag.name}`,
error.message,
);
}
} }
} }

2
src-tauri/Cargo.lock generated
View File

@@ -1132,7 +1132,7 @@ dependencies = [
[[package]] [[package]]
name = "clash-verge" name = "clash-verge"
version = "2.2.1" version = "2.2.2"
dependencies = [ dependencies = [
"ab_glyph", "ab_glyph",
"aes-gcm", "aes-gcm",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "clash-verge" name = "clash-verge"
version = "2.2.1" version = "2.2.2"
description = "clash verge" description = "clash verge"
authors = ["zzzgydi", "wonfen", "MystiPanda"] authors = ["zzzgydi", "wonfen", "MystiPanda"]
license = "GPL-3.0-only" license = "GPL-3.0-only"

View File

@@ -19,6 +19,7 @@ use super::service::is_service_running;
#[derive(Debug)] #[derive(Debug)]
pub struct CoreManager { pub struct CoreManager {
running: Arc<Mutex<bool>>, running: Arc<Mutex<bool>>,
last_check_time: Arc<Mutex<Option<std::time::Instant>>>,
} }
/// 内核运行模式 /// 内核运行模式
@@ -37,6 +38,7 @@ impl CoreManager {
static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new(); static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new();
CORE_MANAGER.get_or_init(|| CoreManager { CORE_MANAGER.get_or_init(|| CoreManager {
running: Arc::new(Mutex::new(false)), running: Arc::new(Mutex::new(false)),
last_check_time: Arc::new(Mutex::new(None)),
}) })
} }
@@ -681,8 +683,25 @@ impl CoreManager {
// 5. 应用新配置 // 5. 应用新配置
println!("[core配置更新] 应用新配置"); println!("[core配置更新] 应用新配置");
for i in 0..3 {
CoreManager::global().ensure_running_core().await; // 检查当前运行模式
let running_mode = self.get_running_mode().await;
// 使用指数退避策略进行重试
let mut retry_count = 0;
let max_retries = 3;
loop {
// 仅在服务模式下确保服务在运行
match running_mode {
RunningMode::Service => {
println!("[core配置更新] 服务模式下检查服务状态");
self.ensure_running_core().await;
},
_ => {
println!("[core配置更新] 非服务模式,跳过服务状态检查");
}
}
match MihomoManager::global().put_configs_force(run_path).await { match MihomoManager::global().put_configs_force(run_path).await {
Ok(_) => { Ok(_) => {
@@ -691,19 +710,21 @@ impl CoreManager {
return Ok((true, String::new())); return Ok((true, String::new()));
} }
Err(err) => { Err(err) => {
if i < 2 { retry_count += 1;
println!("[core配置更新] 第{}次重试应用配置", i + 1); if retry_count < max_retries {
log::info!(target: "app", "{err}"); // 使用指数退避策略计算下一次重试间隔
sleep(Duration::from_millis(100)).await; let wait_time = 200 * (2_u64.pow(retry_count as u32 - 1));
println!("[core配置更新] 第{}次重试应用配置,等待{}ms", retry_count, wait_time);
log::info!(target: "app", "配置应用失败: {},将在{}ms后重试", err, wait_time);
sleep(Duration::from_millis(wait_time)).await;
} else { } else {
println!("[core配置更新] 配置应用失败: {}", err); println!("[core配置更新] 已重试{}次,配置应用失败: {}", max_retries, err);
Config::runtime().discard(); Config::runtime().discard();
return Ok((false, err.to_string())); return Ok((false, err.to_string()));
} }
} }
} }
} }
Ok((true, String::new()))
} }
Ok((false, error_msg)) => { Ok((false, error_msg)) => {
println!("[core配置更新] 配置验证失败: {}", error_msg); println!("[core配置更新] 配置验证失败: {}", error_msg);
@@ -896,7 +917,7 @@ impl CoreManager {
async fn is_port_in_use(&self, port: u16) -> bool { async fn is_port_in_use(&self, port: u16) -> bool {
println!("[端口检查] 检查端口 {} 是否被占用", port); println!("[端口检查] 检查端口 {} 是否被占用", port);
use tokio::net::TcpSocket; use tokio::net::TcpSocket;
match TcpSocket::new_v4() { match TcpSocket::new_v4() {
Ok(socket) => { Ok(socket) => {
@@ -990,17 +1011,74 @@ impl CoreManager {
} }
/// 确保 Mihomo 和 Verge service 都在运行 /// 确保 Mihomo 和 Verge service 都在运行
pub async fn ensure_running_core(&self) { pub async fn ensure_running_core(&self) {
if MihomoManager::global().is_mihomo_running().await.is_err() { // 添加时间间隔检查,避免频繁执行
log_err!(self.restart_core().await); let min_check_interval = Duration::from_secs(20); // 最小检查间隔为20秒
}
match is_service_running().await { let should_check = {
Ok(false) => log_err!(self.restart_core().await), let mut last_check = self.last_check_time.lock().await;
Ok(true) => { let now = std::time::Instant::now();
if MihomoManager::global().is_mihomo_running().await.is_err() {
log_err!(self.restart_core().await); match *last_check {
Some(time) if now.duration_since(time) < min_check_interval => {
// 如果距离上次检查时间不足30秒跳过本次检查
false
},
_ => {
// 更新最后检查时间
*last_check = Some(now);
true
} }
} }
_ => {} };
if !should_check {
return;
}
// 检查当前运行模式,只在服务模式下执行完整的检查
match self.get_running_mode().await {
RunningMode::Service => {
println!("[确保核心运行] 服务模式下检查核心状态");
// 检查Mihomo是否运行
if MihomoManager::global().is_mihomo_running().await.is_err() {
println!("[确保核心运行] Mihomo未运行尝试重启");
log_err!(self.restart_core().await);
return; // 已重启,无需继续检查
}
// 检查服务是否运行
match is_service_running().await {
Ok(false) => {
println!("[确保核心运行] 服务未运行,尝试重启");
log_err!(self.restart_core().await);
},
Ok(true) => {
// 服务运行中再次确认Mihomo状态
if MihomoManager::global().is_mihomo_running().await.is_err() {
println!("[确保核心运行] 服务运行但Mihomo未响应尝试重启");
log_err!(self.restart_core().await);
} else {
println!("[确保核心运行] 服务和Mihomo都正常运行");
}
},
Err(err) => {
println!("[确保核心运行] 检查服务状态失败: {:?}", err);
}
}
},
RunningMode::Sidecar => {
println!("[确保核心运行] Sidecar模式下仅检查Mihomo状态");
// 在Sidecar模式下只检查Mihomo是否运行
if MihomoManager::global().is_mihomo_running().await.is_err() {
println!("[确保核心运行] Mihomo未运行尝试重启");
log_err!(self.restart_core().await);
}
},
RunningMode::NotRunning => {
println!("[确保核心运行] 核心未运行,尝试启动");
log_err!(self.start_core().await);
}
} }
} }
} }

View File

@@ -216,6 +216,12 @@ pub async fn reinstall_service() -> Result<()> {
); );
} }
// 记录安装信息并保存
let mut service_state = ServiceState::get();
service_state.record_install();
service_state.last_error = None;
service_state.save()?;
Ok(()) Ok(())
} }
@@ -268,6 +274,13 @@ pub async fn reinstall_service() -> Result<()> {
status.code().unwrap() status.code().unwrap()
); );
} }
// 记录安装信息并保存
let mut service_state = ServiceState::get();
service_state.record_install();
service_state.last_error = None;
service_state.save()?;
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,5 @@
{ {
"version": "2.2.1", "version": "2.2.2",
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"bundle": { "bundle": {
"active": true, "active": true,
@@ -30,6 +30,14 @@
"plugins": { "plugins": {
"updater": { "updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK", "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK",
"endpoints": [
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://gh-proxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update.json",
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater-alpha/update-alpha-proxy.json",
"https://gh-proxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater-alpha/update-alpha-proxy.json",
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater-alpha/update-alpha.json"
],
"windows": { "windows": {
"installMode": "basicUi" "installMode": "basicUi"
} }

View File

@@ -353,7 +353,6 @@
"clash_mode_direct": "直连模式", "clash_mode_direct": "直连模式",
"toggle_system_proxy": "打开/关闭系统代理", "toggle_system_proxy": "打开/关闭系统代理",
"toggle_tun_mode": "打开/关闭 TUN 模式", "toggle_tun_mode": "打开/关闭 TUN 模式",
"toggle_lightweight_mode": "进入轻量模式",
"entry_lightweight_mode": "进入轻量模式", "entry_lightweight_mode": "进入轻量模式",
"Backup Setting": "备份设置", "Backup Setting": "备份设置",
"Backup Setting Info": "支持 WebDAV 备份配置文件", "Backup Setting Info": "支持 WebDAV 备份配置文件",

View File

@@ -249,8 +249,8 @@ const Layout = () => {
? { ? {
borderRadius: "8px", borderRadius: "8px",
border: "1px solid var(--divider-color)", border: "1px solid var(--divider-color)",
width: "calc(100vw - 0px)", width: "calc(100vw - 4px)",
height: "calc(100vh - 0px)", height: "calc(100vh - 4px)",
} }
: {}, : {},
]} ]}