Skip to content

Commit

Permalink
Merge pull request #58 from aspriddell/add-filerequest-progress
Browse files Browse the repository at this point in the history
add file download progress reporting
  • Loading branch information
aspriddell authored Jan 11, 2021
2 parents 9c3d41c + 534a444 commit d4e8ba1
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 12 deletions.
23 changes: 17 additions & 6 deletions DragonFruit.Common.Data.Tests/Files/FileDownloadTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// DragonFruit.Common Copyright 2020 DragonFruit Network
// Licensed under the MIT License. Please refer to the LICENSE file at the root of this project for details

using System;
using System.IO;
using DragonFruit.Common.Data.Basic;
using NUnit.Framework;
Expand All @@ -10,19 +11,29 @@ namespace DragonFruit.Common.Data.Tests.Files
[TestFixture]
public class FileDownloadTests : ApiTest
{
[TestCase]
public void FileDownloadTest()
[TestCase("https://github.com/ppy/osu/archive/2020.1121.0.zip", 19018589)]
public void FileDownloadTest(string path, long expectedFileSize)
{
var request = new BasicApiFileRequest("https://github.com/ppy/osu/archive/2020.1121.0.zip", Path.GetTempPath());
var request = new BasicApiFileRequest(path, Path.GetTempPath());

Assert.IsFalse(File.Exists(request.Destination));
if (File.Exists(request.Destination))
{
try
{
File.Delete(request.Destination);
}
catch
{
Assert.Inconclusive("Failed to remove file needed for test");
}
}

try
{
Client.Perform(request);
Client.Perform(request, (progress, total) => TestContext.Out.WriteLine($"Progress: {progress:n0}/{total:n0} ({Convert.ToSingle(progress) / Convert.ToSingle(total):F2}%)"));

Assert.IsTrue(File.Exists(request.Destination));
Assert.IsTrue(new FileInfo(request.Destination).Length > 5000);
Assert.GreaterOrEqual(new FileInfo(request.Destination).Length, expectedFileSize);
}
finally
{
Expand Down
15 changes: 11 additions & 4 deletions DragonFruit.Common.Data/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ public virtual T Perform<T>(HttpRequestMessage request, CancellationToken token
/// Download a file with an <see cref="ApiRequest"/>.
/// Bypasses <see cref="ValidateAndProcess{T}"/>
/// </summary>
public virtual void Perform(ApiFileRequest request, CancellationToken token = default)
public virtual void Perform(ApiFileRequest request, Action<long, long?> progressUpdated = null, CancellationToken token = default)
{
//check request data is valid
ValidateRequest(request);
Expand All @@ -256,18 +256,25 @@ public virtual void Perform(ApiFileRequest request, CancellationToken token = de

HttpResponseMessage CopyProcess(HttpResponseMessage response)
{
//validate
// validate
response.EnsureSuccessStatusCode();

// create a new filestream and copy all data into
using var stream = File.Open(request.Destination, request.FileCreationMode);

#if NET5_0
using var networkStream = response.Content.ReadAsStreamAsync(token).Result;
#else
using var networkStream = response.Content.ReadAsStreamAsync().Result;
#endif
networkStream.CopyTo(stream);
// create a buffer for progress reporting
var buffer = new byte[request.BufferSize];
int count;

while ((count = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, count);
progressUpdated?.Invoke(stream.Length, response.Content.Headers.ContentLength);
}

// flush and return
stream.Flush();
Expand Down
17 changes: 15 additions & 2 deletions DragonFruit.Common.Data/ApiFileRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@ namespace DragonFruit.Common.Data
{
public abstract class ApiFileRequest : ApiRequest
{
protected override Methods Method => Methods.Get;

/// <summary>
/// The location, on the disk, to put the resultant file
/// </summary>
public abstract string Destination { get; }

/// <summary>
/// The mode of file creation
/// </summary>
public virtual FileMode FileCreationMode => FileMode.Create;

/// <summary>
/// Length, in bytes, of the buffer used for copying data from the network stream to the file.
/// Defaults to 32kb
/// </summary>
/// <remarks>
/// This should be less than 85KiB (87040 bytes) to avoid potential memory leaks
/// </remarks>
public virtual int BufferSize => 32 * 1024;
}
}

0 comments on commit d4e8ba1

Please sign in to comment.