using MassTransit; using Microsoft.Extensions.Logging; using Musify.Application.Contracts.Infrastructure; using Musify.Domain.Entities; using Musify.Infrastructure.MassTransit.Activities.Arguments; using Musify.Infrastructure.MassTransit.Activities.Logs; using Musify.Infrastructure.MassTransit.RoutingSlip.Builders; namespace Musify.Infrastructure.MassTransit.Activities { public class ResizePictureActivity( IPictureHandler pictureHandler, ILogger logger, IProcessTrackingStore processTrackingStore) : IActivity { public const string ExecuteEndpointName = "resize-picture"; public async Task Execute(ExecuteContext executeContext) { var processId = await processTrackingStore.GetOrCreateProcessAsync( "RoutingSlip", executeContext.CorrelationId ?? executeContext.TrackingNumber, executeContext.ConversationId, executeContext.MessageId, executeContext.CancellationToken); var stepId = await processTrackingStore.StartStepAsync( processId, nameof(ResizePictureActivity), ProcessStepComponentType.Activity, 0, executeContext.CancellationToken); var sourceFilePath = executeContext.GetVariable(executeContext.Arguments.SourceFilePathVariableName); ArgumentNullException.ThrowIfNull(sourceFilePath, nameof(sourceFilePath)); var destinationFilePath = executeContext.GetVariable(executeContext.Arguments.DestinationFilePathVariableName); ArgumentNullException.ThrowIfNull(destinationFilePath, nameof(destinationFilePath)); try { if (!File.Exists(sourceFilePath)) { logger.LogWarning("Source file not found at {SourceFilePath}", sourceFilePath); throw new FileNotFoundException($"Source file not found: {sourceFilePath}"); } await using var fileStream = File.OpenRead(sourceFilePath); var resizedPicture = await pictureHandler.ResizePictureAsWebpAsync( fileStream, executeContext.Arguments.Width, executeContext.Arguments.Height, executeContext.CancellationToken); if (!resizedPicture.IsSuccess) { var errorMessage = string.Join("; ", resizedPicture.Errors); logger.LogError("Failed to resize picture {SourceFilePath} to {Width}x{Height}. Errors: {Errors}", sourceFilePath, executeContext.Arguments.Width, executeContext.Arguments.Height, errorMessage); throw new Exception(errorMessage); } var destinationDirectory = Path.GetDirectoryName(destinationFilePath); if (!string.IsNullOrEmpty(destinationDirectory)) Directory.CreateDirectory(destinationDirectory); await using var destinationStream = File.Create(destinationFilePath); await resizedPicture.Value.CopyToAsync(destinationStream, executeContext.CancellationToken); logger.LogDebug("Picture resized from {SourceFilePath} to {DestinationFilePath} ({Width}x{Height})", sourceFilePath, destinationFilePath, executeContext.Arguments.Width, executeContext.Arguments.Height); await processTrackingStore.CompleteStepAsync(processId, stepId, executeContext.CancellationToken); return executeContext.Completed(new ResizePictureLog(destinationFilePath)); } catch (Exception exception) { logger.LogError(exception, "Error resizing picture {SourceFilePath}", sourceFilePath); await processTrackingStore.FailStepAsync(processId, stepId, exception.Message, executeContext.CancellationToken); throw; } } public Task Compensate(CompensateContext compensateContext) { try { File.Delete(compensateContext.Log.DestinationFilePath); return Task.FromResult(compensateContext.Compensated()); } catch (Exception exception) { logger.LogError(exception, "Error compensating resized file {DestinationFilePath}", compensateContext.Log.DestinationFilePath); return Task.FromResult(compensateContext.Failed(exception)); } } } }