Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File Downloader Submodule Major Refactor (Hi3Helper.Http) #563

Merged
merged 28 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3e55bcc
Moving Legacy ``Http()`` to ``DownloadClient()`` (phase 1)
neon-nyan Aug 22, 2024
ba96d7c
Change ``DownloadProgress`` as ``struct``
neon-nyan Aug 22, 2024
6843438
Moving Legacy ``Http()`` to ``DownloadClient()`` (phase 2)
neon-nyan Aug 22, 2024
e1767c0
Moving Legacy ``Http()`` to ``DownloadClient()`` (phase 3 - Hi3)
neon-nyan Aug 22, 2024
37e50a4
Use ``RunDownloadTask()`` on Star Rail Cache Update
neon-nyan Aug 22, 2024
426fdca
Fix early disposal of "Pustaka Senadina"-type file
neon-nyan Aug 22, 2024
6314afd
Always ensure the file directory existence
neon-nyan Aug 23, 2024
e22d33c
Moving Legacy ``Http()`` to ``DownloadClient()`` (phase 4)
neon-nyan Aug 24, 2024
2942aea
Moving Legacy ``Http()`` to ``DownloadClient()`` (phase 5 - GI)
neon-nyan Aug 24, 2024
5cb2cc8
Add ``long`` and ``ulong`` parser on ``IniFile``
neon-nyan Aug 24, 2024
741bd26
Update base
bagusnl Aug 25, 2024
9eac564
Update submodules
bagusnl Aug 25, 2024
29c1cc8
A lil trolling
bagusnl Aug 25, 2024
3b57b28
Adding settings for the new Hi3Helper.Http
neon-nyan Aug 25, 2024
053e1ea
Use newly ``DownloadClient`` for ``InstallManagerBase``
neon-nyan Aug 29, 2024
8e5e92d
Enforce ``IsUsePreallocatedDownloader`` on ``InstallManagerBase``
neon-nyan Aug 29, 2024
5a1f3aa
Code QA
neon-nyan Aug 29, 2024
eb1348c
Code QA (hopefully?)
neon-nyan Aug 29, 2024
f3dce7b
Update base
bagusnl Aug 30, 2024
94f9b3e
CodeQA
bagusnl Aug 30, 2024
7cfcee1
Adjust reserved thread count as a const
neon-nyan Aug 30, 2024
30f1b39
Locale Grammar Correction
neon-nyan Aug 30, 2024
9118fea
Adjust reserved thread count as a const (pt. 2)
neon-nyan Aug 30, 2024
f4fc8be
Code QA once again
neon-nyan Aug 30, 2024
2297644
Update base
neon-nyan Aug 30, 2024
193033f
Adding speed limiter to Sophon
neon-nyan Aug 31, 2024
f20a6cf
Fix progress bar determinate status set to true
neon-nyan Aug 31, 2024
e210969
Use new speed calculation for Cache Update and Game Repair
neon-nyan Aug 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 42 additions & 52 deletions CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,66 +25,56 @@ internal partial class HonkaiCache
private async Task<List<CacheAsset>> Fetch(CancellationToken token)
{
// Initialize asset index for the return
List<CacheAsset> returnAsset = new();
List<CacheAsset> returnAsset = [];

// Initialize new proxy-aware HttpClient
using HttpClient httpClientNew = new HttpClientBuilder()
.UseLauncherConfig(_downloadThreadCount + 16)
.UseLauncherConfig(_downloadThreadCount + _downloadThreadCountReserved)
.SetUserAgent(_userAgent)
.SetAllowedDecompression(DecompressionMethods.None)
.Create();

// Use HttpClient instance on fetching
using Http httpClient = new Http(true, 5, 1000, _userAgent, httpClientNew);
try
{
// Subscribe the event listener
httpClient.DownloadProgress += _httpClient_FetchAssetProgress;
// Use a new DownloadClient for fetching
DownloadClient downloadClient = DownloadClient.CreateInstance(httpClientNew);

// Build _gameRepoURL from loading Dispatcher and Gateway
await BuildGameRepoURL(token);
// Build _gameRepoURL from loading Dispatcher and Gateway
await BuildGameRepoURL(downloadClient, token);

// Iterate type and do fetch
foreach (CacheAssetType type in Enum.GetValues<CacheAssetType>())
// Iterate type and do fetch
foreach (CacheAssetType type in Enum.GetValues<CacheAssetType>())
{
// Skip for unused type
switch (type)
{
// Skip for unused type
switch (type)
{
case CacheAssetType.Unused:
case CacheAssetType.Dispatcher:
case CacheAssetType.Gateway:
case CacheAssetType.General:
case CacheAssetType.IFix:
case CacheAssetType.DesignData:
case CacheAssetType.Lua:
continue;
}
case CacheAssetType.Unused:
neon-nyan marked this conversation as resolved.
Show resolved Hide resolved
case CacheAssetType.Dispatcher:
case CacheAssetType.Gateway:
case CacheAssetType.General:
case CacheAssetType.IFix:
case CacheAssetType.DesignData:
case CacheAssetType.Lua:
continue;
}

// uint = Count of the assets available
// long = Total size of the assets available
(int, long) count = await FetchByType(type, httpClient, returnAsset, token);
// uint = Count of the assets available
// long = Total size of the assets available
(int, long) count = await FetchByType(type, downloadClient, returnAsset, token);

// Write a log about the metadata
LogWriteLine($"Cache Metadata [T: {type}]:", LogType.Default, true);
LogWriteLine($" Cache Count = {count.Item1}", LogType.NoTag, true);
LogWriteLine($" Cache Size = {SummarizeSizeSimple(count.Item2)}", LogType.NoTag, true);
// Write a log about the metadata
LogWriteLine($"Cache Metadata [T: {type}]:", LogType.Default, true);
LogWriteLine($" Cache Count = {count.Item1}", LogType.NoTag, true);
LogWriteLine($" Cache Size = {SummarizeSizeSimple(count.Item2)}", LogType.NoTag, true);

// Increment the Total Size and Count
_progressAllCountTotal += count.Item1;
_progressAllSizeTotal += count.Item2;
}
}
finally
{
// Unsubscribe the event listener and dispose Http client
httpClient.DownloadProgress -= _httpClient_FetchAssetProgress;
// Increment the Total Size and Count
_progressAllCountTotal += count.Item1;
_progressAllSizeTotal += count.Item2;
}

// Return asset index
return returnAsset;
}

