Commit 92edfcc2 authored by Antoni Zaprzała's avatar Antoni Zaprzała

update

parent 276a4432
......@@ -30,12 +30,12 @@ app.MapGet("/files", (LogFileBrowser browser) =>
// downloads to working directory a single log file by name
// example: curl -OJ http://127.0.0.1:8082/files/download/lcd-2026-07-01_09-18-33.log
app.MapGet("/files/download/{name}", (string name, LogFileBrowser browser) =>
app.MapGet("/files/download/{name}", async (string name, LogFileBrowser browser, CancellationToken ct) =>
{
var path = browser.GetFilePath(name);
if (path is null) return Results.NotFound();
var bytes = await browser.ReadSnapshotAsync(name, ct);
if (bytes is null) return Results.NotFound();
return Results.File(path, "application/octet-stream", fileDownloadName: name);
return Results.File(bytes, "application/octet-stream", fileDownloadName: name);
});
// example: curl -OJ http://127.0.0.1:8082/files/download-all
......
......@@ -37,10 +37,37 @@ namespace LcdLogger.Services
public string? GetFilePath(string name)
{
var fullPath = Path.Combine(_options.Directory, name);
var safeName = Path.GetFileName(name);
if (string.IsNullOrEmpty(safeName)) return null;
var fullPath = Path.Combine(_options.Directory, safeName);
return File.Exists(fullPath) ? fullPath : null;
}
public async Task<byte[]?> ReadSnapshotAsync(string name, CancellationToken cancellationToken = default)
{
var path = GetFilePath(name);
if (path is null) return null;
try
{
using var fileStream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
bufferSize: 4096,
useAsync: true);
return await ReadExactSnapshotAsync(fileStream, name, fileStream.Length, cancellationToken);
}
catch (IOException e)
{
_logger.LogError(e, "Failed to read snapshot of {FileName}", name);
return null;
}
}
public async Task<byte[]> BuildZipAsync(CancellationToken cancellationToken = default)
{
var directoryInfo = new DirectoryInfo(_options.Directory);
......@@ -58,6 +85,7 @@ namespace LcdLogger.Services
{
try
{
var snapshotLength = file.Length;
var entry = zip.CreateEntry(file.Name, CompressionLevel.Fastest);
using (var entryStream = entry.Open())
......@@ -67,7 +95,7 @@ namespace LcdLogger.Services
FileAccess.Read,
FileShare.ReadWrite))
{
await fileStream.CopyToAsync(entryStream, cancellationToken);
await CopyExactAsync(fileStream, entryStream, snapshotLength, cancellationToken);
}
}
catch (Exception e)
......@@ -76,10 +104,49 @@ namespace LcdLogger.Services
}
}
}
// zip.Dispose() na końcu tego bloku → zapisuje footer do buffer (MemoryStream, sync OK)
return buffer.ToArray();
}
private async Task<byte[]> ReadExactSnapshotAsync(Stream source, string name, long length, CancellationToken cancellationToken)
{
var buffer = new byte[length];
var offset = 0;
while (offset < buffer.Length)
{
var read = await source.ReadAsync(buffer.AsMemory(offset), cancellationToken);
if (read == 0) break;
offset += read;
}
if (offset < buffer.Length)
{
_logger.LogWarning(
"Snapshot {FileName} truncated: expected {Expected} bytes, read {Actual}",
name, buffer.Length, offset);
return buffer[..offset];
}
return buffer;
}
private static async Task CopyExactAsync(Stream source, Stream destination, long count, CancellationToken cancellationToken)
{
var buffer = new byte[81920];
var remaining = count;
while (remaining > 0)
{
var toRead = (int)Math.Min(buffer.Length, remaining);
var read = await source.ReadAsync(buffer.AsMemory(0, toRead), cancellationToken);
if (read == 0) break;
await destination.WriteAsync(buffer.AsMemory(0, read), cancellationToken);
remaining -= read;
}
}
}
}
......@@ -138,8 +138,13 @@ namespace LcdLogger.Services
// }
//}
private bool _disposed;
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_disposed = true;
try
{
await _fileStream.FlushAsync();
......@@ -147,7 +152,7 @@ namespace LcdLogger.Services
}
catch(Exception e)
{
_logger.LogError(e.Message);
_logger.LogError(e, "Failed to flush/close log file on dispose");
}
}
}
......
......@@ -30,6 +30,10 @@
_logger.LogError("Failed to write batch {e}", e);
}
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
}
catch (Exception e)
{
......@@ -37,7 +41,6 @@
}
finally
{
await _logFileManager.DisposeAsync();
_logger.LogInformation("LogWriterWorker stopped");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment