Safe code and changes

This commit is contained in:
2026-05-14 01:00:44 +02:00
parent 1ecf4a872e
commit f6ac45cb79
25 changed files with 568 additions and 266 deletions
@@ -1,6 +1,5 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using MimeMapping;
using Musify.Application.Contracts.Infrastructure;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Logs;
@@ -3,7 +3,6 @@ using Microsoft.Extensions.Logging;
using Musify.Application.Contracts.Infrastructure;
using Musify.Infrastructure.MassTransit.Activities.Arguments;
using Musify.Infrastructure.MassTransit.Activities.Logs;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
namespace Musify.Infrastructure.MassTransit.Activities
{
@@ -1,7 +1,6 @@
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;
@@ -0,0 +1,40 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Contracts.Infrastructure;
using Musify.Application.Events;
namespace Musify.Infrastructure.MassTransit.Consumers
{
public class RemoveFileConsumer(
IStorageService storageService,
ILogger<RemoveFileConsumer> logger)
: IConsumer<RemoveFileEvent>
{
public const string QueueName = "remove-file";
public async Task Consume(ConsumeContext<RemoveFileEvent> consumeContext)
{
try
{
await storageService.RemoveFileAsync(
consumeContext.Message.Bucket,
consumeContext.Message.Key,
consumeContext.CancellationToken);
logger.LogInformation(
"Removed file {Key} from bucket {Bucket}",
consumeContext.Message.Key,
consumeContext.Message.Bucket);
}
catch (Exception exception)
{
logger.LogError(
exception,
"Failed to remove file {Key} from bucket {Bucket}",
consumeContext.Message.Key,
consumeContext.Message.Bucket);
throw;
}
}
}
}
@@ -0,0 +1,50 @@
using MassTransit;
using Musify.Infrastructure.MassTransit.Consumers;
namespace Musify.Infrastructure.MassTransit
{
public static partial class MassTransitDependencyInjection
{
static void ConfigureConsumerEndpoint<TConsumer>(
IRabbitMqBusFactoryConfigurator busFactoryConfigurator,
IBusRegistrationContext busRegistrationContext,
string queueName)
where TConsumer : class, IConsumer
{
busFactoryConfigurator.ReceiveEndpoint(queueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<TConsumer>(busRegistrationContext));
}
static void ConfigureExecuteActivityEndpoint<TActivity, TArguments>(
IRabbitMqBusFactoryConfigurator busFactoryConfigurator,
IBusRegistrationContext busRegistrationContext,
string endpointName)
where TActivity : class, IExecuteActivity<TArguments>
where TArguments : class
{
busFactoryConfigurator.ReceiveEndpoint(MassTransitEndpointNames.ExecuteQueue(endpointName), endpointConfigurator =>
{
endpointConfigurator.ExecuteActivityHost<TActivity, TArguments>(busRegistrationContext);
});
}
static void ConfigureActivityEndpoint<TActivity, TArguments, TLog>(
IRabbitMqBusFactoryConfigurator busFactoryConfigurator,
IBusRegistrationContext busRegistrationContext,
string endpointName)
where TActivity : class, IActivity<TArguments, TLog>
where TArguments : class
where TLog : class
{
busFactoryConfigurator.ReceiveEndpoint(MassTransitEndpointNames.ExecuteQueue(endpointName), endpointConfigurator =>
endpointConfigurator.ExecuteActivityHost<TActivity, TArguments>(
EndpointHelper.BuildCompensateActivityUri(endpointName),
busRegistrationContext)
);
busFactoryConfigurator.ReceiveEndpoint(MassTransitEndpointNames.CompensateQueue(endpointName), endpointConfigurator =>
endpointConfigurator.CompensateActivityHost<TActivity, TLog>(busRegistrationContext)
);
}
}
}
@@ -0,0 +1,24 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Musify.Infrastructure.MassTransit
{
public static partial class MassTransitDependencyInjection
{
static void RegisterValidatedOptions<TOptions>(
IServiceCollection services,
IConfiguration configuration,
string sectionName)
where TOptions : class
{
services
.AddOptionsWithValidateOnStart<TOptions>()
.Bind(configuration.GetRequiredSection(sectionName))
.ValidateDataAnnotations();
services.AddSingleton(serviceProvider =>
serviceProvider.GetRequiredService<IOptions<TOptions>>().Value);
}
}
}
@@ -0,0 +1,144 @@
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Musify.Infrastructure.Configuration;
using Musify.Infrastructure.MassTransit.Activities;
using Musify.Infrastructure.MassTransit.Activities.Arguments;
using Musify.Infrastructure.MassTransit.Activities.Audio;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Logs;
using Musify.Infrastructure.MassTransit.Activities.Tracks;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Consumers;
using Musify.Infrastructure.MassTransit.Logs;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
namespace Musify.Infrastructure.MassTransit
{
public static partial class MassTransitDependencyInjection
{
static void RegisterRoutingSlipBuilders(IServiceCollection services)
{
services.AddScoped<AudioWorkflowRoutingSlipBuilder>();
services.AddScoped<PictureWorkflowRoutingSlipBuilder>();
services.AddScoped<DeleteTrackRoutingSlipBuilder>();
}
static void RegisterConsumersAndActivities(IBusRegistrationConfigurator options)
{
options.AddConsumer<UpdatePlayListPictureConsumer>();
options.AddConsumer<UpdateTrackPictureConsumer>();
options.AddConsumer<RoutingSlipCleanUpConsumer>();
options.AddConsumer<UpdateTrackAudioConsumer>();
options.AddConsumer<DeleteTrackConsumer>();
options.AddConsumer<RemoveFileConsumer>();
options.AddExecuteActivity<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>();
options.AddExecuteActivity<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>();
options.AddExecuteActivity<GeneratePictureWorkflowPathsActivity, GeneratePictureWorkflowPathsArguments>();
options.AddExecuteActivity<DeleteTrackActivity, DeleteTrackArguments>();
options.AddActivity<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>();
options.AddActivity<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>();
options.AddActivity<UpdateTrackPictureActivity, UpdateTrackPictureArguments, UpdateTrackPictureLog>();
options.AddActivity<DownloadFileFromBucketActivity, DownloadFileFromBucketArguments, DownloadFileFromBucketLog>();
options.AddActivity<TranscodeDashAudioActivity, TranscodeDashAudioArguments, TranscodeDashAudioLog>();
options.AddActivity<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>();
options.AddActivity<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>();
options.AddActivity<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>();
}
static void ConfigureRabbitMqWorkerEndpoints(
IBusRegistrationContext busRegistrationContext,
IRabbitMqBusFactoryConfigurator busFactoryConfigurator)
{
ConfigureRabbitMqHost(
busFactoryConfigurator,
busRegistrationContext.GetRequiredService<MassTransitConfiguration>());
ConfigureConsumerEndpoint<UpdatePlayListPictureConsumer>(
busFactoryConfigurator,
busRegistrationContext,
UpdatePlayListPictureConsumer.QueueName);
ConfigureConsumerEndpoint<UpdateTrackAudioConsumer>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackAudioConsumer.QueueName);
ConfigureConsumerEndpoint<UpdateTrackPictureConsumer>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackPictureConsumer.QueueName);
ConfigureConsumerEndpoint<DeleteTrackConsumer>(
busFactoryConfigurator,
busRegistrationContext,
DeleteTrackConsumer.QueueName);
ConfigureConsumerEndpoint<RemoveFileConsumer>(
busFactoryConfigurator,
busRegistrationContext,
RemoveFileConsumer.QueueName);
ConfigureConsumerEndpoint<RoutingSlipCleanUpConsumer>(
busFactoryConfigurator,
busRegistrationContext,
RoutingSlipCleanUpConsumer.QueueName);
ConfigureExecuteActivityEndpoint<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>(
busFactoryConfigurator,
busRegistrationContext,
RemoveFileFromBucketActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>(
busFactoryConfigurator,
busRegistrationContext,
GenerateAudioWorkflowPathsActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<GeneratePictureWorkflowPathsActivity, GeneratePictureWorkflowPathsArguments>(
busFactoryConfigurator,
busRegistrationContext,
GeneratePictureWorkflowPathsActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>(
busFactoryConfigurator,
busRegistrationContext,
ResizePictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdatePlayListPictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdateTrackPictureActivity, UpdateTrackPictureArguments, UpdateTrackPictureLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackPictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<DownloadFileFromBucketActivity, DownloadFileFromBucketArguments, DownloadFileFromBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
DownloadFileFromBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<TranscodeDashAudioActivity, TranscodeDashAudioArguments, TranscodeDashAudioLog>(
busFactoryConfigurator,
busRegistrationContext,
TranscodeDashAudioActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
TransferFilesToBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackAudioActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
UploadFileToBucketActivity.ExecuteEndpointName);
}
}
}
@@ -1,33 +1,19 @@
using MassTransit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Musify.Application.Contracts.Infrastructure;
using Musify.Infrastructure.Configuration;
using Musify.Infrastructure.MassTransit.Activities;
using Musify.Infrastructure.MassTransit.Activities.Arguments;
using Musify.Infrastructure.MassTransit.Activities.Audio;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Logs;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Consumers;
using Musify.Infrastructure.MassTransit.Logs;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
using Musify.Infrastructure.MassTransit.Activities.Tracks;
namespace Musify.Infrastructure.MassTransit
{
public static class MassTransitDependencyInjection
public static partial class MassTransitDependencyInjection
{
public static IServiceCollection AddMassTransitClient(this IServiceCollection serviceDescriptors, IConfiguration configuration)
{
serviceDescriptors
.AddOptionsWithValidateOnStart<MassTransitConfiguration>()
.Bind(configuration.GetRequiredSection(MassTransitConfiguration.SectionName))
.ValidateDataAnnotations();
serviceDescriptors.AddSingleton(serviceProvider =>
serviceProvider.GetRequiredService<IOptions<MassTransitConfiguration>>().Value);
RegisterValidatedOptions<MassTransitConfiguration>(
serviceDescriptors,
configuration,
MassTransitConfiguration.SectionName);
serviceDescriptors.AddScoped<IEventBus, MassTransitEventBus>();
serviceDescriptors.AddMassTransit(options =>
@@ -43,124 +29,24 @@ namespace Musify.Infrastructure.MassTransit
public static IServiceCollection AddMassTransitConsumers(this IServiceCollection serviceDescriptors, IConfiguration configuration)
{
serviceDescriptors
.AddOptionsWithValidateOnStart<MassTransitConfiguration>()
.Bind(configuration.GetRequiredSection(MassTransitConfiguration.SectionName))
.ValidateDataAnnotations();
RegisterValidatedOptions<MassTransitConfiguration>(
serviceDescriptors,
configuration,
MassTransitConfiguration.SectionName);
serviceDescriptors.AddSingleton(serviceProvider =>
serviceProvider.GetRequiredService<IOptions<MassTransitConfiguration>>().Value);
RegisterValidatedOptions<WorkerConfiguration>(
serviceDescriptors,
configuration,
WorkerConfiguration.SectionName);
serviceDescriptors
.AddOptionsWithValidateOnStart<WorkerConfiguration>()
.Bind(configuration.GetRequiredSection(WorkerConfiguration.SectionName))
.ValidateDataAnnotations();
serviceDescriptors.AddSingleton(serviceProvider =>
serviceProvider.GetRequiredService<IOptions<WorkerConfiguration>>().Value);
serviceDescriptors.AddScoped<AudioWorkflowRoutingSlipBuilder>();
serviceDescriptors.AddScoped<PictureWorkflowRoutingSlipBuilder>();
serviceDescriptors.AddScoped<DeleteTrackRoutingSlipBuilder>();
RegisterRoutingSlipBuilders(serviceDescriptors);
serviceDescriptors.AddMassTransit(options =>
{
options.AddConsumer<UpdatePlayListPictureConsumer>();
options.AddConsumer<UpdateTrackPictureConsumer>();
options.AddConsumer<RoutingSlipCleanUpConsumer>();
options.AddConsumer<UpdateTrackAudioConsumer>();
options.AddConsumer<DeleteTrackConsumer>();
options.AddExecuteActivity<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>();
options.AddExecuteActivity<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>();
options.AddExecuteActivity<GeneratePictureWorkflowPathsActivity, GeneratePictureWorkflowPathsArguments>();
options.AddExecuteActivity<DeleteTrackActivity, DeleteTrackArguments>();
options.AddActivity<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>();
options.AddActivity<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>();
options.AddActivity<UpdateTrackPictureActivity, UpdateTrackPictureArguments, UpdateTrackPictureLog>();
options.AddActivity<DownloadFileFromBucketActivity, DownloadFileFromBucketArguments, DownloadFileFromBucketLog>();
options.AddActivity<TranscodeDashAudioActivity, TranscodeDashAudioArguments, TranscodeDashAudioLog>();
options.AddActivity<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>();
options.AddActivity<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>();
options.AddActivity<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>();
RegisterConsumersAndActivities(options);
options.UsingRabbitMq((busRegistrationContext, busFactoryConfigurator) =>
{
ConfigureRabbitMqHost(
busFactoryConfigurator,
busRegistrationContext.GetRequiredService<MassTransitConfiguration>());
busFactoryConfigurator.ReceiveEndpoint(UpdatePlayListPictureConsumer.QueueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<UpdatePlayListPictureConsumer>(busRegistrationContext));
busFactoryConfigurator.ReceiveEndpoint(UpdateTrackAudioConsumer.QueueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<UpdateTrackAudioConsumer>(busRegistrationContext));
busFactoryConfigurator.ReceiveEndpoint(UpdateTrackPictureConsumer.QueueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<UpdateTrackPictureConsumer>(busRegistrationContext));
busFactoryConfigurator.ReceiveEndpoint(DeleteTrackConsumer.QueueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<DeleteTrackConsumer>(busRegistrationContext));
busFactoryConfigurator.ReceiveEndpoint(RoutingSlipCleanUpConsumer.QueueName, endpointConfigurator =>
endpointConfigurator.ConfigureConsumer<RoutingSlipCleanUpConsumer>(busRegistrationContext));
ConfigureExecuteActivityEndpoint<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>(
busFactoryConfigurator,
busRegistrationContext,
RemoveFileFromBucketActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>(
busFactoryConfigurator,
busRegistrationContext,
GenerateAudioWorkflowPathsActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<GeneratePictureWorkflowPathsActivity, GeneratePictureWorkflowPathsArguments>(
busFactoryConfigurator,
busRegistrationContext,
GeneratePictureWorkflowPathsActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>(
busFactoryConfigurator,
busRegistrationContext,
ResizePictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdatePlayListPictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdateTrackPictureActivity, UpdateTrackPictureArguments, UpdateTrackPictureLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackPictureActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<DownloadFileFromBucketActivity, DownloadFileFromBucketArguments, DownloadFileFromBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
DownloadFileFromBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<TranscodeDashAudioActivity, TranscodeDashAudioArguments, TranscodeDashAudioLog>(
busFactoryConfigurator,
busRegistrationContext,
TranscodeDashAudioActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
TransferFilesToBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>(
busFactoryConfigurator,
busRegistrationContext,
UpdateTrackAudioActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
UploadFileToBucketActivity.ExecuteEndpointName);
} );
ConfigureRabbitMqWorkerEndpoints(busRegistrationContext, busFactoryConfigurator));
} );
return serviceDescriptors;
@@ -176,37 +62,5 @@ namespace Musify.Infrastructure.MassTransit
options.Password(massTransitConfiguration.Password);
} );
}
static void ConfigureExecuteActivityEndpoint<TActivity, TArguments>(
IRabbitMqBusFactoryConfigurator busFactoryConfigurator,
IBusRegistrationContext busRegistrationContext,
string endpointName)
where TActivity : class, IExecuteActivity<TArguments>
where TArguments : class
{
busFactoryConfigurator.ReceiveEndpoint($"{endpointName}_execute", endpointConfigurator =>
{
endpointConfigurator.ExecuteActivityHost<TActivity, TArguments>(busRegistrationContext);
} );
}
static void ConfigureActivityEndpoint<TActivity, TArguments, TLog>(
IRabbitMqBusFactoryConfigurator busFactoryConfigurator,
IBusRegistrationContext busRegistrationContext,
string endpointName)
where TActivity : class, IActivity<TArguments, TLog>
where TArguments : class
where TLog : class
{
busFactoryConfigurator.ReceiveEndpoint($"{endpointName}_execute", endpointConfigurator =>
endpointConfigurator.ExecuteActivityHost<TActivity, TArguments>(
EndpointHelper.BuildCompensateActivityUri(endpointName),
busRegistrationContext)
);
busFactoryConfigurator.ReceiveEndpoint($"{endpointName}_compensate", endpointConfigurator =>
endpointConfigurator.CompensateActivityHost<TActivity, TLog>(busRegistrationContext)
);
}
}
}
@@ -0,0 +1,9 @@
namespace Musify.Infrastructure.MassTransit
{
internal static class MassTransitEndpointNames
{
internal static string ExecuteQueue(string endpointName) => $"{endpointName}_execute";
internal static string CompensateQueue(string endpointName) => $"{endpointName}_compensate";
}
}
@@ -3,7 +3,7 @@ namespace Musify.Infrastructure.MassTransit.Activities.Logs
public record UpdateTrackPictureLog(
Guid TrackId,
string PreviousOriginalPictureKey,
string PreviousSmallPictureKey,
string PreviousMediumPictureKey,
string PreviousLargePictureKey);
string? PreviousSmallPictureKey,
string? PreviousMediumPictureKey,
string? PreviousLargePictureKey);
}