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

Add faster file download approach #2672

Closed
Closed
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
069ba2b
Replace usage of ResumableDownloader with NonReusableDownloader for f…
AlexDickerson Dec 27, 2024
dc6847e
Reverted unneeded change to AInstaller
AlexDickerson Dec 27, 2024
28a7f4e
Added more explicit error logging
AlexDickerson Dec 27, 2024
861e7df
Synced Namespaces
AlexDickerson Dec 27, 2024
44fe695
Adding UI for setting minimum file size at which to use resumable dow…
AlexDickerson Dec 28, 2024
fa7b2a0
Reverting unintended changes
AlexDickerson Dec 28, 2024
5ef9812
Reverting unneeded changes
AlexDickerson Dec 28, 2024
c25f439
Remove deprecated nexus auth method
AlexDickerson Dec 28, 2024
e8eff20
Merge pull request #2673 from AlexDickerson/removeSetNexusAPI
tr4wzified Dec 28, 2024
54863c6
Refactored performance settings and its dependency injection
AlexDickerson Dec 28, 2024
e8fa2be
Replaced references to concrete SettingsManager with interface
AlexDickerson Dec 28, 2024
76cd4dc
Removed two unnecessary usings
AlexDickerson Dec 28, 2024
f0d8b64
Fixed DownloadClientFactory to compare file size correctly
AlexDickerson Dec 28, 2024
66545cd
One more cleanup pass
AlexDickerson Dec 28, 2024
5ff915c
Replace usage of ResumableDownloader with NonReusableDownloader for f…
AlexDickerson Dec 27, 2024
4120d41
Reverted unneeded change to AInstaller
AlexDickerson Dec 27, 2024
d6ec4b2
Added more explicit error logging
AlexDickerson Dec 27, 2024
6fc715a
Synced Namespaces
AlexDickerson Dec 27, 2024
c87b302
Adding UI for setting minimum file size at which to use resumable dow…
AlexDickerson Dec 28, 2024
19c7583
Reverting unintended changes
AlexDickerson Dec 28, 2024
2fcad64
Reverting unneeded changes
AlexDickerson Dec 28, 2024
2d77b12
Refactored performance settings and its dependency injection
AlexDickerson Dec 28, 2024
7c73b24
Replaced references to concrete SettingsManager with interface
AlexDickerson Dec 28, 2024
31626cf
Removed two unnecessary usings
AlexDickerson Dec 28, 2024
a3bbcbf
Fixed DownloadClientFactory to compare file size correctly
AlexDickerson Dec 28, 2024
192c34b
One more cleanup pass
AlexDickerson Dec 28, 2024
7dd4ac7
Merge branch 'downloadsRefactor' of https://github.com/AlexDickerson/…
AlexDickerson Dec 28, 2024
a3e9016
Refactored downloader to resume on network failures
AlexDickerson Dec 29, 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
Prev Previous commit
Refactored downloader to resume on network failures
AlexDickerson committed Dec 29, 2024
commit a3e901625640f7ef1605ac3431e8c68cd404cae7
53 changes: 35 additions & 18 deletions Wabbajack.Downloader.Clients/NonResumableDownloadClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.Extensions.Logging;
using System.Net.Http.Headers;
using System.Net.Sockets;
using Wabbajack.Downloaders.Interfaces;
using Wabbajack.Hashing.xxHash64;
using Wabbajack.Paths;
@@ -10,46 +12,61 @@ internal class NonResumableDownloadClient(HttpRequestMessage _msg, AbsolutePath
{
public async Task<Hash> Download(CancellationToken token)
{
Stream? fileStream;
if (_msg.RequestUri == null)
{
throw new ArgumentException("Request URI is null");
}

try
{
fileStream = _outputPath.Open(FileMode.Create, FileAccess.Write, FileShare.None);
return await DownloadStreamDirectlyToFile(_msg.RequestUri, token, _outputPath, 5);
}
catch (Exception ex)
{
_logger.LogError(ex, "Could not open file path '{filePath}'. Throwing...", _outputPath.FileName.ToString());
_logger.LogError(ex, "Failed to download '{name}'", _outputPath.FileName.ToString());

throw;
}
}

private async Task<Hash> DownloadStreamDirectlyToFile(Uri rquestURI, CancellationToken token, AbsolutePath filePath, int retry = 5)
{
try
{
_logger.LogDebug("Download for '{name}' is starting from scratch...", _outputPath.FileName.ToString());

var httpClient = _httpClientFactory.CreateClient("SmallFilesClient");
var response = await httpClient.GetStreamAsync(_msg.RequestUri!.ToString());
using Stream fileStream = GetFileStream(filePath);
var startingPosition = fileStream.Length;

_logger.LogDebug("Download for '{name}' is starting from {position}...", _outputPath.FileName.ToString(), startingPosition);
httpClient.DefaultRequestHeaders.Range = new RangeHeaderValue(startingPosition, null); //GetStreamAsync does not accept a HttpRequestMessage so we have to set headers on the client itself

var response = await httpClient.GetStreamAsync(rquestURI, token);
await response.CopyToAsync(fileStream, token);
fileStream.Close();

return await fileStream.Hash(token);
}
catch (Exception ex)
catch (Exception ex) when (ex is SocketException || ex is IOException)
{
_logger.LogError(ex, "Download for '{name}' encountered error. Throwing...", _outputPath.FileName.ToString());
_logger.LogWarning(ex, "Failed to download '{name}' due to network error. Retrying...", _outputPath.FileName.ToString());

throw;
if(retry == 0)
{
throw;
}

return await DownloadStreamDirectlyToFile(rquestURI, token, _outputPath, retry--);
}
}

try
private Stream GetFileStream(AbsolutePath filePath)
{
if (filePath.FileExists())
{
await using var file = _outputPath.Open(FileMode.Open);
return await file.Hash(token);
return filePath.Open(FileMode.Append, FileAccess.Write, FileShare.None);
}
catch (Exception ex)
else
{
_logger.LogError(ex, "Could not hash file '{filePath}'. Throwing...", _outputPath.FileName.ToString());

throw;
return filePath.Open(FileMode.Create, FileAccess.Write, FileShare.None);
}
}
}
}
Loading