Files
EonaCat.Logger/Testers/EonaCat.Logger.Test.Web/Logger.cs
2023-07-12 21:44:11 +02:00

164 lines
5.9 KiB
C#

using EonaCat.Logger.Managers;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace EonaCat.Logger.Test.Web
{
public static class Logger
{
private static readonly LogManager LogManager = new LogManager(new LoggerSettings
{
Id = "EonaCatDnsLogger",
MaxLogType = ELogType.TRACE,
FileLoggerOptions =
{
LogDirectory = "Logs",
FileSizeLimit = 20_000_000, // 20 MB
}
});
public static string LogFolder => "Logs";
public static string CurrentLogFile => LogManager.CurrentLogFile;
public static bool IsDisabled { get; set; }
public static void DeleteCurrentLogFile()
{
if (IsDisabled)
return;
LogManager.DeleteCurrentLogFile();
}
internal static IActionResult DownloadLogAsync(HttpResponse response, string logFile)
{
if (IsDisabled)
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
return null;
}
// Check if the file exists
if (!File.Exists(logFile))
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
return null;
}
// Create a cancellation token source to handle cancellation
var cancellationTokenSource = new CancellationTokenSource();
// Start streaming the file content to the response
Task.Run(() => StreamFileContentAsync(response, logFile, response.Body, cancellationTokenSource.Token), cancellationTokenSource.Token);
// Return an empty result to indicate that streaming has started
return new EmptyResult();
}
private static void DisableResponseBuffering(HttpResponse response)
{
var httpContext = response.HttpContext;
var responseBodyFeature = httpContext.Features.Get<IHttpResponseBodyFeature>();
if (responseBodyFeature != null)
{
responseBodyFeature.DisableBuffering();
}
}
private static async Task StreamFileContentAsync(HttpResponse response, string filePath, Stream outputStream, CancellationToken cancellationToken)
{
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
try
{
// Clear the response first
response.Clear();
// Disable response buffering
DisableResponseBuffering(response);
// Set the response headers
response.Headers.Add("Content-Disposition", $"attachment; filename={Path.GetFileName(filePath)}");
response.Headers.Add("Content-Type", "application/octet-stream");
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
// Check if the response is completed
if (response.HasStarted)
{
// The response is already completed, so we can't write further
break;
}
try
{
await outputStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
}
catch (Exception)
{
// Do nothing, handle any specific error if needed
}
// Check if the file has been modified
if (File.GetLastWriteTimeUtc(filePath) > File.GetLastWriteTimeUtc(fileStream.Name))
{
// Close the existing stream and reopen the file with updated contents
fileStream.Close();
await StreamFileContentAsync(response, filePath, outputStream, cancellationToken).ConfigureAwait(false);
return;
}
}
}
catch (OperationCanceledException)
{
// The operation was canceled, clean up if necessary
fileStream.Close();
}
finally
{
try
{
// Flush and close the output stream
await outputStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
catch (ObjectDisposedException e)
{
Log(e, "StreamFileContentAsync");
}
finally
{
outputStream?.Close();
}
}
}
}
public static void Log(string message, ELogType logType = ELogType.INFO, bool writeToConsole = true)
{
if (IsDisabled)
return;
LogManager.Write(message, logType, writeToConsole);
}
public static void Log(Exception exception, string message = "", bool writeToConsole = true)
{
if (IsDisabled)
return;
LogManager.Write(exception, module: message, writeToConsole: writeToConsole);
}
}
}