NetworkTaskFactory

This commit is contained in:
2024-09-29 08:21:48 +05:00
parent 45c3f90da0
commit 4704f1217a
24 changed files with 817 additions and 287 deletions

View File

@@ -0,0 +1,112 @@
using System.Security.Cryptography;
using DTLib.Extensions;
using Млаумчерб.Клиент.видимое;
using Млаумчерб.Клиент.классы;
using static Млаумчерб.Клиент.сеть.Сеть;
namespace Млаумчерб.Клиент.сеть.NetworkTaskFactories;
public class AssetsDownloadTaskFactory : INetworkTaskFactory
{
private const string ASSET_SERVER_URL = "https://resources.download.minecraft.net/";
private VersionDescriptor _descriptor;
private SHA1 _hasher;
private IOPath _indexFilePath;
List<AssetDownloadProperties> _assetsToDownload = new();
public AssetsDownloadTaskFactory(VersionDescriptor descriptor)
{
_descriptor = descriptor;
_hasher = SHA1.Create();
_indexFilePath = Пути.GetAssetIndexFilePath(_descriptor.assetIndex.id);
}
public async Task<NetworkTask?> CreateAsync(bool checkHashes)
{
if (!await CheckFilesAsync(checkHashes))
return new NetworkTask(
$"assets '{_descriptor.assetIndex.id}'",
GetTotalSize(),
Download
);
return null;
}
private async Task<bool> CheckFilesAsync(bool checkHashes)
{
if(!File.Exists(_indexFilePath))
{
Приложение.Логгер.LogInfo(nameof(Сеть), $"started downloading asset index to '{_indexFilePath}'");
await DownloadFileHTTP(_descriptor.assetIndex.url, _indexFilePath);
Приложение.Логгер.LogInfo(nameof(Сеть), "finished downloading asset index");
}
string indexFileText = File.ReadAllText(_indexFilePath);
var assetIndex = JsonConvert.DeserializeObject<AssetIndex>(indexFileText)
?? throw new Exception($"can't deserialize asset index file '{_indexFilePath}'");
_assetsToDownload.Clear();
// removing duplicates for Dictionary (idk how can it be possible, but Newtonsoft.Json creates them)
HashSet<string> assetHashes = new HashSet<string>();
foreach (var pair in assetIndex.objects)
{
if (assetHashes.Add(pair.Value.hash))
{
var a = new AssetDownloadProperties(pair.Key, pair.Value);
if (!File.Exists(a.filePath))
{
_assetsToDownload.Add(a);
}
else if(checkHashes)
{
await using var fs = File.OpenRead(a.filePath);
string hash = _hasher.ComputeHash(fs).HashToString();
if (hash != a.hash)
_assetsToDownload.Add(a);
}
}
}
return _assetsToDownload.Count == 0;
}
private long GetTotalSize()
{
long totalSize = 0;
foreach (var a in _assetsToDownload)
totalSize += a.size;
return totalSize;
}
private class AssetDownloadProperties
{
public string name;
public string hash;
public long size;
public string url;
public IOPath filePath;
public AssetDownloadProperties(string key, AssetProperties p)
{
name = key;
hash = p.hash;
size = p.size;
string hashStart = hash.Substring(0, 2);
url = $"{ASSET_SERVER_URL}/{hashStart}/{hash}";
filePath = Path.Concat(IOPath.ArrayCast(["assets", "objects", hashStart, hash], true));
}
}
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
{
Приложение.Логгер.LogInfo(nameof(Сеть), "started downloading assets");
ParallelOptions opt = new() { MaxDegreeOfParallelism = ParallelDownloadsN, CancellationToken = ct };
await Parallel.ForEachAsync(_assetsToDownload, opt,
async (a, _ct) =>
{
Приложение.Логгер.LogDebug(nameof(Сеть), $"downloading asset '{a.name}' {a.hash}");
await DownloadFileHTTP(a.url, a.filePath, _ct, pr.AddBytesCount);
});
Приложение.Логгер.LogInfo(nameof(Сеть), "finished downloading assets");
}
}

View File

@@ -0,0 +1,7 @@
namespace Млаумчерб.Клиент.сеть.NetworkTaskFactories;
public interface INetworkTaskFactory
{
/// <returns>unstarted network task or null if there is nothing to download</returns>
Task<NetworkTask?> CreateAsync(bool checkHashes);
}

View File

