Skip to content

Commit

Permalink
refactor ProjectController to use FileCallbackResult instead of my ha…
Browse files Browse the repository at this point in the history
…cked version
  • Loading branch information
hahn-kev committed Feb 14, 2024
1 parent f4cfe1c commit 883f8d7
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 14 deletions.
50 changes: 50 additions & 0 deletions backend/LexBoxApi/Controllers/ActionResults/FileCallbackResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace LexBoxApi.Controllers.ActionResults;

/// <summary>
/// Represents an <see cref="ActionResult"/> that when executed will
/// execute a callback to write the file content out as a stream.
/// copied from https://github.com/StephenClearyExamples/AsyncDynamicZip/tree/net6-ziparchive
/// MIT License
/// </summary>
public sealed class FileCallbackResult : FileResult
{
private readonly Func<Stream, ActionContext, Task> _callback;

/// <summary>
/// Creates a new <see cref="FileCallbackResult"/> instance.
/// </summary>
/// <param name="contentType">The Content-Type header of the response.</param>
/// <param name="callback">The stream with the file.</param>
public FileCallbackResult(string contentType, Func<Stream, ActionContext, Task> callback)
: base(contentType)
{
_ = callback ?? throw new ArgumentNullException(nameof(callback));
_callback = callback;
}

/// <inheritdoc />
public override Task ExecuteResultAsync(ActionContext context)
{
_ = context ?? throw new ArgumentNullException(nameof(context));
var executor =
new FileCallbackResultExecutor(context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>());
return executor.ExecuteAsync(context, this);
}

private sealed class FileCallbackResultExecutor : FileResultExecutorBase
{
public FileCallbackResultExecutor(ILoggerFactory loggerFactory)
: base(CreateLogger<FileCallbackResultExecutor>(loggerFactory))
{
}

public Task ExecuteAsync(ActionContext context, FileCallbackResult result)
{
SetHeadersAndLog(context, result, fileLength: null, enableRangeProcessing: false);
return result._callback(context.HttpContext.Response.BodyWriter.AsStream(), context);
}
}
}
16 changes: 5 additions & 11 deletions backend/LexBoxApi/Controllers/ProjectController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using LexBoxApi.Auth;
using LexBoxApi.Auth.Attributes;
using LexBoxApi.Controllers.ActionResults;
using LexBoxApi.Jobs;
using LexBoxApi.Services;
using LexCore.Entities;
Expand Down Expand Up @@ -114,18 +115,11 @@ public async Task<IActionResult> BackupProject(string code)
var backupExecutor = await projectService.BackupProject(code);
if (backupExecutor is null)
return NotFound();
return new StreamingResponse(backupExecutor.ExecuteBackup, "application/zip", $"{code}_backup.zip");
}

private class StreamingResponse(Func<Stream, Task> execute, string contentType, string fileName): ActionResult
{
public override async Task ExecuteResultAsync(ActionContext context)
return new FileCallbackResult("application/zip",
async (stream, context) => await backupExecutor.ExecuteBackup(stream, context.HttpContext.RequestAborted))
{
context.HttpContext.Response.ContentType = contentType;
context.HttpContext.Response.Headers.Append("Content-Disposition",
$"attachment; filename=\"{Path.GetFileName(fileName)}\"");
await execute.Invoke(context.HttpContext.Response.BodyWriter.AsStream());
}
FileDownloadName = $"{code}_backup.zip"
};
}

[HttpPost("resetProject/{code}")]
Expand Down
4 changes: 2 additions & 2 deletions backend/LexBoxApi/Services/HgService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ public async Task DeleteRepo(string code)
{
return null;
}
return new(stream => Task.Run(() =>
return new((stream, token) => Task.Run(() =>
{
ZipFile.CreateFromDirectory(repoPath, stream, CompressionLevel.Fastest, false);
}));
}, token));
}

public async Task ResetRepo(string code)
Expand Down
2 changes: 1 addition & 1 deletion backend/LexCore/ServiceInterfaces/IHgService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace LexCore.ServiceInterfaces;

public record BackupExecutor(Func<Stream, Task> ExecuteBackup);
public record BackupExecutor(Func<Stream, CancellationToken, Task> ExecuteBackup);
public interface IHgService
{
Task InitRepo(string code);
Expand Down

0 comments on commit 883f8d7

Please sign in to comment.