123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.IO.Compression;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Net.Http.Handlers;
- using System.Text.Json;
- using System.Threading;
- using System.Threading.Tasks;
- using VeloeMinecraftLauncher.Entity.Assets;
- using VeloeMinecraftLauncher.Utils.Starter;
- namespace VeloeMinecraftLauncher.Utils.Downloader;
- internal class Downloader
- {
- static HttpClient _sHttpClient = new();
- public DownloaderParameters Parameters { get; private set; }
- private readonly Serilog.ILogger _logger;
- public Downloader(DownloaderParameters parameters, Serilog.ILogger logger)
- {
- Parameters = parameters;
- _logger = logger;
- }
- public async Task DownloadClient(
- CancellationToken cancellationToken = default)
- {
- try
- {
- //task 1 - download java
- //task 2 - download jar
- //task 3 - download libs
- //task 4 - download assets
- //task 5 - download addons
- //task 6 - download modpacks
- Parameters.Action.IsControlsEnabled(false);
- Parameters.Action.SetProgress(0);
- var tasksCount = 3;
- var tasksIterator = 0;
- if (Parameters.Parameter.DownloadJava) tasksCount++;
- if (Parameters.Parameter.InstallForge || Parameters.Parameter.InstallOptifine || Parameters.Parameter.InstallForgeOptifine || Parameters.Parameter.InstallFabric) tasksCount++;
- if (Parameters.Data.SelectedModpack is not null) tasksCount++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- var handler = new HttpClientHandler() { AllowAutoRedirect = true };
- var ph = new ProgressMessageHandler(handler);
- ph.HttpSendProgress += (_, args) =>
- {
- Parameters.Action.SetProgress(args.ProgressPercentage);
- };
- ph.HttpReceiveProgress += (_, args) =>
- {
- Parameters.Action.SetProgress(args.ProgressPercentage);
- };
- using var httpClient = new HttpClient(ph);
- //downloading json
- Entity.Version.Version? versionJson = Parameters.Data.VersionJson ?? await GetVersionJson();
- ArgumentNullException.ThrowIfNull(versionJson);
- //SetMaxProgressBarValue(size);
- _logger.Debug("Downloading minecraft {0}", versionJson.Id);
- //download java
- if (Parameters.Parameter.DownloadJava)
- {
- try
- {
- await DownloadJava(httpClient, versionJson, cancellationToken);
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- }
- catch (Exception ex) when (ex is ArgumentException or HttpRequestException)
- {
- _logger.Warning(ex.Message);
- }
- }
- await DownloadMainJar(httpClient, versionJson, cancellationToken);
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- //end download jar
- //download libraries
- await DownloadLibraries(httpClient, versionJson, cancellationToken);
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- await DownloadAssets(versionJson, cancellationToken);
- Parameters.Action.SetProgress(100);
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- if (Parameters.Parameter.InstallForge)
- {
- await DownloadForge(httpClient, versionJson, cancellationToken);
- }
- if (Parameters.Parameter.InstallOptifine)
- {
- await DownloadOptifine(httpClient, versionJson, cancellationToken);
- }
- if (Parameters.Parameter.InstallForgeOptifine)
- {
- await DownloadForgeOptifine(httpClient, versionJson, cancellationToken);
- }
- if (Parameters.Parameter.InstallForge || Parameters.Parameter.InstallOptifine || Parameters.Parameter.InstallForgeOptifine || Parameters.Parameter.InstallFabric)
- {
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- }
- if (Parameters.Data.SelectedModpack is not null)
- {
- await DownloadModpack(httpClient, cancellationToken);
- tasksIterator++;
- Parameters.Action.TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
- }
- //RemoveProgressBar(webClient);
- //Progress = 100;
- _logger.Debug("Downloading finished.");
- Parameters.Action.DownloadingFileName("Finished!");
- Parameters.Action.IsControlsEnabled(true);
- //webClient.Dispose();
- }
- catch (TaskCanceledException ex)
- {
- Parameters.Action.IsControlsEnabled(true);
- if (Parameters.Data.SelectedModpack is not null)
- Parameters.Action.DownloadingFileName($"Downloading {Parameters.Data.SelectedModpack.Name} canceled.");
- else if (Parameters.Data.SelectedVersion is not null)
- Parameters.Action.DownloadingFileName($"Downloading {Parameters.Data.SelectedVersion.Id} canceled.");
- else
- Parameters.Action.DownloadingFileName("Downloading canceled: version config is null!");
- _logger.Warning(ex.Message);
- return;// Task.FromCanceled(cancellationToken);
- }
- catch (Exception ex)
- {
- Parameters.Action.IsControlsEnabled(true);
- if (Parameters.Data.SelectedModpack is not null)
- Parameters.Action.DownloadingFileName($"Error occured while downloading {Parameters.Data.SelectedModpack.Name}.");
- else if (Parameters.Data.SelectedVersion is not null)
- Parameters.Action.DownloadingFileName($"Error occured while downloading {Parameters.Data.SelectedVersion.Id}.");
- else
- Parameters.Action.DownloadingFileName($"Error occured while downloading: version config is null!");
- _logger.Error(ex.Message);
- if (ex.StackTrace is not null)
- _logger.Error(ex.StackTrace);
- return;// Task.FromException(ex);
- }
- return;
- }
- private async Task DownloadModpack(HttpClient httpClient, CancellationToken cancellationToken)
- {
- ArgumentNullException.ThrowIfNull(Parameters.Data.SelectedModpack);
- string modpackUrl = string.Empty;
- if (!string.IsNullOrWhiteSpace(Parameters.Data.SelectedModpack.Url))
- modpackUrl = Parameters.Data.SelectedModpack.Url;
- else
- modpackUrl = $"https://files.veloe.link/launcher/modpacks/{Parameters.Data.SelectedModpack.Name}.zip";
- if (!Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}"))
- {
- _logger.Debug("Creating path: {0}", $"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}");
- Directory.CreateDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}");
- }
- _logger.Debug("Downloading: {0}", $"{Parameters.Data.SelectedModpack.Name}.zip");
- Parameters.Action.DownloadingFileName($"{Parameters.Data.SelectedModpack.Name}.zip");
- await DownloadFileAsync(modpackUrl, SettingsService.Instance.MinecraftForlderPath + $"versions/{Parameters.Data.SelectedModpack.Name}.zip", cancellationToken, httpClient);
- FileStream? stream = null;
- if (Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/mods"))
- {
- foreach (var file in Directory.GetFiles($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/mods"))
- {
- try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
- finally { stream?.Close(); }
- }
- }
- if (Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/config"))
- foreach (var file in Directory.GetFiles($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/mods"))
- {
- try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
- finally { stream?.Close(); }
- }
- stream?.Dispose();
- if (Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/mods"))
- Directory.Delete($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/mods", true);
- if (Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/config"))
- Directory.Delete($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/config", true);
- _logger.Debug("Extracting: {0}", $"{Parameters.Data.SelectedModpack.Name}.zip");
- Parameters.Action.DownloadingFileName($"Unpacking {Parameters.Data.SelectedModpack.Name}.zip");
- ZipFile.ExtractToDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}.zip", SettingsService.Instance.MinecraftForlderPath + $"versions/{Parameters.Data.SelectedModpack.Name}", true);
- File.Delete($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}.zip");
- File.WriteAllText($"{SettingsService.Instance.MinecraftForlderPath}versions/{Parameters.Data.SelectedModpack.Name}/revision.json", JsonSerializer.Serialize(Parameters.Data.SelectedModpack.Revision));
- }
- private async Task DownloadForgeOptifine(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- if (!Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/Forge{versionJson.Id}/mods"))
- {
- _logger.Debug("Creating path: {0}", $"{SettingsService.Instance.MinecraftForlderPath}versions/Forge" + versionJson.Id + "/mods");
- Directory.CreateDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/Forge" + versionJson.Id + "/mods");
- }
- _logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
- Parameters.Action.DownloadingFileName($"Optifine{versionJson.Id}.jar");
- await DownloadFileAsync($@"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/Optifine{versionJson.Id}.jar", SettingsService.Instance.MinecraftForlderPath + "versions/Forge" + versionJson.Id + "/mods/" + "Optifine" + versionJson.Id + ".jar", cancellationToken, httpClient);
- }
- private async Task DownloadOptifine(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- var optifinePath = $"Optifine{versionJson.Id}";
- var optifineUrl = $"https://files.veloe.link/launcher/optifine/Optifine{versionJson.Id}/";
- if (!Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/{optifinePath}"))
- {
- _logger.Debug("Creating path: {0}", $"{SettingsService.Instance.MinecraftForlderPath}versions/" + optifinePath);
- Directory.CreateDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/" + optifinePath);
- }
- _logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.json");
- Parameters.Action.DownloadingFileName($"Optifine{versionJson.Id}.json");
- await DownloadFileAsync($"{optifineUrl}Optifine{versionJson.Id}.json", SettingsService.Instance.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json", cancellationToken, httpClient);
- _logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
- Parameters.Action.DownloadingFileName($"Optifine{versionJson.Id}.json");
- await DownloadFileAsync($"{optifineUrl}Optifine{versionJson.Id}.jar", SettingsService.Instance.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar", cancellationToken, httpClient);
- _logger.Debug("Downloading: {0}", "libraries.zip");
- Parameters.Action.DownloadingFileName("libraries.zip");
- await DownloadFileAsync(optifineUrl + "libraries.zip", SettingsService.Instance.MinecraftForlderPath + "versions/" + optifinePath + "/libraries.zip", cancellationToken, httpClient);
- _logger.Debug("Extracting: {0}", "libraries.zip");
- Parameters.Action.DownloadingFileName("Unpacking libraries.zip");
- ZipFile.ExtractToDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/Optifine{versionJson.Id}/libraries.zip", SettingsService.Instance.MinecraftForlderPath, true);
- File.Delete($"{SettingsService.Instance.MinecraftForlderPath}versions/Optifine{versionJson.Id}/libraries.zip");
- }
- private async Task DownloadForge(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- var forgePath = $"Forge{versionJson.Id}";
- var forgeUrl = $"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/";
- if (!Directory.Exists($"{SettingsService.Instance.MinecraftForlderPath}versions/Forge{versionJson.Id}"))
- {
- _logger.Debug("Creating path: {0}", $"{SettingsService.Instance.MinecraftForlderPath}versions/" + forgePath);
- Directory.CreateDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/" + forgePath);
- }
- _logger.Debug("Downloading: {0}", $"Forge{versionJson.Id}.json");
- Parameters.Action.DownloadingFileName($"Forge{versionJson.Id}.json");
- await DownloadFileAsync($"{forgeUrl}Forge{versionJson.Id}.json", SettingsService.Instance.MinecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json", cancellationToken, httpClient);
- _logger.Debug("Downloading: {0}", "libraries.zip");
- Parameters.Action.DownloadingFileName("libraries.zip");
- await DownloadFileAsync(forgeUrl + "libraries.zip", SettingsService.Instance.MinecraftForlderPath + "versions/" + forgePath + "/libraries.zip", cancellationToken, httpClient);
- _logger.Debug("Extracting: {0}", "libraries.zip");
- Parameters.Action.DownloadingFileName("Unpacking libraries.zip");
- ZipFile.ExtractToDirectory($"{SettingsService.Instance.MinecraftForlderPath}versions/Forge{versionJson.Id}/libraries.zip", SettingsService.Instance.MinecraftForlderPath, true);
- File.Delete($"{SettingsService.Instance.MinecraftForlderPath}versions/Forge{versionJson.Id}/libraries.zip");
- }
- private async Task DownloadAssets(Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- using var httpClient = new HttpClient();
- var assetsJson = await DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.AssetIndex.Url);
- var assetsPath = $"{SettingsService.Instance.MinecraftForlderPath}{(versionJson.Assets == "pre-1.6" ? "resources" : $"assets/{versionJson.Assets}/objects")}";
- var assetsUrl = "https://resources.download.minecraft.net/";
- //download assets json
- _logger.Debug("Downloading: {0}", versionJson.Assets + ".json");
- if (!Directory.Exists(SettingsService.Instance.MinecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/"))
- Directory.CreateDirectory(SettingsService.Instance.MinecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/");
- await DownloadFileAsync(versionJson.AssetIndex.Url, SettingsService.Instance.MinecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/" + versionJson.Assets + ".json", cancellationToken);
- _logger.Debug("Downloading assets.");
- Parameters.Action.SetProgress(0);
- var assetsCount = assetsJson?.Objects?.Count ?? 1;
- var assetsIterator = 1;
- List<Task> assetsDownloadTasks = new(assetsJson?.Objects?.Count ?? 1024);
- using SemaphoreSlim concurrencySemaphore = new(40, 40);
- foreach (var asset in assetsJson?.Objects?.DistinctBy(a => a.Value.Hash) ?? new Dictionary<string, Asset>())
- {
- assetsDownloadTasks.Add(Task.Run(async () =>
- {
- var isPreVersion = versionJson.Assets == "pre-1.6";
- var folder = isPreVersion ?
- Path.GetDirectoryName(asset.Key) :
- asset.Value.Hash[..2];
- var name = isPreVersion ?
- Path.GetFileName(asset.Key) :
- asset.Value.Hash;
- var assetRoot = folder.Contains("icons") ? $"{SettingsService.Instance.MinecraftForlderPath}assets/{versionJson.Assets}" : assetsPath;
- var chksum = string.Empty;
- //here hash check
- if (File.Exists(Path.Combine(assetRoot, folder, name)))
- {
- Parameters.Action.DownloadingFileName($"Checking hash {assetsIterator} of {assetsCount}");
- using FileStream fop = File.OpenRead(Path.Combine(assetRoot, folder, name));
- byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
- chksum = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
- fop.Close();
- }
- if (chksum != (isPreVersion ? asset.Value.Hash : name))
- {
- await concurrencySemaphore.WaitAsync(cancellationToken);
- try
- {
- if (!Directory.Exists(assetRoot + "/" + folder))
- Directory.CreateDirectory(assetRoot + "/" + folder);
- _logger.Debug("Downloading asset: {0} ", name);
- //DownloadingFileName($"Asset {assetsIterator} of {assetsCount}");
- Parameters.Action.DownloadingFileName($"Asset {assetsIterator} of {assetsCount}");
- await DownloadFileAsync(assetsUrl + asset.Value.Hash[..2] + "/" + asset.Value.Hash, Path.Combine(assetRoot, folder, name), cancellationToken, httpClient);
- }
- finally
- {
- concurrencySemaphore.Release();
- }
- }
- Parameters.Action.SetProgress(assetsIterator * 100 / assetsCount);
- Interlocked.Increment(ref assetsIterator);
- }));
- }
- Task.WaitAll(assetsDownloadTasks.ToArray());
- }
- private async Task DownloadLibraries(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- _logger.Debug("Downloading libraries.");
- foreach (var library in versionJson.Libraries)
- {
- var libPath = SettingsService.Instance.MinecraftForlderPath + "libraries/";
- string libUrl = string.Empty;
- string sha1 = string.Empty;
- // getting path and url if universal lib
- if (library.Natives is null)
- {
- libPath += library.Downloads.Artifact.Path;
- libUrl = library.Downloads.Artifact.Url;
- sha1 = library.Downloads.Artifact.Sha1;
- }
- else
- { // getting path if native
- libUrl = "";
- if (library.Downloads.Classifiers is not null)
- {
- if (OperatingSystem.IsWindows() && library.Natives.Windows is not null)
- {
- if (library.Downloads.Classifiers.NativesWindows is not null)
- {
- libPath += library.Downloads.Classifiers.NativesWindows.Path;
- libUrl = library.Downloads.Classifiers.NativesWindows.Url;
- sha1 = library.Downloads.Classifiers.NativesWindows.Sha1;
- }
- else
- {
- if (Environment.Is64BitOperatingSystem && library.Downloads.Classifiers.NativesWindows64 is not null)
- {
- libPath += library.Downloads.Classifiers.NativesWindows64.Path;
- libUrl = library.Downloads.Classifiers.NativesWindows64.Url;
- sha1 = library.Downloads.Classifiers.NativesWindows64.Sha1;
- }
- else if (library.Downloads.Classifiers.NativesWindows32 is not null)
- {
- libPath += library.Downloads.Classifiers.NativesWindows32.Path;
- libUrl = library.Downloads.Classifiers.NativesWindows32.Url;
- sha1 = library.Downloads.Classifiers.NativesWindows32.Sha1;
- }
- }
- }
- if (OperatingSystem.IsLinux() && library.Natives.Linux is not null && library.Downloads.Classifiers.NativesLinux is not null)
- {
- libPath += library.Downloads.Classifiers.NativesLinux.Path;
- libUrl = library.Downloads.Classifiers.NativesLinux.Url;
- sha1 = library.Downloads.Classifiers.NativesLinux.Url;
- }
- }
- }
- //if no lib url
- if (libUrl == string.Empty)
- continue;
- var libName = Path.GetFileName(libPath);
- var libDir = Path.GetDirectoryName(libPath);
- if (libName is null || libDir is null)
- {
- if (libPath == string.Empty)
- _logger.Warning("Library dir, name are null, because libraryPath is empty! Skipping...");
- else
- _logger.Warning("Library dir or name are null! Skipping...");
- continue;
- }
- //checking rules
- if (library.Rules == null)
- {
- if (!Directory.Exists(libDir))
- {
- _logger.Debug("Creating path: {0}", libDir);
- Directory.CreateDirectory(libDir);
- }
- var chksum = string.Empty;
- if (File.Exists(libPath))
- {
- Parameters.Action.DownloadingFileName($"Checking hash: {libName}");
- FileStream fop = File.OpenRead(libPath);
- byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
- chksum = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
- fop.Close();
- fop.Dispose();
- }
- if (chksum != sha1)
- {
- _logger.Debug("Downloading: {0}", libName);
- Parameters.Action.DownloadingFileName(libName);
- await DownloadFileAsync(libUrl, libDir + "/" + libName, cancellationToken, httpClient);
- }
- }
- else
- {
- foreach (var rule in library.Rules)
- {
- if (rule.Action == "allow") // && rule.os is null
- {
- if (!Directory.Exists(libDir))
- {
- _logger.Debug("Creating path: {0}", libDir);
- Directory.CreateDirectory(libDir);
- }
- var chksum = string.Empty;
- if (File.Exists(libDir + "/" + libName) && sha1 != string.Empty)
- {
- Parameters.Action.DownloadingFileName($"Checking hash: {libName}");
- FileStream fop = File.OpenRead(libDir + "/" + libName);
- byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
- chksum = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
- fop.Close();
- fop.Dispose();
- }
- if (chksum != sha1)
- {
- _logger.Debug("Downloading: {0}", libName);
- Parameters.Action.DownloadingFileName(libName);
- await DownloadFileAsync(libUrl, libDir + "/" + libName, cancellationToken, httpClient);
- }
- continue;
- }
- //fabic on start needs all libraries for all os, so os check removed
- /*
- if (rule.action == "allow" && (rule.os.name == "windows" || rule.os.name == "linux" || rule.os.name == "osx" ))
- {
- if (!Directory.Exists(libPath))
- {
- _logger.Debug("Creating path: {0}", path);
- Directory.CreateDirectory(libPath);
- }
- _logger.Debug("Downloading: {0}", libName);
- DownloadingFileName = libName;
- webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libName);
- }
- */
- }
- }
- //unpacking native libs
- if ((library.Natives is not null || library.Downloads.Classifiers is not null) && File.Exists(libPath)/*&& chksum != sha1*/)
- {
- try
- {
- if (!(library.Downloads.Classifiers is not null && (
- library.Downloads.Classifiers.NativesWindows is not null ||
- library.Downloads.Classifiers.NativesWindows64 is not null ||
- library.Downloads.Classifiers.NativesWindows32 is not null && OperatingSystem.IsWindows() ||
- library.Downloads.Classifiers.NativesLinux is not null && OperatingSystem.IsLinux())))
- continue;
- if (!Directory.Exists(SettingsService.Instance.MinecraftForlderPath + "versions/" + versionJson.Id + "/natives/"))
- {
- _logger.Debug("Creating path: {0}", SettingsService.Instance.MinecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
- Directory.CreateDirectory(SettingsService.Instance.MinecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
- }
- _logger.Debug("Extracting {0} to {1}", libName, SettingsService.Instance.MinecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
- ZipFile.ExtractToDirectory(libDir + "/" + libName, SettingsService.Instance.MinecraftForlderPath + "versions/" + versionJson.Id + "/natives/", true);
- }
- catch (IOException)
- {
- _logger.Error("IOException on native lib extraction");
- }
- //TODO delete META-INF and sha1 files after
- }
- }
- }
- private async Task DownloadMainJar(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- //download json
- var path = SettingsService.Instance.MinecraftForlderPath + "/versions/" + versionJson.Id;
- //download jar
- if (!Directory.Exists(path))
- {
- _logger.Debug("Creating path: {0}", path);
- Directory.CreateDirectory(path);
- }
- string chksum = string.Empty;
- //here hash check
- if (File.Exists(path + "/" + versionJson.Id + ".jar"))
- {
- Parameters.Action.DownloadingFileName($"Checking hash: {versionJson.Id}.jar");
- FileStream fop = File.OpenRead(path + "/" + versionJson.Id + ".jar");
- byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
- chksum = BitConverter.ToString(hash).Replace("-", string.Empty).ToLower();
- fop.Close();
- fop.Dispose();
- }
- if (chksum != versionJson.Downloads.Client.Sha1)
- {
- _logger.Debug("Downloading {0}", $"{versionJson.Id}.jar");
- Parameters.Action.DownloadingFileName($"{versionJson.Id}.jar");
- await DownloadFileAsync(versionJson.Downloads.Client.Url, path + "/" + versionJson.Id + ".jar", cancellationToken, httpClient);
- }
- }
- private async Task DownloadJava(HttpClient httpClient, Entity.Version.Version versionJson, CancellationToken cancellationToken)
- {
- _logger.Debug("Getting required Java version.");
- var javaVersion = versionJson.JavaVersion?.MajorVersion ??
- (versionJson.Assets == "legacy" ? 8 :
- throw new ArgumentException("Required Java version was not found in json file."));
- var javaUrl = $"https://files.veloe.link/launcher/java/{javaVersion}/{(OperatingSystem.IsWindows() ? "windows" : "linux")}{(Environment.Is64BitOperatingSystem ? "64" : "32")}/java.zip";
- if (await IsFileAvaliable(javaUrl, cancellationToken))
- {
- _logger.Debug("Downloading Java");
- Parameters.Action.DownloadingFileName("java.zip");
- await DownloadFileAsync(javaUrl, SettingsService.Instance.MinecraftForlderPath + "java.zip", cancellationToken, httpClient);
- _logger.Debug("Unpacking Java");
- Parameters.Action.DownloadingFileName("Unpacking java.zip");
- ZipFile.ExtractToDirectory($"{SettingsService.Instance.MinecraftForlderPath}java.zip", SettingsService.Instance.MinecraftForlderPath, true);
- File.Delete($"{SettingsService.Instance.MinecraftForlderPath}java.zip");
- }
- else
- throw new HttpRequestException("Required Java version was not found on server.");
- }
- private async Task<Entity.Version.Version?> GetVersionJson()
- {
- ArgumentNullException.ThrowIfNull(Parameters.Data.SelectedVersion);
-
- if (Parameters.Data.SelectedModpack is not null)
- {
- ArgumentNullException.ThrowIfNull(Parameters.Data.SelectedModpack);
- if (Parameters.Data.SelectedVersion.Id != Parameters.Data.SelectedModpack.Version)
- throw new ArgumentException("Selected version id not equal selected modpack version!");
- Parameters.Parameter.InstallForge = Parameters.Data.SelectedModpack.Forge;
- Parameters.Parameter.InstallForgeOptifine = Parameters.Data.SelectedModpack.ForgeOptifine;
- Parameters.Parameter.InstallOptifine = Parameters.Data.SelectedModpack.Optifine;
- Parameters.Parameter.InstallFabric = Parameters.Data.SelectedModpack.Fabric;
- _logger.Debug("Downloading {0}.json", Parameters.Data.SelectedVersion.Id);
- Parameters.Action.DownloadingFileName($"{Parameters.Data.SelectedVersion.Id}.json");
- return await DownloadAndDeserializeJsonData<Entity.Version.Version>(Parameters.Data.SelectedVersion.Url, SettingsService.Instance.MinecraftForlderPath + "versions/" + Parameters.Data.SelectedVersion.Id + "/", Parameters.Data.SelectedVersion.Id + ".json");
- }
- else
- {
- Parameters.Action.DownloadingFileName($"{Parameters.Data.SelectedVersion.Id}.json");
- _logger.Debug("Downloading {0}.json", Parameters.Data.SelectedVersion.Id);
- return await DownloadAndDeserializeJsonData<Entity.Version.Version>(Parameters.Data.SelectedVersion.Url, SettingsService.Instance.MinecraftForlderPath + "versions/" + Parameters.Data.SelectedVersion.Id + "/", Parameters.Data.SelectedVersion.Id + ".json");
- }
- }
- public static async Task<T?> DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "", Serilog.ILogger? logger = null) where T : new()
- {
- string jsonData;
- if (logger is null) logger = SettingsService.logger;
- try
- {
- logger.Debug($"Downloading: {url.Split('/').Last()}");
- jsonData = await _sHttpClient.GetStringAsync(url);
- }
- catch (Exception ex)
- {
- throw new WebException($"An error occured while downloading {url}. Check your internet connection.", ex);
- }
- if (string.IsNullOrEmpty(jsonData))
- {
- logger.Warning("Empty string!");
- return new T();
- }
- else
- {
- if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(path))
- {
- if (!Directory.Exists(path))
- {
- logger.Debug("Creating path: {0}", path);
- Directory.CreateDirectory(path);
- }
- File.WriteAllText(path + filename, jsonData);
- }
- //_logger.Debug("Return serialized string.");
- return JsonSerializer.Deserialize<T>(jsonData, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
- }
- }
- public static async Task DownloadFileAsync(string url, string path, CancellationToken ct, HttpClient? client = null)
- {
- client ??= _sHttpClient;
- using HttpResponseMessage response = await client.GetAsync(new Uri(url), HttpCompletionOption.ResponseHeadersRead, ct);
- response.EnsureSuccessStatusCode();
- using Stream contentStream = await response.Content.ReadAsStreamAsync(ct);
- using FileStream fileStream = File.OpenWrite(path);
- await contentStream.CopyToAsync(fileStream, ct);
- }
- public static async Task<bool> IsFileAvaliable(string url, CancellationToken ct)
- {
- using HttpResponseMessage response = await _sHttpClient.GetAsync(new Uri(url), HttpCompletionOption.ResponseHeadersRead, ct);
- return response.IsSuccessStatusCode;
- }
- public async Task DownloadFabricLibraries(CancellationToken ct)
- {
- var handler = new HttpClientHandler() { AllowAutoRedirect = true };
- var ph = new ProgressMessageHandler(handler);
- ph.HttpSendProgress += (_, args) =>
- {
- Parameters.Action.SetProgress(args.ProgressPercentage);
- };
- ph.HttpReceiveProgress += (_, args) =>
- {
- Parameters.Action.SetProgress(args.ProgressPercentage);
- };
- using var httpClient = new HttpClient(ph);
- ArgumentNullException.ThrowIfNull(Parameters.Data.VersionJson);
- foreach (var library in Parameters.Data.VersionJson.Libraries)
- {
- if (string.IsNullOrEmpty(library.Name) || string.IsNullOrEmpty(library.Url))
- continue;
- var relativePath = StartCommandBuilder.GetLibRelativePathFromName(library.Name);
- var libPath = SettingsService.Instance.MinecraftForlderPath + "libraries/" + relativePath;
- var dirPath = Path.GetDirectoryName(libPath);
- ArgumentNullException.ThrowIfNullOrEmpty(dirPath);
- if (!Directory.Exists(dirPath))
- {
- Directory.CreateDirectory(dirPath);
- }
- // some links may be unawailable
- if (await IsFileAvaliable($"{library.Url}{relativePath}", ct))
- await DownloadFileAsync($"{library.Url}{relativePath}", libPath, ct, httpClient);
- else
- _logger.Warning($"Library {library.Name} url is not accessible. Skipping...");
- }
- }
- }
|