4.1 ImageStore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
52
src/FrameProcessor/Storage/ImageStore.cs
Normal file
52
src/FrameProcessor/Storage/ImageStore.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using FrameProcessor.Configuration;
|
||||
using FrameProcessor.Domain;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FrameProcessor.Storage;
|
||||
|
||||
/// <summary>
|
||||
/// Persists the latest processed PNG for each frame to <see cref="StorageOptions.ImageDirectory"/>.
|
||||
/// Writes are atomic via a temp file + <see cref="File.Move(string, string, bool)"/> rename so the
|
||||
/// fetch endpoint never observes a partial file (see SPEC.md §7.2, CLAUDE.md "Atomic writes only").
|
||||
/// </summary>
|
||||
public sealed class ImageStore
|
||||
{
|
||||
private readonly string _directory;
|
||||
|
||||
public ImageStore(IOptions<StorageOptions> options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
_directory = options.Value.ImageDirectory;
|
||||
Directory.CreateDirectory(_directory);
|
||||
}
|
||||
|
||||
public async Task WriteAsync(MacAddress mac, ReadOnlyMemory<byte> bytes, CancellationToken cancellationToken)
|
||||
{
|
||||
var finalPath = GetPath(mac);
|
||||
var tmpPath = finalPath + ".tmp";
|
||||
|
||||
await using (var stream = new FileStream(tmpPath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
await stream.WriteAsync(bytes, cancellationToken).ConfigureAwait(false);
|
||||
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
File.Move(tmpPath, finalPath, overwrite: true);
|
||||
}
|
||||
|
||||
public bool TryGetPath(MacAddress mac, [NotNullWhen(true)] out string? path)
|
||||
{
|
||||
var candidate = GetPath(mac);
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
path = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
path = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetPath(MacAddress mac) => Path.Combine(_directory, $"{mac}.png");
|
||||
}
|
||||
Reference in New Issue
Block a user