mlaumcherb/Mlaumcherb.Client.Avalonia/сеть/TaskFactories/LibrariesDownloadTaskFactory.cs
2024-12-27 21:11:19 +05:00

117 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.IO.Compression;
using System.Security.Cryptography;
using DTLib.Extensions;
using Mlaumcherb.Client.Avalonia.зримое;
using Mlaumcherb.Client.Avalonia.классы;
using Mlaumcherb.Client.Avalonia.холопы;
using static Mlaumcherb.Client.Avalonia.сеть.NetworkHelper;
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
public class LibrariesDownloadTaskFactory : INetworkTaskFactory
{
private GameVersionDescriptor _descriptor;
private Libraries _libraries;
private SHA1 _hasher;
private List<Libraries.JarLib> _libsToDownload = new();
private IOPath _nativesDir;
public LibrariesDownloadTaskFactory(GameVersionDescriptor descriptor, Libraries libraries)
{
_descriptor = descriptor;
_libraries = libraries;
_hasher = SHA1.Create();
_nativesDir = PathHelper.GetNativeLibrariesDir(descriptor.id);
}
public Task<NetworkTask?> CreateAsync(bool checkHashes)
{
NetworkTask? networkTask = null;
if (!CheckFiles(checkHashes))
networkTask = new NetworkTask(
$"libraries '{_descriptor.id}'",
GetTotalSize(),
Download
);
return Task.FromResult(networkTask);
}
private bool CheckFiles(bool checkHashes)
{
_libsToDownload.Clear();
bool nativeDirExists = Directory.Exists(_nativesDir);
foreach (var l in _libraries.Libs)
{
// Forge installer downloads some libraries manually.
// Such libraries have empty url in descriptor.
if(l.jarFilePath is null)
{
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"library artifact has empty url: '{l.name}'");
continue;
}
if (!File.Exists(l.jarFilePath.Value))
{
_libsToDownload.Add(l);
}
else if (!nativeDirExists && l is Libraries.NativeLib)
{
_libsToDownload.Add(l);
}
else if (checkHashes)
{
using var fs = File.OpenRead(l.jarFilePath.Value);
string hash = _hasher.ComputeHash(fs).HashToString();
if(hash != l.artifact.sha1)
_libsToDownload.Add(l);
}
}
return _libsToDownload.Count == 0;
}
private long GetTotalSize()
{
long total = 0;
foreach (var l in _libsToDownload)
total += l.artifact.size;
return total;
}
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
{
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading libraries '{_descriptor.id}'");
ParallelOptions opt = new()
{
MaxDegreeOfParallelism = LauncherApp.Config.max_parallel_downloads,
CancellationToken = ct
};
await Parallel.ForEachAsync(_libsToDownload, opt, async (l, _ct) =>
{
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading library '{l.name}' to '{l.jarFilePath}'");
if(l.jarFilePath is null)
throw new Exception("jarFilePath is null");
await DownloadFile(l.artifact.url, l.jarFilePath.Value, _ct, pr.AddBytesCount);
if (l is Libraries.NativeLib n)
{
var zipf = File.OpenRead(n.jarFilePath!.Value);
ZipFile.ExtractToDirectory(zipf, _nativesDir.ToString(), true);
if (n.extractionOptions?.exclude != null)
{
foreach (var excluded in n.extractionOptions.exclude)
{
IOPath path = Path.Concat(_nativesDir, excluded);
if(Directory.Exists(path))
Directory.Delete(path);
if(File.Exists(path))
File.Delete(path);
}
}
}
});
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading libraries '{_descriptor.id}'");
}
}