using MassTransit; using Microsoft.Extensions.Logging; using Musify.Infrastructure.MassTransit.Arguments; using Musify.Infrastructure.MassTransit.Logs; namespace Musify.Infrastructure.MassTransit.Activities.Files { internal class DownloadFileFromUrlActivity( IHttpClientFactory httpClientFactory, ILogger logger) : IActivity { public const string ExecuteEndpointName = "download-file-from-url"; public async Task Execute(ExecuteContext executeContext) { var destinationPath = executeContext.GetVariable(executeContext.Arguments.DestinationFilePathVariable); ArgumentNullException.ThrowIfNull(destinationPath, nameof(destinationPath)); try { var httpClient = httpClientFactory.CreateClient(); using var response = await httpClient.GetAsync( executeContext.Arguments.SourceUrl, HttpCompletionOption.ResponseHeadersRead, executeContext.CancellationToken); response.EnsureSuccessStatusCode(); var destinationDirectory = Path.GetDirectoryName(destinationPath); if (!string.IsNullOrWhiteSpace(destinationDirectory)) Directory.CreateDirectory(destinationDirectory); await using (var destinationStream = File.Create(destinationPath)) { await response.Content.CopyToAsync(destinationStream, executeContext.CancellationToken); } logger.LogInformation("Downloaded {SourceUrl} to {DestinationPath}", executeContext.Arguments.SourceUrl, destinationPath); return executeContext.Completed(new DownloadFileFromUrlLog( executeContext.Arguments.SourceUrl, destinationPath)); } catch (Exception exception) { logger.LogError(exception, "Failed to download file from {SourceUrl}", executeContext.Arguments.SourceUrl); throw; } } public Task Compensate(CompensateContext compensateContext) { try { if (File.Exists(compensateContext.Log.DestinationFilePath)) File.Delete(compensateContext.Log.DestinationFilePath); return Task.FromResult(compensateContext.Compensated()); } catch (Exception exception) { logger.LogError(exception, "Failed to compensate downloaded file {DestinationFilePath}", compensateContext.Log.DestinationFilePath); return Task.FromResult(compensateContext.Failed(exception)); } } } }