private async Task BuildGameRepoURL(CancellationToken token)
private async Task BuildGameRepoURL(DownloadClient downloadClient, CancellationToken token)
{
KianaDispatch dispatch = null;
Exception lastException = null;
Expand All @@ -93,7 +83,7 @@ private async Task BuildGameRepoURL(CancellationToken token)
{
try
{
// Init the key and decrypt it if exist.
// Init the key and decrypt it if existed.
if (string.IsNullOrEmpty(_gameVersionManager.GamePreset.DispatcherKey))
{
throw new NullReferenceException("Dispatcher key is null or empty!");
Expand All @@ -102,7 +92,7 @@ private async Task BuildGameRepoURL(CancellationToken token)
string key = _gameVersionManager.GamePreset.DispatcherKey;

// Try assign dispatcher
dispatch = await KianaDispatch.GetDispatch(baseURL,
dispatch = await KianaDispatch.GetDispatch(downloadClient, baseURL,
_gameVersionManager.GamePreset.GameDispatchURLTemplate,
_gameVersionManager.GamePreset.GameDispatchChannelName,
key, _gameVersion.VersionArray, token);
Expand All @@ -120,13 +110,13 @@ private async Task BuildGameRepoURL(CancellationToken token)

// Get gatewayURl and fetch the gateway
_gameGateway =
await KianaDispatch.GetGameserver(dispatch!, _gameVersionManager.GamePreset.GameGatewayDefault!, token);
await KianaDispatch.GetGameserver(downloadClient, dispatch!, _gameVersionManager.GamePreset.GameGatewayDefault!, token);
_gameRepoURL = BuildAssetBundleURL(_gameGateway);
}

private string BuildAssetBundleURL(KianaDispatch gateway) => CombineURLFromString(gateway!.AssetBundleUrls![0], "/{0}/editor_compressed/");
private static string BuildAssetBundleURL(KianaDispatch gateway) => CombineURLFromString(gateway!.AssetBundleUrls![0], "/{0}/editor_compressed/");

private async Task<(int, long)> FetchByType(CacheAssetType type, Http httpClient, List<CacheAsset> assetIndex, CancellationToken token)
private async Task<(int, long)> FetchByType(CacheAssetType type, DownloadClient downloadClient, List<CacheAsset> assetIndex, CancellationToken token)
{
// Set total activity string as "Fetching Caches Type: <type>"
_status!.ActivityStatus = string.Format(Lang!._CachesPage!.CachesStatusFetchingType!, type);
Expand All @@ -145,9 +135,9 @@ private async Task BuildGameRepoURL(CancellationToken token)

// Get a direct HTTP Stream
await using HttpResponseInputStream remoteStream = await HttpResponseInputStream.CreateStreamAsync(
httpClient.GetHttpClient(), assetIndexURL, null, null, token);
downloadClient.GetHttpClient(), assetIndexURL, null, null, null, null, null, token);

using XORStream stream = new XORStream(remoteStream);
await using XORStream stream = new XORStream(remoteStream);

// Build the asset index and return the count and size of each type
(int, long) returnValue = await BuildAssetIndex(type, baseURL, stream, assetIndex, token);
Expand Down Expand Up @@ -263,7 +253,7 @@ private IEnumerable<CacheAsset> EnumerateCacheTextAsset(CacheAssetType type, IEn

// Initialize local HTTP client
using HttpClient client = new HttpClientBuilder()
.UseLauncherConfig(_downloadThreadCount + 16)
.UseLauncherConfig(_downloadThreadCount + _downloadThreadCountReserved)
.SetUserAgent(_userAgent)
.SetAllowedDecompression(DecompressionMethods.None)
.Create();
Expand Down Expand Up @@ -339,16 +329,16 @@ private bool IsValidRegionFile(string input, string lang)
public KianaDispatch GetCurrentGateway() => _gameGateway;

public async Task<(List<CacheAsset>, string, string, int)> GetCacheAssetList(
Http httpClient, CacheAssetType type, CancellationToken token)
DownloadClient downloadClient, CacheAssetType type, CancellationToken token)
{
// Initialize asset index for the return
List<CacheAsset> returnAsset = new();

// Build _gameRepoURL from loading Dispatcher and Gateway
await BuildGameRepoURL(token);
await BuildGameRepoURL(downloadClient, token);

// Fetch the progress
_ = await FetchByType(type, httpClient, returnAsset, token);
_ = await FetchByType(type, downloadClient, returnAsset, token);

// Return the list and base asset bundle repo URL
return (returnAsset, _gameGateway!.ExternalAssetUrls!.FirstOrDefault(), BuildAssetBundleURL(_gameGateway),
Expand Down
66 changes: 7 additions & 59 deletions CollapseLauncher/Classes/CachesManagement/Honkai/Update.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using CollapseLauncher.Helper;
using CollapseLauncher.Interfaces;
using Hi3Helper;
using Hi3Helper.Data;
using Hi3Helper.Http;
using System;
using System.Collections.Generic;
Expand All @@ -22,21 +21,19 @@ private async Task<bool> Update(List<CacheAsset> updateAssetIndex, List<CacheAss
{
// Initialize new proxy-aware HttpClient
using HttpClient client = new HttpClientBuilder<SocketsHttpHandler>()
.UseLauncherConfig(_downloadThreadCount + 16)
.UseLauncherConfig(_downloadThreadCount + _downloadThreadCountReserved)
.SetUserAgent(_userAgent)
.SetAllowedDecompression(DecompressionMethods.None)
.Create();

// Assign Http client
Http httpClient = new Http(true, 5, 1000, _userAgent, client);
// Use the new DownloadClient instance
DownloadClient downloadClient = DownloadClient.CreateInstance(client);
try
{
// Set IsProgressAllIndetermined as false and update the status
_status!.IsProgressAllIndetermined = true;
UpdateStatus();

// Subscribe the event listener
httpClient.DownloadProgress += _httpClient_UpdateAssetProgress;
// Iterate the asset index and do update operation
ObservableCollection<IAssetProperty> assetProperty = new ObservableCollection<IAssetProperty>(AssetEntry);
if (_isBurstDownloadEnabled)
Expand All @@ -52,7 +49,7 @@ await Parallel.ForEachAsync(
new ParallelOptions { CancellationToken = token, MaxDegreeOfParallelism = _downloadThreadCount },
async (asset, innerToken) =>
{
await UpdateCacheAsset(asset, httpClient, innerToken);
await UpdateCacheAsset(asset, downloadClient, _httpClient_UpdateAssetProgress, innerToken);
});
}
else
Expand All @@ -66,7 +63,7 @@ await Parallel.ForEachAsync(
#endif
, assetProperty))
{
await UpdateCacheAsset(asset, httpClient, token);
await UpdateCacheAsset(asset, downloadClient, _httpClient_UpdateAssetProgress, token);
}
}

Expand All @@ -82,11 +79,6 @@ await Parallel.ForEachAsync(
LogWriteLine($"An error occured while updating cache file!\r\n{ex}", LogType.Error, true);
throw;
}
finally
{
// Unsubscribe the event listener and dispose Http client
httpClient.DownloadProgress -= _httpClient_UpdateAssetProgress;
}
}

private void UpdateCacheVerifyList(List<CacheAsset> assetIndex)
Expand All @@ -110,7 +102,7 @@ private void UpdateCacheVerifyList(List<CacheAsset> assetIndex)
}
}

private async Task UpdateCacheAsset((CacheAsset AssetIndex, IAssetProperty AssetProperty) asset, Http httpClient, CancellationToken token)
private async Task UpdateCacheAsset((CacheAsset AssetIndex, IAssetProperty AssetProperty) asset, DownloadClient downloadClient, DownloadProgressDelegate downloadProgress, CancellationToken token)
{
// Increment total count and update the status
_progressAllCountCurrent++;
Expand All @@ -132,28 +124,11 @@ private async Task UpdateCacheAsset((CacheAsset AssetIndex, IAssetProperty Asset
// Other than unused file, do this action
else
{
// Assign and check the path of the asset directory
string assetDir = Path.GetDirectoryName(asset.AssetIndex.ConcatPath);
if (!Directory.Exists(assetDir))
{
Directory.CreateDirectory(assetDir!);
}

#if DEBUG
LogWriteLine($"Downloading cache [T: {asset.AssetIndex.DataType}]: {asset.AssetIndex.N} at URL: {asset.AssetIndex.ConcatURL}", LogType.Debug, true);
#endif

// Do multi-session download for asset that has applicable size
if (asset.AssetIndex.CS >= _sizeForMultiDownload && !_isBurstDownloadEnabled)
{
await httpClient!.Download(asset.AssetIndex.ConcatURL, asset.AssetIndex.ConcatPath, _downloadThreadCount, true, token);
await httpClient.Merge(token);
}
// Do single-session download for others
else
{
await httpClient!.Download(asset.AssetIndex.ConcatURL, asset.AssetIndex.ConcatPath, true, null, null, token);
}
await RunDownloadTask(asset.AssetIndex.CS, asset.AssetIndex.ConcatPath, asset.AssetIndex.ConcatURL, downloadClient, downloadProgress, token);

#if !DEBUG
LogWriteLine($"Downloaded cache [T: {asset.AssetIndex.DataType}]: {asset.AssetIndex.N}", LogType.Default, true);
Expand All @@ -163,32 +138,5 @@ private async Task UpdateCacheAsset((CacheAsset AssetIndex, IAssetProperty Asset
// Remove Asset Entry display
PopRepairAssetEntry(asset.AssetProperty);
}

private async void _httpClient_UpdateAssetProgress(object sender, DownloadEvent e)
{
// Update current progress percentages and speed
_progress!.ProgressAllPercentage = _progressAllSizeCurrent != 0 ?
ConverterTool.GetPercentageNumber(_progressAllSizeCurrent, _progressAllSizeTotal) :
0;

if (e!.State != DownloadState.Merging)
{
_progressAllSizeCurrent += e.Read;
}
long speed = (long)(_progressAllSizeCurrent / _stopwatch!.Elapsed.TotalSeconds);

if (await CheckIfNeedRefreshStopwatch())
{
// Update current activity status
_status!.IsProgressAllIndetermined = false;
string timeLeftString = string.Format(Lang!._Misc!.TimeRemainHMSFormat!, ((_progressAllSizeCurrent - _progressAllSizeTotal) / ConverterTool.Unzeroed(speed)).ToTimeSpanNormalized());
_status.ActivityAll = string.Format(Lang!._Misc!.Downloading + ": {0}/{1} ", _progressAllCountCurrent, _progressAllCountTotal)
+ string.Format($"({Lang._Misc.SpeedPerSec})", ConverterTool.SummarizeSizeSimple(speed))
+ $" | {timeLeftString}";

// Trigger update
UpdateAll();
}
}
}
}
Loading
Loading