mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
update service
This commit is contained in:
23
src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/SHA256.cs
Normal file
23
src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/SHA256.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Core.IO.Hashing;
|
||||
|
||||
internal static class SHA256
|
||||
{
|
||||
public static async ValueTask<string> HashFileAsync(string filePath, CancellationToken token = default)
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
return await HashAsync(stream, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask<string> HashAsync(Stream stream, CancellationToken token = default)
|
||||
{
|
||||
byte[] bytes = await System.Security.Cryptography.SHA256.HashDataAsync(stream, token).ConfigureAwait(false);
|
||||
return System.Convert.ToHexString(bytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction;
|
||||
|
||||
internal interface IUpdateService
|
||||
{
|
||||
}
|
||||
95
src/Snap.Hutao/Snap.Hutao/Service/UpdateService.cs
Normal file
95
src/Snap.Hutao/Snap.Hutao/Service/UpdateService.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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.Service.Abstraction;
|
||||
using Snap.Hutao.Web.Hutao;
|
||||
using Snap.Hutao.Web.Hutao.Response;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Service;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(IUpdateService))]
|
||||
internal sealed partial class UpdateService : IUpdateService
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public async ValueTask<bool> InitializeAsync(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>();
|
||||
HutaoResponse<HutaoVersionInformation> response = await infrastructureClient.GetHutaoVersionInfomationAsync(token).ConfigureAwait(false);
|
||||
|
||||
if (!response.IsOk())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HutaoVersionInformation versionInformation = response.Data;
|
||||
|
||||
if (versionInformation.Sha256 is not { } sha256)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string dataFolder = scope.ServiceProvider.GetRequiredService<RuntimeOptions>().DataFolder;
|
||||
string msixPath = Path.Combine(dataFolder, "UpdateCache/Snap.Hutao.msix");
|
||||
|
||||
if (await CheckUpdateCacheSHA256Async(msixPath, sha256, token).ConfigureAwait(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return await DownloadUpdatePackageAsync(versionInformation, msixPath, progress, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static async ValueTask<bool> CheckUpdateCacheSHA256Async(string filePath, string remoteHash, CancellationToken token = default)
|
||||
{
|
||||
string localHash = await SHA256.HashFileAsync(filePath, token).ConfigureAwait(false);
|
||||
return string.Equals(localHash, remoteHash, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private async ValueTask<bool> DownloadUpdatePackageAsync(HutaoVersionInformation versionInformation, string filePath, IProgress<UpdateStatus> progress, CancellationToken token = default)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
using (HttpClient httpClient = scope.ServiceProvider.GetRequiredService<HttpClient>())
|
||||
{
|
||||
string version = versionInformation.Version.ToString();
|
||||
foreach (string url in versionInformation.Urls)
|
||||
{
|
||||
HttpShardCopyWorkerOptions<UpdateStatus> options = new()
|
||||
{
|
||||
HttpClient = httpClient,
|
||||
SourceUrl = url,
|
||||
DestinationFilePath = filePath,
|
||||
StatusFactory = (bytesRead, totalBytes) => new UpdateStatus(version, bytesRead, totalBytes),
|
||||
};
|
||||
|
||||
using (HttpShardCopyWorker<UpdateStatus> worker = await HttpShardCopyWorker<UpdateStatus>.CreateAsync(options).ConfigureAwait(false))
|
||||
{
|
||||
await worker.CopyAsync(progress, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string? remoteHash = versionInformation.Sha256;
|
||||
ArgumentNullException.ThrowIfNull(remoteHash);
|
||||
if (await CheckUpdateCacheSHA256Async(filePath, remoteHash, token).ConfigureAwait(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
25
src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs
Normal file
25
src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Common;
|
||||
|
||||
namespace Snap.Hutao.Service;
|
||||
|
||||
internal sealed class UpdateStatus
|
||||
{
|
||||
public UpdateStatus(string version, long bytesRead, long totalBytes)
|
||||
{
|
||||
Version = version;
|
||||
BytesRead = bytesRead;
|
||||
TotalBytes = totalBytes;
|
||||
ProgressDescription = $"{Converters.ToFileSizeString(bytesRead)}/{Converters.ToFileSizeString(totalBytes)}";
|
||||
}
|
||||
|
||||
public string? Version { get; set; }
|
||||
|
||||
public long BytesRead { get; set; }
|
||||
|
||||
public long TotalBytes { get; set; }
|
||||
|
||||
public string ProgressDescription { get; }
|
||||
}
|
||||
@@ -7,4 +7,10 @@ internal sealed class HutaoVersionInformation
|
||||
{
|
||||
[JsonPropertyName("version")]
|
||||
public Version Version { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("urls")]
|
||||
public List<string> Urls { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("sha256")]
|
||||
public string? Sha256 { get; set; } = default!;
|
||||
}
|
||||
Reference in New Issue
Block a user