mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
update source selectable
This commit is contained in:
@@ -1440,7 +1440,7 @@
|
||||
<value>如果自动更新下载过慢,可以手动下载并安装</value>
|
||||
</data>
|
||||
<data name="ViewDialogUpdatePackageMirrorHeader" xml:space="preserve">
|
||||
<value>下载链接</value>
|
||||
<value>下载源</value>
|
||||
</data>
|
||||
<data name="ViewDialogUpdatePackagePrimaryText" xml:space="preserve">
|
||||
<value>更新</value>
|
||||
|
||||
@@ -8,7 +8,6 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
using static Snap.Hutao.Win32.Kernel32;
|
||||
using static Snap.Hutao.Win32.Macros;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
|
||||
namespace Snap.Hutao.Service.Update;
|
||||
|
||||
internal sealed class HutaoSelectedMirrorInformation
|
||||
{
|
||||
public required Version Version { get; set; }
|
||||
|
||||
public required string Validation { get; set; }
|
||||
|
||||
public required HutaoPackageMirror Mirror { get; set; }
|
||||
}
|
||||
@@ -9,7 +9,7 @@ internal interface IUpdateService
|
||||
{
|
||||
ValueTask<CheckUpdateResult> CheckUpdateAsync(IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
|
||||
ValueTask<bool> DownloadUpdateAsync(CheckUpdateResult checkUpdateResult, IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
ValueTask<bool> DownloadUpdateAsync(HutaoSelectedMirrorInformation mirrorInformation, IProgress<UpdateStatus> progress, CancellationToken token = default);
|
||||
|
||||
LaunchUpdaterResult LaunchUpdater();
|
||||
}
|
||||
@@ -82,10 +82,9 @@ internal sealed partial class UpdateService : IUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<bool> DownloadUpdateAsync(CheckUpdateResult checkUpdateResult, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
public ValueTask<bool> DownloadUpdateAsync(HutaoSelectedMirrorInformation mirrorInformation, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(checkUpdateResult.PackageInformation);
|
||||
return DownloadUpdatePackageAsync(checkUpdateResult.PackageInformation, GetUpdatePackagePath(), progress, token);
|
||||
return DownloadUpdatePackageAsync(mirrorInformation, GetUpdatePackagePath(), progress, token);
|
||||
}
|
||||
|
||||
public LaunchUpdaterResult LaunchUpdater()
|
||||
@@ -131,70 +130,68 @@ internal sealed partial class UpdateService : IUpdateService
|
||||
return runtimeOptions.GetDataFolderUpdateCacheFolderFile("Snap.Hutao.msix");
|
||||
}
|
||||
|
||||
private async ValueTask<bool> DownloadUpdatePackageAsync(HutaoPackageInformation versionInformation, string filePath, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
private async ValueTask<bool> DownloadUpdatePackageAsync(HutaoSelectedMirrorInformation mirrorInformation, string filePath, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
string version = versionInformation.Version.ToString();
|
||||
|
||||
using IServiceScope scope = serviceProvider.CreateScope();
|
||||
using HttpClient httpClient = scope.ServiceProvider.GetRequiredService<HttpClient>();
|
||||
|
||||
foreach (HutaoPackageMirror mirror in versionInformation.Mirrors)
|
||||
HutaoPackageMirror mirror = mirrorInformation.Mirror;
|
||||
string version = mirrorInformation.Version.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
using HttpResponseMessage responseMessage = await httpClient.GetAsync(mirror.Url, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);
|
||||
long totalBytes = responseMessage.Content.Headers.ContentLength ?? 0;
|
||||
using Stream webStream = await responseMessage.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
|
||||
|
||||
switch (mirror.MirrorType)
|
||||
{
|
||||
using HttpResponseMessage responseMessage = await httpClient.GetAsync(mirror.Url, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);
|
||||
long totalBytes = responseMessage.Content.Headers.ContentLength ?? 0;
|
||||
using Stream webStream = await responseMessage.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
|
||||
case HutaoPackageMirrorType.Direct:
|
||||
using (FileStream fileStream = File.Create(filePath))
|
||||
{
|
||||
StreamCopyWorker<UpdateStatus> worker = new(webStream, fileStream, bytesRead => new UpdateStatus(version, bytesRead, totalBytes));
|
||||
await worker.CopyAsync(progress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
switch (mirror.MirrorType)
|
||||
{
|
||||
case HutaoPackageMirrorType.Direct:
|
||||
using (FileStream fileStream = File.Create(filePath))
|
||||
break;
|
||||
case HutaoPackageMirrorType.Archive:
|
||||
using (TempFileStream tempFileStream = new(FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
StreamCopyWorker<UpdateStatus> worker = new(webStream, tempFileStream, bytesRead => new UpdateStatus(version, bytesRead, totalBytes));
|
||||
await worker.CopyAsync(progress).ConfigureAwait(false);
|
||||
|
||||
using ZipArchive archive = new(tempFileStream);
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
StreamCopyWorker<UpdateStatus> worker = new(webStream, fileStream, bytesRead => new UpdateStatus(version, bytesRead, totalBytes));
|
||||
await worker.CopyAsync(progress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
break;
|
||||
case HutaoPackageMirrorType.Archive:
|
||||
using (TempFileStream tempFileStream = new(FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
StreamCopyWorker<UpdateStatus> worker = new(webStream, tempFileStream, bytesRead => new UpdateStatus(version, bytesRead, totalBytes));
|
||||
await worker.CopyAsync(progress).ConfigureAwait(false);
|
||||
|
||||
using ZipArchive archive = new(tempFileStream);
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
if (!entry.FullName.EndsWith(".msix", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!entry.FullName.EndsWith(".msix", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using Stream entryStream = entry.Open();
|
||||
using FileStream fileStream = File.Create(filePath);
|
||||
await entryStream.CopyToAsync(fileStream, token).ConfigureAwait(false);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
using Stream entryStream = entry.Open();
|
||||
using FileStream fileStream = File.Create(filePath);
|
||||
await entryStream.CopyToAsync(fileStream, token).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string? remoteHash = versionInformation.Validation;
|
||||
ArgumentNullException.ThrowIfNull(remoteHash);
|
||||
if (await CheckUpdateCacheSHA256Async(filePath, remoteHash, token).ConfigureAwait(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
catch
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string? remoteHash = mirrorInformation.Validation;
|
||||
ArgumentNullException.ThrowIfNull(remoteHash);
|
||||
if (await CheckUpdateCacheSHA256Async(filePath, remoteHash, token).ConfigureAwait(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -6,7 +6,6 @@ using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Core.Graphics;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
@@ -22,7 +22,6 @@ using Snap.Hutao.UI.Xaml.Media.Backdrop;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.Graphics.Dwm;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.IO;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
using Windows.UI;
|
||||
|
||||
@@ -15,12 +15,6 @@
|
||||
Style="{ThemeResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<ContentDialog.Resources>
|
||||
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
||||
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
|
||||
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
|
||||
</ContentDialog.Resources>
|
||||
|
||||
<StackPanel Spacing="16">
|
||||
<TextBlock>
|
||||
<Run Text="{shuxm:ResourceString Name=ViewTitileUpdatePackageDownloadContent}"/>
|
||||
@@ -31,28 +25,15 @@
|
||||
<Run/>
|
||||
</TextBlock>
|
||||
|
||||
<cwc:SettingsExpander
|
||||
Description="{shuxm:ResourceString Name=ViewDialogUpdatePackageMirrorDescription}"
|
||||
<ListView
|
||||
Header="{shuxm:ResourceString Name=ViewDialogUpdatePackageMirrorHeader}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind Mirrors}">
|
||||
<cwc:SettingsExpander.ItemTemplate>
|
||||
ItemsSource="{x:Bind Mirrors}"
|
||||
SelectedItem="{x:Bind SelectedItem}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<cwc:SettingsCard
|
||||
MinWidth="0"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Header="{Binding MirrorName}"
|
||||
IsClickEnabled="True">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="Click">
|
||||
<cwb:NavigateToUriAction NavigateUri="{Binding Url}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</cwc:SettingsCard>
|
||||
<TextBlock Text="{Binding MirrorName}"/>
|
||||
</DataTemplate>
|
||||
</cwc:SettingsExpander.ItemTemplate>
|
||||
</cwc:SettingsExpander>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
@@ -7,10 +7,21 @@ using Snap.Hutao.Web.Hutao;
|
||||
namespace Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
|
||||
[DependencyProperty("Mirrors", typeof(List<HutaoPackageMirror>))]
|
||||
[DependencyProperty("SelectedItem", typeof(HutaoPackageMirror))]
|
||||
internal sealed partial class UpdatePackageDownloadConfirmDialog : ContentDialog
|
||||
{
|
||||
public UpdatePackageDownloadConfirmDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public async ValueTask<ValueResult<bool, HutaoPackageMirror>> GetSelectedMirrorAsync()
|
||||
{
|
||||
if (await ShowAsync() is ContentDialogResult.Primary)
|
||||
{
|
||||
return new(true, SelectedItem);
|
||||
}
|
||||
|
||||
return new(false, default!);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Graphics.Canvas.Effects;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Caching;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
@@ -21,10 +20,6 @@ using System.IO;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 测试视图模型
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class TestViewModel : Abstraction.ViewModel
|
||||
|
||||
@@ -15,6 +15,7 @@ using Snap.Hutao.UI.Xaml.Behavior.Action;
|
||||
using Snap.Hutao.UI.Xaml.Control;
|
||||
using Snap.Hutao.UI.Xaml.View.Dialog;
|
||||
using Snap.Hutao.UI.Xaml.View.Window.WebView2;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
@@ -95,11 +96,22 @@ internal sealed partial class TitleViewModel : Abstraction.ViewModel
|
||||
|
||||
dialog.Title = SH.FormatViewTitileUpdatePackageDownloadTitle(UpdateStatus?.Version);
|
||||
dialog.Mirrors = checkUpdateResult.PackageInformation?.Mirrors;
|
||||
dialog.SelectedItem = dialog.Mirrors?.FirstOrDefault();
|
||||
|
||||
if (await dialog.ShowAsync() is ContentDialogResult.Primary)
|
||||
(bool isOk, HutaoPackageMirror mirror) = await dialog.GetSelectedMirrorAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(checkUpdateResult.PackageInformation);
|
||||
HutaoSelectedMirrorInformation mirrorInformation = new()
|
||||
{
|
||||
Mirror = mirror,
|
||||
Validation = checkUpdateResult.PackageInformation.Validation,
|
||||
Version = checkUpdateResult.PackageInformation.Version,
|
||||
};
|
||||
|
||||
// This method will set CheckUpdateResult.Kind to NeedInstall if download success
|
||||
if (!await DownloadPackageAsync(progress, checkUpdateResult).ConfigureAwait(false))
|
||||
if (!await DownloadPackageAsync(progress, mirrorInformation, checkUpdateResult).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Warning(SH.ViewTitileUpdatePackageDownloadFailedMessage);
|
||||
return;
|
||||
@@ -139,12 +151,12 @@ internal sealed partial class TitleViewModel : Abstraction.ViewModel
|
||||
UpdateStatus = null;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> DownloadPackageAsync(IProgress<UpdateStatus> progress, CheckUpdateResult checkUpdateResult)
|
||||
private async ValueTask<bool> DownloadPackageAsync(IProgress<UpdateStatus> progress, HutaoSelectedMirrorInformation mirrorInformation, CheckUpdateResult checkUpdateResult)
|
||||
{
|
||||
bool downloadSuccess = true;
|
||||
try
|
||||
{
|
||||
if (await updateService.DownloadUpdateAsync(checkUpdateResult, progress).ConfigureAwait(false))
|
||||
if (await updateService.DownloadUpdateAsync(mirrorInformation, progress).ConfigureAwait(false))
|
||||
{
|
||||
checkUpdateResult.Kind = CheckUpdateResultKind.NeedInstall;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ internal static class ApiOsEndpoints
|
||||
public const string CalculateWeaponList = $"{SgPublicApi}/event/calculateos/weapon/list";
|
||||
public const string CalculateCompute = $"{SgPublicApi}/event/calculateos/compute";
|
||||
public const string CalculateBatchCompute = $"{SgPublicApi}/event/calculateos/batch_compute";
|
||||
|
||||
public static string CalculateSyncAvatarDetail(in AvatarId avatarId, in PlayerUid uid)
|
||||
{
|
||||
return $"{SgPublicApi}/event/calculateos/sync/avatar/detail?avatar_id={avatarId.Value}&uid={uid.Value}®ion={uid.Region}";
|
||||
|
||||
@@ -9,7 +9,7 @@ internal sealed class HutaoPackageInformation
|
||||
public Version Version { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("validation")]
|
||||
public string? Validation { get; set; } = default!;
|
||||
public string Validation { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("mirrors")]
|
||||
public List<HutaoPackageMirror> Mirrors { get; set; } = default!;
|
||||
|
||||
Reference in New Issue
Block a user