@@ -0,0 +1,46 @@
using System.Security.Cryptography;
using Млаумчерб.Клиент.классы;
using static Млаумчерб.Клиент.сеть.Сеть;
namespace Млаумчерб.Клиент.сеть.NetworkTaskFactories;
public class JavaDownloadTaskFactory : INetworkTaskFactory
{
private VersionDescriptor _descriptor;
private SHA1 _hasher;
IOPath _javaVersionDir;
public JavaDownloadTaskFactory(VersionDescriptor descriptor)
{
_descriptor = descriptor;
_hasher = SHA1.Create();
_javaVersionDir = Пути.GetJavaRuntimeDir(_descriptor.javaVersion.component);
}
public Task<NetworkTask?> CreateAsync(bool checkHashes)
{
NetworkTask? networkTask = null;
if (!CheckFiles(checkHashes))
networkTask = new(
$"java runtime '{_descriptor.javaVersion.component}'",
GetTotalSize(),
Download
);
return Task.FromResult(networkTask);
}
private bool CheckFiles(bool checkHashes)
{
throw new NotImplementedException();
}
private long GetTotalSize()
{
throw new NotImplementedException();
}
private Task Download(NetworkProgressReporter pr, CancellationToken ct)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,78 @@
using System.Security.Cryptography;
using DTLib.Extensions;
using Млаумчерб.Клиент.видимое;
using Млаумчерб.Клиент.классы;
using static Млаумчерб.Клиент.сеть.Сеть;
namespace Млаумчерб.Клиент.сеть.NetworkTaskFactories;
public class LibrariesDownloadTaskFactory : INetworkTaskFactory
{
private VersionDescriptor _descriptor;
private Libraries _libraries;
private SHA1 _hasher;
private List<Libraries.JarLib> _libsToDownload = new();
public LibrariesDownloadTaskFactory(VersionDescriptor descriptor, Libraries libraries)
{
_descriptor = descriptor;
_libraries = libraries;
_hasher = SHA1.Create();
}
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();
foreach (var l in _libraries.Libs)
{
if (!File.Exists(l.jarFilePath))
{
_libsToDownload.Add(l);
}
else if (checkHashes)
{
using var fs = File.OpenRead(l.jarFilePath);
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)
{
Приложение.Логгер.LogInfo(nameof(Сеть), "started downloading libraries");
ParallelOptions opt = new() { MaxDegreeOfParallelism = ParallelDownloadsN, CancellationToken = ct };
await Parallel.ForEachAsync(_libsToDownload, opt, async (l, _ct) =>
{
Приложение.Логгер.LogDebug(nameof(Сеть),
$"downloading library '{l.name}' to '{l.jarFilePath}'");
await DownloadFileHTTP(l.artifact.url, l.jarFilePath, _ct, pr.AddBytesCount);
//TODO: extract natives from jar
});
Приложение.Логгер.LogInfo(nameof(Сеть), "finished downloading libraries");
}
}

View File

@@ -0,0 +1,53 @@
using System.Security.Cryptography;
using DTLib.Extensions;
using Млаумчерб.Клиент.классы;
using static Млаумчерб.Клиент.сеть.Сеть;
namespace Млаумчерб.Клиент.сеть.NetworkTaskFactories;
public class VersionFileDownloadTaskFactory : INetworkTaskFactory
{
private VersionDescriptor _descriptor;
private IOPath _filePath;
private SHA1 _hasher;
public VersionFileDownloadTaskFactory(VersionDescriptor descriptor)
{
_descriptor = descriptor;
_filePath = Пути.GetVersionJarFilePath(_descriptor.id);
_hasher = SHA1.Create();
}
public Task<NetworkTask?> CreateAsync(bool checkHashes)
{
NetworkTask? networkTask = null;
if (!CheckFiles(checkHashes))
networkTask = new NetworkTask(
$"version file '{_descriptor.id}'",
GetTotalSize(),
Download
);
return Task.FromResult(networkTask);
}
private bool CheckFiles(bool checkHashes)
{
if (!File.Exists(_filePath))
return false;
if (!checkHashes)
return true;
using var fs = File.OpenRead(_filePath);
string hash = _hasher.ComputeHash(fs).HashToString();
return hash == _descriptor.downloads.client.sha1;
}
private long GetTotalSize()
{
return _descriptor.downloads.client.size;
}
private Task Download(NetworkProgressReporter pr, CancellationToken ct)
{
return DownloadFileHTTP(_descriptor.downloads.client.url, _filePath, ct, pr.AddBytesCount);
}
}