mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
update flow rework
This commit is contained in:
@@ -24,7 +24,13 @@ internal static class DependencyInjection
|
||||
ServiceProvider serviceProvider = new ServiceCollection()
|
||||
|
||||
// Microsoft extension
|
||||
.AddLogging(builder => builder.AddDebug().AddConsoleWindow())
|
||||
.AddLogging(builder =>
|
||||
{
|
||||
builder
|
||||
.SetMinimumLevel(LogLevel.Trace)
|
||||
.AddDebug()
|
||||
.AddConsoleWindow();
|
||||
})
|
||||
.AddMemoryCache()
|
||||
|
||||
// Hutao extensions
|
||||
|
||||
@@ -9,7 +9,11 @@ internal static class LoggerFactoryExtension
|
||||
{
|
||||
builder.Services.AddSingleton<ConsoleWindowLifeTime>();
|
||||
|
||||
builder.AddSimpleConsole();
|
||||
builder.AddSimpleConsole(options =>
|
||||
{
|
||||
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -2834,6 +2834,15 @@
|
||||
<data name="ViewSpiralAbyssUploadRecord" xml:space="preserve">
|
||||
<value>上传数据</value>
|
||||
</data>
|
||||
<data name="ViewTitileUpdatePackageDownloadContent" xml:space="preserve">
|
||||
<value>是否立即下载</value>
|
||||
</data>
|
||||
<data name="ViewTitileUpdatePackageDownloadFailedMessage" xml:space="preserve">
|
||||
<value>下载更新失败</value>
|
||||
</data>
|
||||
<data name="ViewTitileUpdatePackageDownloadTitle" xml:space="preserve">
|
||||
<value>胡桃 {0} 版本已发布</value>
|
||||
</data>
|
||||
<data name="ViewTitileUpdatePackageReadyContent" xml:space="preserve">
|
||||
<value>是否立即安装?</value>
|
||||
</data>
|
||||
@@ -2843,6 +2852,9 @@
|
||||
<data name="ViewTitleAutoClicking" xml:space="preserve">
|
||||
<value>自动连点</value>
|
||||
</data>
|
||||
<data name="ViewTitleUpdatePackageInstallingContent" xml:space="preserve">
|
||||
<value>正在安装更新</value>
|
||||
</data>
|
||||
<data name="ViewToolHeader" xml:space="preserve">
|
||||
<value>工具</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.IO.Hashing;
|
||||
using Snap.Hutao.Core.IO.Http.Sharding;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
using Snap.Hutao.Web.Hutao.Response;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Snap.Hutao.Service.Update;
|
||||
|
||||
internal sealed class CheckUpdateResult
|
||||
{
|
||||
public CheckUpdateResultKind Kind { get; set; }
|
||||
|
||||
public HutaoVersionInformation? HutaoVersionInformation { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Update;
|
||||
|
||||
internal enum CheckUpdateResultKind
|
||||
{
|
||||
None = 0,
|
||||
VersionApiInvalidResponse = 1,
|
||||
VersionApiInvalidSha256 = 2,
|
||||
AlreayUpdated = 3,
|
||||
|
||||
NeedDownload = 4,
|
||||
NeedInstall = 5,
|
||||
}
|
||||
@@ -7,7 +7,9 @@ namespace Snap.Hutao.Service.Abstraction;
|
||||
|
||||
internal interface IUpdateService
|
||||
{
|
||||
ValueTask<bool> CheckForUpdateAndDownloadAsync(IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
ValueTask<CheckUpdateResult> CheckUpdateAsync(IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
|
||||
ValueTask<bool> LaunchUpdaterAsync();
|
||||
ValueTask<bool> DownloadUpdateAsync(CheckUpdateResult checkUpdateResult, IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
|
||||
ValueTask<LaunchUpdaterResult> LaunchUpdaterAsync();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.IO.Hashing;
|
||||
using Snap.Hutao.Core.IO.Http.Sharding;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
using Snap.Hutao.Web.Hutao.Response;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Snap.Hutao.Service.Update;
|
||||
|
||||
internal sealed class LaunchUpdaterResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
|
||||
public Process? Process { get; set; }
|
||||
}
|
||||
@@ -24,54 +24,71 @@ internal sealed partial class UpdateService : IUpdateService
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public async ValueTask<bool> CheckForUpdateAndDownloadAsync(IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
public async ValueTask<CheckUpdateResult> CheckUpdateAsync(IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
ITaskContext taskContext = scope.ServiceProvider.GetRequiredService<ITaskContext>();
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
|
||||
HutaoInfrastructureClient infrastructureClient = serviceProvider.GetRequiredService<HutaoInfrastructureClient>();
|
||||
HutaoInfrastructureClient infrastructureClient = scope.ServiceProvider.GetRequiredService<HutaoInfrastructureClient>();
|
||||
HutaoResponse<HutaoVersionInformation> response = await infrastructureClient.GetHutaoVersionInfomationAsync(token).ConfigureAwait(false);
|
||||
|
||||
CheckUpdateResult checkUpdateResult = new();
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
return false;
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.VersionApiInvalidResponse;
|
||||
return checkUpdateResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.NeedDownload;
|
||||
checkUpdateResult.HutaoVersionInformation = response.Data;
|
||||
}
|
||||
|
||||
HutaoVersionInformation versionInformation = response.Data;
|
||||
string msixPath = GetUpdatePackagePath();
|
||||
|
||||
if (!LocalSetting.Get(SettingKeys.OverrideUpdateVersionComparison, false))
|
||||
{
|
||||
if (scope.ServiceProvider.GetRequiredService<RuntimeOptions>().Version >= versionInformation.Version)
|
||||
// Launched in an updated version
|
||||
if (scope.ServiceProvider.GetRequiredService<RuntimeOptions>().Version >= checkUpdateResult.HutaoVersionInformation.Version)
|
||||
{
|
||||
if (File.Exists(msixPath))
|
||||
{
|
||||
File.Delete(msixPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.AlreayUpdated;
|
||||
return checkUpdateResult;
|
||||
}
|
||||
}
|
||||
|
||||
progress.Report(new(versionInformation.Version.ToString(), 0, 0));
|
||||
progress.Report(new(checkUpdateResult.HutaoVersionInformation.Version.ToString(), 0, 0));
|
||||
|
||||
if (versionInformation.Sha256 is not { Length: > 0 } sha256)
|
||||
if (checkUpdateResult.HutaoVersionInformation.Sha256 is not { Length: > 0 } sha256)
|
||||
{
|
||||
return false;
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.VersionApiInvalidSha256;
|
||||
return checkUpdateResult;
|
||||
}
|
||||
|
||||
if (File.Exists(msixPath) && await CheckUpdateCacheSHA256Async(msixPath, sha256, token).ConfigureAwait(false))
|
||||
{
|
||||
return true;
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.NeedInstall;
|
||||
return checkUpdateResult;
|
||||
}
|
||||
|
||||
return await DownloadUpdatePackageAsync(versionInformation, msixPath, progress, token).ConfigureAwait(false);
|
||||
return checkUpdateResult;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> LaunchUpdaterAsync()
|
||||
public ValueTask<bool> DownloadUpdateAsync(CheckUpdateResult checkUpdateResult, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(checkUpdateResult.HutaoVersionInformation);
|
||||
return DownloadUpdatePackageAsync(checkUpdateResult.HutaoVersionInformation, GetUpdatePackagePath(), progress, token);
|
||||
}
|
||||
|
||||
public async ValueTask<LaunchUpdaterResult> LaunchUpdaterAsync()
|
||||
{
|
||||
RuntimeOptions runtimeOptions = serviceProvider.GetRequiredService<RuntimeOptions>();
|
||||
string updaterTargetPath = runtimeOptions.GetDataFolderUpdateCacheFolderFile(UpdaterFilename);
|
||||
@@ -88,19 +105,19 @@ internal sealed partial class UpdateService : IUpdateService
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo()
|
||||
Process? process = Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
Arguments = commandLine,
|
||||
FileName = updaterTargetPath,
|
||||
UseShellExecute = true,
|
||||
});
|
||||
|
||||
return true;
|
||||
return new() { IsSuccess = true, Process = process };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Error(ex);
|
||||
return false;
|
||||
return new() { IsSuccess = false };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -321,11 +321,11 @@
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240311000" />
|
||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||
<PackageReference Include="Snap.Discord.GameSDK" Version="1.6.0" />
|
||||
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.15.3">
|
||||
<PackageReference Include="Snap.Hutao.Deployment.Runtime" Version="1.16.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Snap.Hutao.SourceGeneration" Version="1.0.6">
|
||||
<PackageReference Include="Snap.Hutao.SourceGeneration" Version="1.0.7">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Windowing.HotKey;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Progress;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Service.Update;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
@@ -19,6 +22,7 @@ internal sealed partial class TitleViewModel : Abstraction.ViewModel
|
||||
{
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IProgressFactory progressFactory;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly HotKeyOptions hotKeyOptions;
|
||||
private readonly IUpdateService updateService;
|
||||
@@ -61,21 +65,79 @@ internal sealed partial class TitleViewModel : Abstraction.ViewModel
|
||||
private async ValueTask DoCheckUpdateAsync()
|
||||
{
|
||||
IProgress<UpdateStatus> progress = progressFactory.CreateForMainThread<UpdateStatus>(status => UpdateStatus = status);
|
||||
if (await updateService.CheckForUpdateAndDownloadAsync(progress).ConfigureAwait(false))
|
||||
CheckUpdateResult checkUpdateResult = await updateService.CheckUpdateAsync(progress).ConfigureAwait(false);
|
||||
|
||||
if (checkUpdateResult.Kind is CheckUpdateResultKind.NeedDownload)
|
||||
{
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
ContentDialogResult downloadUpdateUserConsentResult = await contentDialogFactory
|
||||
.CreateForConfirmCancelAsync(
|
||||
SH.FormatViewTitileUpdatePackageDownloadTitle(UpdateStatus?.Version),
|
||||
SH.ViewTitileUpdatePackageDownloadContent,
|
||||
ContentDialogButton.Primary)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (downloadUpdateUserConsentResult is ContentDialogResult.Primary)
|
||||
{
|
||||
// This method will set CheckUpdateResult.Kind to NeedInstall if download success
|
||||
if (!await DownloadPackageAsync(progress, checkUpdateResult).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Warning(SH.ViewTitileUpdatePackageDownloadFailedMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkUpdateResult.Kind is CheckUpdateResultKind.NeedInstall)
|
||||
{
|
||||
ContentDialogResult installUpdateUserConsentResult = await contentDialogFactory
|
||||
.CreateForConfirmCancelAsync(
|
||||
SH.FormatViewTitileUpdatePackageReadyTitle(UpdateStatus?.Version),
|
||||
SH.ViewTitileUpdatePackageReadyContent,
|
||||
ContentDialogButton.Primary)
|
||||
.ConfigureAwait(false);
|
||||
if (result == ContentDialogResult.Primary)
|
||||
|
||||
if (installUpdateUserConsentResult is ContentDialogResult.Primary)
|
||||
{
|
||||
await updateService.LaunchUpdaterAsync().ConfigureAwait(false);
|
||||
LaunchUpdaterResult launchUpdaterResult = await updateService.LaunchUpdaterAsync().ConfigureAwait(false);
|
||||
if (launchUpdaterResult.IsSuccess)
|
||||
{
|
||||
ContentDialog contentDialog = await contentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewTitleUpdatePackageInstallingContent)
|
||||
.ConfigureAwait(false);
|
||||
using (await contentDialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
{
|
||||
if (launchUpdaterResult.Process is { } updater)
|
||||
{
|
||||
await updater.WaitForExitAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
UpdateStatus = null;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> DownloadPackageAsync(IProgress<UpdateStatus> progress, CheckUpdateResult checkUpdateResult)
|
||||
{
|
||||
bool downloadSuccess = true;
|
||||
try
|
||||
{
|
||||
if (await updateService.DownloadUpdateAsync(checkUpdateResult, progress).ConfigureAwait(false))
|
||||
{
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.NeedInstall;
|
||||
}
|
||||
else
|
||||
{
|
||||
downloadSuccess = false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
downloadSuccess = false;
|
||||
}
|
||||
|
||||
return downloadSuccess;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user