Update CheckUpdateViewModel.cs

This commit is contained in:
JieXu 2025-09-11 23:08:54 +08:00 committed by GitHub
parent 9df4726530
commit 3b2da0924d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,8 @@
using System; // +++
using System.IO; // +++
using System.Linq; // +++
using System.Threading.Tasks; // +++
using System.Collections.Generic;// +++
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
@ -64,7 +66,7 @@ public class CheckUpdateViewModel : MyReactiveObject
CheckUpdateModels.Add(GetCheckUpdateModel(_geo));
}
// +++ 新增:在打包环境(AppImage/DEB/RPM)下返回 true其他返回 false
// ---- packaged env detection: AppImage or runs from /opt/v2rayN ----
private static bool IsPackagedInstall()
{
try
@ -72,28 +74,31 @@ public class CheckUpdateViewModel : MyReactiveObject
if (Utils.IsWindows())
return false;
// AppImage: 环境变量 APPIMAGE 存在
// AppImage: APPIMAGE var exists
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPIMAGE")))
return true;
// 安装到 /opt/v2rayN 视为打包安装deb/rpm
var sp = Utils.StartupPath()?.Replace('\\', '/');
if (!string.IsNullOrEmpty(sp) && sp.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase))
return true;
if (Directory.Exists("/opt/v2rayN"))
return true;
// deb/rpm: current startup path is under /opt/v2rayN
var sp = Utils.StartupPath();
if (!string.IsNullOrEmpty(sp))
{
sp = sp.Replace('\\', '/');
if (sp.Equals("/opt/v2rayN", StringComparison.OrdinalIgnoreCase) ||
sp.StartsWith("/opt/v2rayN/", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
catch
{
// ignore
}
return false;
}
private CheckUpdateModel GetCheckUpdateModel(string coreType)
{
// +++ 打包环境下禁用 v2rayN 自更新,默认关并标注 Not Support
// packaged env: disable v2rayN self-update
if (coreType == _v2rayN && IsPackagedInstall())
{
return new()
@ -114,7 +119,7 @@ public class CheckUpdateViewModel : MyReactiveObject
private async Task SaveSelectedCoreTypes()
{
// +++ 打包环境下,不保存 v2rayN 的选择状态
// packaged env: do not persist v2rayN toggle
var list = CheckUpdateModels
.Where(t => t.IsSelected == true && !(IsPackagedInstall() && t.CoreType == _v2rayN))
.Select(t => t.CoreType ?? "")
@ -151,7 +156,6 @@ public class CheckUpdateViewModel : MyReactiveObject
}
else if (item.CoreType == _v2rayN)
{
// +++ 打包环境下,直接跳过 v2rayN 自更新
if (IsPackagedInstall())
{
await UpdateView(_v2rayN, "Not Support");
@ -193,200 +197,4 @@ public class CheckUpdateViewModel : MyReactiveObject
await UpdateView(_geo, msg);
if (success)
{
UpdatedPlusPlus(_geo, "");
}
}
await (new UpdateService()).UpdateGeoFileAll(_config, _updateUI)
.ContinueWith(t =>
{
UpdatedPlusPlus(_geo, "");
});
}
private async Task CheckUpdateN(bool preRelease)
{
async Task _updateUI(bool success, string msg)
{
await UpdateView(_v2rayN, msg);
if (success)
{
await UpdateView(_v2rayN, ResUI.OperationSuccess);
UpdatedPlusPlus(_v2rayN, msg);
}
}
await (new UpdateService()).CheckUpdateGuiN(_config, _updateUI, preRelease)
.ContinueWith(t =>
{
UpdatedPlusPlus(_v2rayN, "");
});
}
private async Task CheckUpdateCore(CheckUpdateModel model, bool preRelease)
{
async Task _updateUI(bool success, string msg)
{
await UpdateView(model.CoreType, msg);
if (success)
{
await UpdateView(model.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
UpdatedPlusPlus(model.CoreType, msg);
}
}
var type = (ECoreType)Enum.Parse(typeof(ECoreType), model.CoreType);
await (new UpdateService()).CheckUpdateCore(type, _config, _updateUI, preRelease)
.ContinueWith(t =>
{
UpdatedPlusPlus(model.CoreType, "");
});
}
private async Task UpdateFinished()
{
if (_lstUpdated.Count > 0 && _lstUpdated.Count(x => x.IsFinished == true) == _lstUpdated.Count)
{
await UpdateFinishedSub(false);
await Task.Delay(2000);
await UpgradeCore();
if (_lstUpdated.Any(x => x.CoreType == _v2rayN && x.IsFinished == true))
{
await Task.Delay(1000);
await UpgradeN();
}
await Task.Delay(1000);
await UpdateFinishedSub(true);
}
}
private async Task UpdateFinishedSub(bool blReload)
{
RxApp.MainThreadScheduler.Schedule(blReload, (scheduler, blReload) =>
{
_ = UpdateFinishedResult(blReload);
return Disposable.Empty;
});
}
public async Task UpdateFinishedResult(bool blReload)
{
if (blReload)
{
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
else
{
Locator.Current.GetService<MainWindowViewModel>()?.CloseCore();
}
}
private async Task UpgradeN()
{
try
{
var fileName = _lstUpdated.FirstOrDefault(x => x.CoreType == _v2rayN)?.FileName;
if (fileName.IsNullOrEmpty())
{
return;
}
if (!Utils.UpgradeAppExists(out var upgradeFileName))
{
await UpdateView(_v2rayN, ResUI.UpgradeAppNotExistTip);
NoticeManager.Instance.SendMessageAndEnqueue(ResUI.UpgradeAppNotExistTip);
Logging.SaveLog("UpgradeApp does not exist");
return;
}
var id = ProcUtils.ProcessStart(upgradeFileName, fileName, Utils.StartupPath());
if (id > 0)
{
await AppManager.Instance.AppExitAsync(true);
}
}
catch (Exception ex)
{
await UpdateView(_v2rayN, ex.Message);
}
}
private async Task UpgradeCore()
{
foreach (var item in _lstUpdated)
{
if (item.FileName.IsNullOrEmpty())
{
continue;
}
var fileName = item.FileName;
if (!File.Exists(fileName))
{
continue;
}
var toPath = Utils.GetBinPath("", item.CoreType);
if (fileName.Contains(".tar.gz"))
{
FileManager.DecompressTarFile(fileName, toPath);
var dir = new DirectoryInfo(toPath);
if (dir.Exists)
{
foreach (var subDir in dir.GetDirectories())
{
FileManager.CopyDirectory(subDir.FullName, toPath, false, true);
subDir.Delete(true);
}
}
}
else if (fileName.Contains(".gz"))
{
FileManager.DecompressFile(fileName, toPath, item.CoreType);
}
else
{
FileManager.ZipExtractToFile(fileName, toPath, "geo");
}
if (Utils.IsNonWindows())
{
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList)
{
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower()));
}
}
await UpdateView(item.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfully);
if (File.Exists(fileName))
{
File.Delete(fileName);
}
}
}
private async Task UpdateView(string coreType, string msg)
{
var item = new CheckUpdateModel()
{
CoreType = coreType,
Remarks = msg,
};
RxApp.MainThreadScheduler.Schedule(item, (scheduler, model) =>
{
_ = UpdateViewResult(model);
return Disposable.Empty;
});
}
public async Task UpdateViewResult(CheckUpdateModel model)
{
var found = CheckUpdateModels.FirstOrDefault(t => t.CoreType == model.CoreType);
if (found == null)
{
return;
}
found.Remarks = model.Remarks;
}
}
Updated