2023-07-12 09:19:33 +02:00
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Threading.Tasks;
|
2023-05-18 20:04:00 -04:00
|
|
|
|
using Serilog;
|
2023-05-11 23:11:39 -04:00
|
|
|
|
using SPTInstaller.Models;
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
namespace SPTInstaller.Helpers;
|
|
|
|
|
|
|
|
|
|
public static class DownloadCacheHelper
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
private static HttpClient _httpClient = new() { Timeout = TimeSpan.FromHours(1) };
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-30 16:15:52 -04:00
|
|
|
|
public static string CachePath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "spt-installer/cache");
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-08-25 23:46:11 -04:00
|
|
|
|
public static string GetCacheSizeText()
|
|
|
|
|
{
|
|
|
|
|
if (!Directory.Exists(CachePath))
|
|
|
|
|
return "No cache folder";
|
|
|
|
|
|
|
|
|
|
var cacheDir = new DirectoryInfo(CachePath);
|
|
|
|
|
|
|
|
|
|
var cacheSize = DirectorySizeHelper.GetSizeOfDirectory(cacheDir);
|
|
|
|
|
|
|
|
|
|
if (cacheSize == 0)
|
|
|
|
|
return "Empty";
|
|
|
|
|
|
|
|
|
|
return DirectorySizeHelper.SizeSuffix(cacheSize);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
private static bool CheckCache(FileInfo cacheFile, string expectedHash = null)
|
|
|
|
|
{
|
|
|
|
|
try
|
2023-03-06 18:28:02 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
cacheFile.Refresh();
|
2023-07-30 16:15:52 -04:00
|
|
|
|
Directory.CreateDirectory(CachePath);
|
2023-03-06 18:28:02 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
if (cacheFile.Exists)
|
|
|
|
|
{
|
|
|
|
|
if (expectedHash != null && FileHashHelper.CheckHash(cacheFile, expectedHash))
|
2023-03-06 18:28:02 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
Log.Information($"Using cached file: {cacheFile.Name} - Hash: {expectedHash}");
|
|
|
|
|
return true;
|
2023-03-06 18:28:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
cacheFile.Delete();
|
|
|
|
|
cacheFile.Refresh();
|
2023-03-06 18:28:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
catch
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
private static async Task<Result> DownloadFile(FileInfo outputFile, string targetLink, IProgress<double> progress, string expectedHash = null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Use the provided extension method
|
|
|
|
|
using (var file = new FileStream(outputFile.FullName, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
|
|
|
await _httpClient.DownloadDataAsync(targetLink, file, progress);
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
outputFile.Refresh();
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
if (!outputFile.Exists)
|
|
|
|
|
{
|
|
|
|
|
return Result.FromError($"Failed to download {outputFile.Name}");
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
2023-07-12 09:19:33 +02:00
|
|
|
|
|
|
|
|
|
if (expectedHash != null && !FileHashHelper.CheckHash(outputFile, expectedHash))
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return Result.FromError("Hash mismatch");
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return Result.FromSuccess();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return Result.FromError(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
private static async Task<Result> ProcessInboundStreamAsync(FileInfo cacheFile, Stream downloadStream, string expectedHash = null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (CheckCache(cacheFile, expectedHash)) return Result.FromSuccess();
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
using var patcherFileStream = cacheFile.Open(FileMode.Create);
|
|
|
|
|
{
|
|
|
|
|
await downloadStream.CopyToAsync(patcherFileStream);
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
patcherFileStream.Close();
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
if (expectedHash != null && !FileHashHelper.CheckHash(cacheFile, expectedHash))
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return Result.FromError("Hash mismatch");
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
2023-07-12 09:19:33 +02:00
|
|
|
|
|
|
|
|
|
return Result.FromSuccess();
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
2023-07-12 09:19:33 +02:00
|
|
|
|
catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return Result.FromError(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
private static async Task<Result> ProcessInboundFileAsync(FileInfo cacheFile, string targetLink, IProgress<double> progress, string expectedHash = null)
|
|
|
|
|
{
|
|
|
|
|
try
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
if (CheckCache(cacheFile, expectedHash)) return Result.FromSuccess();
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return await DownloadFile(cacheFile, targetLink, progress, expectedHash);
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
2023-07-12 09:19:33 +02:00
|
|
|
|
catch(Exception ex)
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return Result.FromError(ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
public static async Task<FileInfo?> GetOrDownloadFileAsync(string fileName, string targetLink, IProgress<double> progress, string expectedHash = null)
|
|
|
|
|
{
|
2023-07-30 16:15:52 -04:00
|
|
|
|
var cacheFile = new FileInfo(Path.Join(CachePath, fileName));
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var result = await ProcessInboundFileAsync(cacheFile, targetLink, progress, expectedHash);
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
return result.Succeeded ? cacheFile : null;
|
|
|
|
|
}
|
|
|
|
|
catch(Exception ex)
|
2023-03-04 15:33:37 -05:00
|
|
|
|
{
|
2023-07-12 09:19:33 +02:00
|
|
|
|
Log.Error(ex, $"Error while getting file: {fileName}");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
public static async Task<FileInfo?> GetOrDownloadFileAsync(string fileName, Stream fileDownloadStream, string expectedHash = null)
|
|
|
|
|
{
|
2023-07-30 16:15:52 -04:00
|
|
|
|
var cacheFile = new FileInfo(Path.Join(CachePath, fileName));
|
2023-03-04 15:33:37 -05:00
|
|
|
|
|
2023-07-12 09:19:33 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var result = await ProcessInboundStreamAsync(cacheFile, fileDownloadStream, expectedHash);
|
|
|
|
|
|
|
|
|
|
return result.Succeeded ? cacheFile : null;
|
|
|
|
|
}
|
|
|
|
|
catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error(ex, $"Error while getting file: {fileName}");
|
|
|
|
|
return null;
|
2023-03-04 15:33:37 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-12 09:19:33 +02:00
|
|
|
|
}
|