| | | 1 | | using Anichron.Core.Data.Repository; |
| | | 2 | | using Anichron.Worker.Ingestion.Pipeline; |
| | | 3 | | |
| | | 4 | | namespace Anichron.Worker.Ingestion.Middlewares; |
| | | 5 | | |
| | 3 | 6 | | internal sealed partial class IdempotencyCheckMiddleware( |
| | 3 | 7 | | IMediaAssetRepository repository, |
| | 3 | 8 | | ILogger<IdempotencyCheckMiddleware> logger) : IIngestionMiddleware |
| | | 9 | | { |
| | 0 | 10 | | public int Order => IngestionOrder.IdempotencyCheck; |
| | 0 | 11 | | public bool CanInvoke(IngestionContext context) => true; |
| | | 12 | | |
| | | 13 | | public async Task InvokeAsync(IngestionContext context, IngestionDelegate next, CancellationToken ct) |
| | 3 | 14 | | { |
| | | 15 | | // Ordering guarantees ContentHashingMiddleware ran first; suppression is safe. |
| | 3 | 16 | | var existing = await repository.FindByHashAsync(context.ContentHash!, context.Config.Id, ct); |
| | 3 | 17 | | if (existing is not null) |
| | 1 | 18 | | { |
| | 1 | 19 | | Log.AlreadyIngested(logger, context.Item.AbsolutePath); |
| | 1 | 20 | | return; |
| | | 21 | | } |
| | | 22 | | |
| | 2 | 23 | | await next(context, ct); |
| | 3 | 24 | | } |
| | | 25 | | |
| | | 26 | | private static partial class Log |
| | | 27 | | { |
| | | 28 | | [LoggerMessage(Level = LogLevel.Debug, Message = "Already ingested {Path}, skipping.")] |
| | | 29 | | public static partial void AlreadyIngested(ILogger logger, string path); |
| | | 30 | | } |
| | | 31 | | } |