emo-client/Saradomin/Infrastructure/Services/ClientUpdateService.cs

96 lines
3.7 KiB
C#

using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Saradomin.Model.Settings.Launcher;
using Saradomin.Utilities;
namespace Saradomin.Infrastructure.Services
{
public class ClientUpdateService : IClientUpdateService
{
private readonly ISettingsService _settingsService;
private float CurrentDownloadProgress { get; set; }
public string ClientDownloadURL => "https://assets.emoscape.org/rt4-client.jar";
public string ClientHashURL => "https://assets.emoscape.org/rt4-client.jar.sha256";
public string PreferredTargetFilePath =>
CrossPlatform.Get2009scapeExecutable();
public event EventHandler<float> DownloadProgressChanged;
public ClientUpdateService(ISettingsService settingsService)
{
_settingsService = settingsService;
}
public async Task<string> FetchRemoteClientHashAsync(CancellationToken cancellationToken)
{
using var httpClient = new HttpClient();
{
var response = await httpClient.GetAsync(ClientHashURL, cancellationToken);
return await response.Content.ReadAsStringAsync(cancellationToken);
}
}
public async Task FetchRemoteClientExecutableAsync(CancellationToken cancellationToken, string targetPath = null)
{
CurrentDownloadProgress = 0;
targetPath ??= PreferredTargetFilePath;
// Define a temporary file path to download to
string tempFilePath = targetPath + ".tmp";
// Download the client to the temporary file regardless of whether it already exists.
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(ClientDownloadURL, cancellationToken);
var contentLength = response.Content.Headers.ContentLength ?? 12 * 1024 * 1024 * 1024f;
using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
using (var outFileStream = File.Create(tempFilePath))
{
var buffer = new byte[1024];
var totalRead = 0;
int bytesRead;
while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
await outFileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
totalRead += bytesRead;
CurrentDownloadProgress = totalRead / contentLength;
DownloadProgressChanged?.Invoke(this, CurrentDownloadProgress);
}
}
}
// Replace the existing file only after a successful download.
if (File.Exists(targetPath))
{
File.Delete(targetPath);
}
File.Move(tempFilePath, targetPath);
}
public async Task<string> ComputeLocalClientHashAsync(string filePath = null)
{
filePath ??= PreferredTargetFilePath;
if (!File.Exists(filePath))
throw new FileNotFoundException($"Unable to calculate local client hash. File '{filePath}' missing.");
await using var stream = File.OpenRead(filePath);
{
var sha256 = SHA256.Create();
stream.Position = 0;
var hash = await sha256.ComputeHashAsync(stream);
return BitConverter.ToString(hash).Replace("-", string.Empty);
}
}
}
}