mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-09 20:02:20 +08:00
feat(linux): reinstall an existing Service when upgrading the package
The deb postinst and rpm %post now reinstall the Service in place when an upgrade finds its systemd unit, reusing the unit's group so package-manager runs without a sudo/pkexec user keep the same IPC access. First installs and disabled, masked, or group-less units are left alone; failures warn and exit 0 because neither dpkg nor rpm can restore the previous Service from a failed postinst. The in-app updater stops a Service-run core before installing on Linux and restarts it if the install fails, so the post-update restart does not fail on the session lost when the Service restarts. Refs #8515 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -750,6 +750,17 @@ impl CoreManager {
|
||||
self.controlled_stop_core_inner().await
|
||||
}
|
||||
|
||||
/// Stops the core only when the Service runs it, returning whether it did. Waits for an in-flight start.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) async fn stop_service_core(&self) -> Result<bool> {
|
||||
let _life = self.lifecycle_lock.lock().await;
|
||||
if !matches!(*self.get_running_mode(), RunningMode::Service) {
|
||||
return Ok(false);
|
||||
}
|
||||
self.controlled_stop_core_inner().await?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub(crate) async fn controlled_stop_core_inner(&self) -> Result<()> {
|
||||
self.controlled_stop_core_with_intent(ProxyStopIntent::Clear).await
|
||||
}
|
||||
|
||||
@@ -292,8 +292,36 @@ impl SilentUpdater {
|
||||
Ok(updater_builder.build()?.check().await?)
|
||||
}
|
||||
|
||||
async fn install(update: Update, bytes: Vec<u8>) -> Result<()> {
|
||||
Ok(tokio::task::spawn_blocking(move || update.install(&bytes)).await??)
|
||||
async fn install(update: Update, bytes: Vec<u8>, timeout: Option<Duration>) -> Result<()> {
|
||||
// The package scripts reinstall an existing Service, killing the core it runs and its session;
|
||||
// stopping it first keeps the post-update restart from failing on that lost session.
|
||||
#[cfg(target_os = "linux")]
|
||||
let stopped_service_core = crate::core::CoreManager::global()
|
||||
.stop_service_core()
|
||||
.await
|
||||
.context("failed to stop the Service core before installing the update")?;
|
||||
|
||||
let install = tokio::task::spawn_blocking(move || update.install(&bytes));
|
||||
let joined = match timeout {
|
||||
Some(limit) => tokio::time::timeout(limit, install)
|
||||
.await
|
||||
.map_err(|_| anyhow::anyhow!("install timed out ({}s)", limit.as_secs())),
|
||||
None => Ok(install.await),
|
||||
};
|
||||
let result = joined.and_then(|joined| Ok(joined??));
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if result.is_err()
|
||||
&& stopped_service_core
|
||||
&& let Err(error) = crate::core::CoreManager::global().start_core().await
|
||||
{
|
||||
logging!(
|
||||
error,
|
||||
Type::System,
|
||||
"Failed to restart the core after the update install failed: {error:#}"
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Installs a newer cached update before normal startup, if the user confirms.
|
||||
@@ -369,11 +397,7 @@ impl SilentUpdater {
|
||||
Self::show_update_splash(app_handle, &version);
|
||||
|
||||
// `install()` may hang (#2558); on Windows NSIS can take over without returning.
|
||||
let install = tokio::time::timeout(std::time::Duration::from_secs(30), Self::install(update, bytes));
|
||||
match install
|
||||
.await
|
||||
.unwrap_or_else(|_| Err(anyhow::anyhow!("install timed out (30s)")))
|
||||
{
|
||||
match Self::install(update, bytes, Some(Duration::from_secs(30))).await {
|
||||
Ok(()) => {
|
||||
logging!(info, Type::System, "Update v{version} install triggered at startup");
|
||||
Self::delete_cache();
|
||||
@@ -417,7 +441,7 @@ impl SilentUpdater {
|
||||
};
|
||||
|
||||
logging!(info, Type::System, "Installing update v{version}...");
|
||||
Self::install(update, bytes).await?;
|
||||
Self::install(update, bytes, None).await?;
|
||||
Self::delete_cache();
|
||||
Ok(InstallUpdateOutcome::Installed)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user