From 0b67405bada028706b0d4d50aeec784100250108 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Mon, 9 Nov 2026 20:45:38 +0800 Subject: [PATCH] fix(linux): report an unrestored Service state regardless of readiness Refs #8515 --- src-tauri/src/core/service.rs | 60 ++++++++++++++++------------------ src/locales/ar/settings.json | 2 +- src/locales/de/settings.json | 2 +- src/locales/en/settings.json | 2 +- src/locales/es/settings.json | 2 +- src/locales/fa/settings.json | 2 +- src/locales/id/settings.json | 2 +- src/locales/jp/settings.json | 2 +- src/locales/ko/settings.json | 2 +- src/locales/pt/settings.json | 2 +- src/locales/ru/settings.json | 2 +- src/locales/tr/settings.json | 2 +- src/locales/tt/settings.json | 2 +- src/locales/zh/settings.json | 2 +- src/locales/zhtw/settings.json | 2 +- 15 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src-tauri/src/core/service.rs b/src-tauri/src/core/service.rs index c8ed359e9..c1bc9bab4 100644 --- a/src-tauri/src/core/service.rs +++ b/src-tauri/src/core/service.rs @@ -92,17 +92,15 @@ pub(crate) async fn notify_incomplete_service_upgrade() { return; } let status = SERVICE_MANAGER.current().await; - match service_upgrade_notice(&marker, matches!(status, ServiceStatus::Ready)) { - Some(ServiceUpgradeNotice::Reinstall) => { - logging!(warn, Type::Service, "安装包升级后服务未就绪: {status:?}"); - *PENDING_SERVICE_FALLBACK_NOTICE.lock() = Some(SERVICE_UPGRADE_INCOMPLETE.to_owned()); - Handle::notice(NoticeStatus::ServiceCoreSidecarFallback, ""); - } - Some(ServiceUpgradeNotice::StateNotRestored(state)) => { - logging!(warn, Type::Service, "安装包升级后未能恢复服务原状态: {state}"); - Handle::notice(NoticeStatus::ServiceCoreUpgradeStateNotRestored, state); - } - None => {} + let notice = service_upgrade_notice(&marker, matches!(status, ServiceStatus::Ready)); + if notice.reinstall { + logging!(warn, Type::Service, "安装包升级后服务未就绪: {status:?}"); + *PENDING_SERVICE_FALLBACK_NOTICE.lock() = Some(SERVICE_UPGRADE_INCOMPLETE.to_owned()); + Handle::notice(NoticeStatus::ServiceCoreSidecarFallback, ""); + } + if let Some(state) = notice.unrestored_state { + logging!(warn, Type::Service, "安装包升级后未能恢复服务原状态: {state}"); + Handle::notice(NoticeStatus::ServiceCoreUpgradeStateNotRestored, state); } if let Err(error) = std::fs::write(&ack, id) { logging!(warn, Type::Service, "无法记录服务升级确认: {error}"); @@ -111,21 +109,18 @@ pub(crate) async fn notify_incomplete_service_upgrade() { #[cfg(target_os = "linux")] #[derive(Debug, PartialEq, Eq)] -enum ServiceUpgradeNotice<'a> { - Reinstall, - /// A reinstall would enable and start the Service again, so it cannot restore this state. - StateNotRestored(&'a str), +struct ServiceUpgradeNotice<'a> { + reinstall: bool, + /// Reported regardless of readiness: a reinstall enables and starts the Service, so it cannot restore this state. + unrestored_state: Option<&'a str>, } #[cfg(target_os = "linux")] -fn service_upgrade_notice(marker: &str, ready: bool) -> Option> { - if !ready { - return Some(ServiceUpgradeNotice::Reinstall); +fn service_upgrade_notice(marker: &str, ready: bool) -> ServiceUpgradeNotice<'_> { + ServiceUpgradeNotice { + reinstall: !ready, + unrestored_state: marker.lines().find_map(|line| line.strip_prefix("restore=")), } - marker - .lines() - .find_map(|line| line.strip_prefix("restore=")) - .map(ServiceUpgradeNotice::StateNotRestored) } pub(crate) fn take_service_fallback_notice() -> Option { @@ -2855,21 +2850,22 @@ mod tests { #[cfg(target_os = "linux")] #[test] - fn upgrade_marker_reports_unrestored_state_only_for_a_ready_service() { + fn upgrade_marker_reports_unrestored_state_regardless_of_readiness() { let restored = "gid=995\nid=1\n"; - let unrestored = "gid=995\nid=1\nrestore=disabled,inactive\n"; + let unrestored = "gid=995\nid=1\nrestore=disabled,active\n"; + let notice = |reinstall, unrestored_state| ServiceUpgradeNotice { + reinstall, + unrestored_state, + }; + assert_eq!(service_upgrade_notice(restored, true), notice(false, None)); + assert_eq!(service_upgrade_notice(restored, false), notice(true, None)); assert_eq!( - service_upgrade_notice(restored, false), - Some(ServiceUpgradeNotice::Reinstall) + service_upgrade_notice(unrestored, true), + notice(false, Some("disabled,active")) ); assert_eq!( service_upgrade_notice(unrestored, false), - Some(ServiceUpgradeNotice::Reinstall) - ); - assert_eq!(service_upgrade_notice(restored, true), None); - assert_eq!( - service_upgrade_notice(unrestored, true), - Some(ServiceUpgradeNotice::StateNotRestored("disabled,inactive")) + notice(true, Some("disabled,active")) ); } } diff --git a/src/locales/ar/settings.json b/src/locales/ar/settings.json index 086378e52..9ba341749 100644 --- a/src/locales/ar/settings.json +++ b/src/locales/ar/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "تعذّر على الخدمة التأكد من أن ملفات النواة ومجلداتها آمنة للتشغيل بصلاحيات مرتفعة.", "permissionRepairGuide": "عرض خطوات الإصلاح", "sidecarFallback": "تعذّر على الخدمة تشغيل النواة. تم التبديل إلى وضع Sidecar؛ ولا تزال الخدمة غير متاحة.", - "upgradeStateNotRestored": "أعادت الترقية تثبيت خدمة Clash Verge لكنها لم تتمكن من استعادة حالة بدء التشغيل والتشغيل السابقة ({{state}}). لن تؤدي إعادة تثبيت الخدمة إلى استعادتها؛ تحقق منها باستخدام systemctl status clash-verge-service واضبطها باستخدام systemctl.", + "upgradeStateNotRestored": "بعد الترقية تعذّرت استعادة حالة بدء التشغيل والتشغيل السابقة لخدمة Clash Verge ({{state}}). لن تؤدي إعادة تثبيت الخدمة إلى استعادتها؛ تحقق منها باستخدام systemctl status clash-verge-service واضبطها باستخدام systemctl.", "uninstallSuccess": "تم إلغاء تثبيت الخدمة بنجاح" }, "updater": { diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json index 3812c34ac..dfe7a5d74 100644 --- a/src/locales/de/settings.json +++ b/src/locales/de/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "Der Dienst konnte nicht bestätigen, dass die Kerndateien und Ordner für die Ausführung mit erhöhten Rechten sicher sind.", "permissionRepairGuide": "Reparaturanleitung öffnen", "sidecarFallback": "Der Dienst konnte den Kern nicht starten. Die Anwendung läuft im Sidecar-Modus weiter; der Dienst bleibt nicht verfügbar.", - "upgradeStateNotRestored": "Das Upgrade hat den Clash Verge-Dienst neu installiert, konnte aber seinen vorherigen Autostart- und Laufzustand ({{state}}) nicht wiederherstellen. Eine Neuinstallation des Dienstes stellt ihn nicht wieder her; prüfen Sie ihn mit systemctl status clash-verge-service und passen Sie ihn mit systemctl an.", + "upgradeStateNotRestored": "Nach dem Upgrade konnte der vorherige Autostart- und Laufzustand des Clash Verge-Dienstes ({{state}}) nicht wiederhergestellt werden. Eine Neuinstallation des Dienstes stellt ihn nicht wieder her; prüfen Sie ihn mit systemctl status clash-verge-service und passen Sie ihn mit systemctl an.", "uninstallSuccess": "Service erfolgreich deinstalliert" }, "updater": { diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 96fef1c27..b81b41ad6 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "The service could not confirm that the core files and folders are safe to run with elevated privileges.", "permissionRepairGuide": "View repair instructions", "sidecarFallback": "The service could not start the core. Switched to Sidecar mode; the service remains unavailable.", - "upgradeStateNotRestored": "The upgrade reinstalled the Clash Verge service but could not restore its previous startup and running state ({{state}}). Reinstalling the service will not restore it; check it with systemctl status clash-verge-service and adjust it with systemctl.", + "upgradeStateNotRestored": "After the upgrade, Clash Verge could not restore the service's previous startup and running state ({{state}}). Reinstalling the service will not restore it; check it with systemctl status clash-verge-service and adjust it with systemctl.", "uninstallSuccess": "Service Uninstalled Successfully" }, "updater": { diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index 3c2e5dc51..19e28f8e6 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "El servicio no pudo confirmar que los archivos y carpetas del núcleo sean seguros para ejecutarlos con privilegios elevados.", "permissionRepairGuide": "Ver instrucciones de reparación", "sidecarFallback": "El servicio no pudo iniciar el núcleo. Se ha cambiado al modo Sidecar; el servicio sigue sin estar disponible.", - "upgradeStateNotRestored": "La actualización reinstaló el servicio de Clash Verge, pero no pudo restaurar su estado anterior de inicio y ejecución ({{state}}). Reinstalar el servicio no lo restaurará; compruébelo con systemctl status clash-verge-service y ajústelo con systemctl.", + "upgradeStateNotRestored": "Tras la actualización no se pudo restaurar el estado anterior de inicio y ejecución del servicio de Clash Verge ({{state}}). Reinstalar el servicio no lo restaurará; compruébelo con systemctl status clash-verge-service y ajústelo con systemctl.", "uninstallSuccess": "Servicio desinstalado con éxito" }, "updater": { diff --git a/src/locales/fa/settings.json b/src/locales/fa/settings.json index c17a995ff..81dbc5f81 100644 --- a/src/locales/fa/settings.json +++ b/src/locales/fa/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "سرویس نتوانست ایمن بودن فایل‌ها و پوشه‌های هسته را برای اجرا با دسترسی بالا تأیید کند.", "permissionRepairGuide": "مشاهدهٔ راهنمای رفع مشکل", "sidecarFallback": "سرویس نتوانست هسته را اجرا کند. اجرا در حالت Sidecar ادامه می‌یابد؛ سرویس همچنان در دسترس نیست.", - "upgradeStateNotRestored": "ارتقا سرویس Clash Verge را دوباره نصب کرد اما نتوانست وضعیت قبلی راه‌اندازی خودکار و اجرای آن ({{state}}) را بازگرداند. نصب دوباره سرویس آن را بازنمی‌گرداند؛ با systemctl status clash-verge-service آن را بررسی و با systemctl تنظیم کنید.", + "upgradeStateNotRestored": "پس از ارتقا، وضعیت قبلی راه‌اندازی خودکار و اجرای سرویس Clash Verge ({{state}}) بازگردانده نشد. نصب دوباره سرویس آن را بازنمی‌گرداند؛ با systemctl status clash-verge-service آن را بررسی و با systemctl تنظیم کنید.", "uninstallSuccess": "سرویس با موفقیت حذف نصب شد" }, "updater": { diff --git a/src/locales/id/settings.json b/src/locales/id/settings.json index 400d8aedf..070839e27 100644 --- a/src/locales/id/settings.json +++ b/src/locales/id/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "Layanan tidak dapat memastikan bahwa berkas dan folder inti aman dijalankan dengan hak istimewa.", "permissionRepairGuide": "Lihat panduan perbaikan", "sidecarFallback": "Layanan tidak dapat memulai inti. Beralih ke mode Sidecar; layanan masih tidak tersedia.", - "upgradeStateNotRestored": "Pembaruan telah memasang ulang layanan Clash Verge tetapi tidak dapat memulihkan status mulai otomatis dan berjalan sebelumnya ({{state}}). Memasang ulang layanan tidak akan memulihkannya; periksa dengan systemctl status clash-verge-service dan sesuaikan dengan systemctl.", + "upgradeStateNotRestored": "Setelah pembaruan, status mulai otomatis dan berjalan sebelumnya dari layanan Clash Verge ({{state}}) tidak dapat dipulihkan. Memasang ulang layanan tidak akan memulihkannya; periksa dengan systemctl status clash-verge-service dan sesuaikan dengan systemctl.", "uninstallSuccess": "Layanan Berhasil Dicopot" }, "updater": { diff --git a/src/locales/jp/settings.json b/src/locales/jp/settings.json index b8dd6a981..71b81aa90 100644 --- a/src/locales/jp/settings.json +++ b/src/locales/jp/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "コアファイルとフォルダーを高い権限で安全に実行できるか確認できませんでした。", "permissionRepairGuide": "修復方法を見る", "sidecarFallback": "サービスでコアを起動できなかったため、Sidecar モードで動作を継続しています。サービスは引き続き利用できません。", - "upgradeStateNotRestored": "アップグレードで Clash Verge サービスを再インストールしましたが、以前の自動起動と実行状態({{state}})を復元できませんでした。サービスを再インストールしても復元されません。systemctl status clash-verge-service で状態を確認し、systemctl で調整してください。", + "upgradeStateNotRestored": "アップグレード後、Clash Verge サービスの以前の自動起動と実行状態({{state}})を復元できませんでした。サービスを再インストールしても復元されません。systemctl status clash-verge-service で状態を確認し、systemctl で調整してください。", "uninstallSuccess": "サービスのアンインストールに成功しました。" }, "updater": { diff --git a/src/locales/ko/settings.json b/src/locales/ko/settings.json index 3fac83495..0e08ff6d9 100644 --- a/src/locales/ko/settings.json +++ b/src/locales/ko/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "서비스가 코어 파일과 폴더를 높은 권한으로 안전하게 실행할 수 있는지 확인하지 못했습니다.", "permissionRepairGuide": "해결 방법 보기", "sidecarFallback": "서비스가 코어를 시작하지 못해 Sidecar 모드로 계속 실행합니다. 서비스는 여전히 사용할 수 없습니다.", - "upgradeStateNotRestored": "업그레이드 중 Clash Verge 서비스를 다시 설치했지만 이전 부팅 시 시작 및 실행 상태({{state}})를 복원하지 못했습니다. 서비스를 다시 설치해도 복원되지 않습니다. systemctl status clash-verge-service로 상태를 확인하고 systemctl로 조정하세요.", + "upgradeStateNotRestored": "업그레이드 후 Clash Verge 서비스의 이전 부팅 시 시작 및 실행 상태({{state}})를 복원하지 못했습니다. 서비스를 다시 설치해도 복원되지 않습니다. systemctl status clash-verge-service로 상태를 확인하고 systemctl로 조정하세요.", "uninstallSuccess": "서비스가 제거되었습니다" }, "updater": { diff --git a/src/locales/pt/settings.json b/src/locales/pt/settings.json index 58161e103..9fa5bb890 100644 --- a/src/locales/pt/settings.json +++ b/src/locales/pt/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "O serviço não conseguiu confirmar que os arquivos e pastas do núcleo são seguros para execução com privilégios elevados.", "permissionRepairGuide": "Ver instruções de reparo", "sidecarFallback": "O serviço não conseguiu iniciar o núcleo. Mudou para o modo Sidecar; o serviço continua indisponível.", - "upgradeStateNotRestored": "A atualização reinstalou o serviço do Clash Verge, mas não conseguiu restaurar o estado anterior de inicialização e execução ({{state}}). Reinstalar o serviço não o restaurará; verifique-o com systemctl status clash-verge-service e ajuste-o com systemctl.", + "upgradeStateNotRestored": "Após a atualização, não foi possível restaurar o estado anterior de inicialização e execução do serviço do Clash Verge ({{state}}). Reinstalar o serviço não o restaurará; verifique-o com systemctl status clash-verge-service e ajuste-o com systemctl.", "uninstallSuccess": "Serviço Desinstalado com Sucesso" }, "updater": { diff --git a/src/locales/ru/settings.json b/src/locales/ru/settings.json index 097d2c065..82d1a52c0 100644 --- a/src/locales/ru/settings.json +++ b/src/locales/ru/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "Служба не смогла подтвердить безопасность файлов и папок ядра для запуска с повышенными правами.", "permissionRepairGuide": "Инструкция по исправлению", "sidecarFallback": "Служба не смогла запустить ядро. Работа продолжена в режиме Sidecar; служба по-прежнему недоступна.", - "upgradeStateNotRestored": "Обновление переустановило службу Clash Verge, но не смогло восстановить её прежнее состояние автозапуска и работы ({{state}}). Переустановка службы его не восстановит; проверьте её командой systemctl status clash-verge-service и настройте через systemctl.", + "upgradeStateNotRestored": "После обновления не удалось восстановить прежнее состояние автозапуска и работы службы Clash Verge ({{state}}). Переустановка службы его не восстановит; проверьте её командой systemctl status clash-verge-service и настройте через systemctl.", "uninstallSuccess": "Служба успешно удалена" }, "updater": { diff --git a/src/locales/tr/settings.json b/src/locales/tr/settings.json index 96a69d8ae..e96563c13 100644 --- a/src/locales/tr/settings.json +++ b/src/locales/tr/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "Hizmet, çekirdek dosya ve klasörlerinin yükseltilmiş yetkilerle güvenle çalıştırılabileceğini doğrulayamadı.", "permissionRepairGuide": "Düzeltme adımlarını görüntüle", "sidecarFallback": "Hizmet çekirdeği başlatamadı. Sidecar moduna geçildi; hizmet hâlâ kullanılamıyor.", - "upgradeStateNotRestored": "Yükseltme Clash Verge hizmetini yeniden kurdu ancak önceki açılışta başlatma ve çalışma durumunu ({{state}}) geri yükleyemedi. Hizmeti yeniden kurmak bunu geri yüklemez; systemctl status clash-verge-service ile kontrol edin ve systemctl ile ayarlayın.", + "upgradeStateNotRestored": "Yükseltmeden sonra Clash Verge hizmetinin önceki açılışta başlatma ve çalışma durumu ({{state}}) geri yüklenemedi. Hizmeti yeniden kurmak bunu geri yüklemez; systemctl status clash-verge-service ile kontrol edin ve systemctl ile ayarlayın.", "uninstallSuccess": "Hizmet Başarıyla Kaldırıldı" }, "updater": { diff --git a/src/locales/tt/settings.json b/src/locales/tt/settings.json index 151505219..181c6874f 100644 --- a/src/locales/tt/settings.json +++ b/src/locales/tt/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "Хезмәт төш файлларын һәм папкаларын югары хокуклар белән имин эшләтеп булачагын раслый алмады.", "permissionRepairGuide": "Төзәтү күрсәтмәләрен карау", "sidecarFallback": "Хезмәт төшне эшләтеп җибәрә алмады. Эш Sidecar режимында дәвам итә; хезмәт һаман да эшләми.", - "upgradeStateNotRestored": "Яңарту Clash Verge хезмәтен яңадан урнаштырды, ләкин аның элекке автоҗибәрү һәм эшләү халәтен ({{state}}) кайтара алмады. Хезмәтне яңадан урнаштыру аны кайтармый; аны systemctl status clash-verge-service белән тикшерегез һәм systemctl белән көйләгез.", + "upgradeStateNotRestored": "Яңартудан соң Clash Verge хезмәтенең элекке автоҗибәрү һәм эшләү халәтен ({{state}}) кайтарып булмады. Хезмәтне яңадан урнаштыру аны кайтармый; аны systemctl status clash-verge-service белән тикшерегез һәм systemctl белән көйләгез.", "uninstallSuccess": "Сервис уңышлы салдырылды" }, "updater": { diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index 87be8e583..2c9f8c0ba 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "服务无法确认内核文件及所在目录是否安全,已拒绝高权限运行。", "permissionRepairGuide": "查看修复方法", "sidecarFallback": "服务无法启动内核,已降级为 Sidecar 模式运行,服务仍不可用。", - "upgradeStateNotRestored": "升级已重装 Clash Verge 服务,但未能恢复其原有的开机启动和运行状态({{state}})。重新安装服务也无法恢复该状态;请用 systemctl status clash-verge-service 检查服务状态,并用 systemctl 调整。", + "upgradeStateNotRestored": "升级后未能恢复 Clash Verge 服务原有的开机启动和运行状态({{state}})。重新安装服务也无法恢复该状态;请用 systemctl status clash-verge-service 检查服务状态,并用 systemctl 调整。", "uninstallSuccess": "已成功卸载服务" }, "updater": { diff --git a/src/locales/zhtw/settings.json b/src/locales/zhtw/settings.json index 9bb6e8863..5b1186195 100644 --- a/src/locales/zhtw/settings.json +++ b/src/locales/zhtw/settings.json @@ -697,7 +697,7 @@ "permissionRejectedReason": "服務無法確認核心檔案及所在目錄是否安全,已拒絕以高權限執行。", "permissionRepairGuide": "查看修復方法", "sidecarFallback": "服務無法啟動核心,已降級為 Sidecar 模式執行,服務仍無法使用。", - "upgradeStateNotRestored": "升級已重新安裝 Clash Verge 服務,但未能恢復其原有的開機啟動和執行狀態({{state}})。重新安裝服務也無法恢復該狀態;請用 systemctl status clash-verge-service 檢查服務狀態,並用 systemctl 調整。", + "upgradeStateNotRestored": "升級後未能恢復 Clash Verge 服務原有的開機啟動和執行狀態({{state}})。重新安裝服務也無法恢復該狀態;請用 systemctl status clash-verge-service 檢查服務狀態,並用 systemctl 調整。", "uninstallSuccess": "已成功解除安裝服務" }, "updater": {