| | | 1 | | using Anichron.Worker.Ingestion.Pipeline; |
| | | 2 | | using System.IO.Abstractions; |
| | | 3 | | using System.IO.Hashing; |
| | | 4 | | |
| | | 5 | | namespace Anichron.Worker.Ingestion.Middlewares; |
| | | 6 | | |
| | 7 | 7 | | internal sealed class ContentHashingMiddleware(IFileSystem fileSystem) : IIngestionMiddleware |
| | | 8 | | { |
| | 0 | 9 | | public int Order => IngestionOrder.ContentHashing; |
| | 0 | 10 | | public bool CanInvoke(IngestionContext context) => true; |
| | | 11 | | |
| | | 12 | | public async Task InvokeAsync(IngestionContext context, IngestionDelegate next, CancellationToken ct) |
| | 7 | 13 | | { |
| | 7 | 14 | | context.ContentHash = await HashFileAsync(context.Item.AbsolutePath, ct); |
| | 7 | 15 | | if (context.Item.SecondaryFile is { } secondary) |
| | 1 | 16 | | context.SecondaryHash = await HashFileAsync(secondary.AbsolutePath, ct); |
| | 7 | 17 | | await next(context, ct); |
| | 7 | 18 | | } |
| | | 19 | | |
| | | 20 | | private async Task<string> HashFileAsync(string absolutePath, CancellationToken ct) |
| | 8 | 21 | | { |
| | 8 | 22 | | await using var stream = fileSystem.File.OpenRead(absolutePath); |
| | 8 | 23 | | var hasher = new XxHash64(); |
| | 8 | 24 | | await hasher.AppendAsync(stream, ct); |
| | 8 | 25 | | return Convert.ToHexStringLower(hasher.GetHashAndReset()); |
| | 8 | 26 | | } |
| | | 27 | | } |