This commit is contained in:
2026-05-28 18:37:54 +02:00
parent 868af6dc49
commit 5c75b611f0
29 changed files with 683 additions and 219 deletions
@@ -0,0 +1,12 @@
namespace Musify.Application.Events
{
public record CreatePlayListResourcesEvent(
Guid PlayListId,
Guid PictureIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -0,0 +1,16 @@
namespace Musify.Application.Events
{
public record CreateTrackResourcesEvent(
Guid TrackId,
Guid PictureIntentId,
Guid AudioIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
string AudioSourceKey,
string AudioDestinationKey,
string AudioProcessedFolderKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -0,0 +1,12 @@
namespace Musify.Application.Events
{
public record UpdatePlayListPictureSourceEvent(
Guid PlayListId,
Guid PictureIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -17,7 +17,6 @@ namespace Musify.Application.PlayLists.Handlers
IEventBus eventBus, IEventBus eventBus,
IDatabase database, IDatabase database,
UploadIntentValidator uploadIntentValidator, UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<CreatePlayListCommandHandler> logger, ILogger<CreatePlayListCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration, ApplicationStorageConfiguration storageConfiguration,
PlayListConfiguration playListConfiguration, PlayListConfiguration playListConfiguration,
@@ -35,8 +34,8 @@ namespace Musify.Application.PlayLists.Handlers
return Result.NotFound($"User {request.UserId} not found"); return Result.NotFound($"User {request.UserId} not found");
} }
string originalPictureName;
UploadIntent? pictureIntent = null; UploadIntent? pictureIntent = null;
string originalPictureName;
if (request.PictureIntentId.HasValue) if (request.PictureIntentId.HasValue)
{ {
@@ -48,17 +47,6 @@ namespace Musify.Application.PlayLists.Handlers
pictureIntent = validation.Value; pictureIntent = validation.Value;
originalPictureName = pictureIntent.ObjectName; originalPictureName = pictureIntent.ObjectName;
var finalKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, originalPictureName);
try
{
await storageService.CopyFileAsync(pictureIntent.Bucket, pictureIntent.Key, pictureIntent.Bucket, finalKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy playlist picture from temp {TempKey} to final {FinalKey}", pictureIntent.Key, finalKey);
return Result.Error("Failed to move uploaded file to its final location.");
}
} }
else else
{ {
@@ -81,9 +69,9 @@ namespace Musify.Application.PlayLists.Handlers
if (pictureIntent is not null) if (pictureIntent is not null)
{ {
pictureIntent.Status = UploadIntentStatus.Consumed; var finalPictureKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, originalPictureName);
var publishResult = await PublishCreatePlayListEventAsync(
var publishResult = await PublishPictureUpdateEventAsync(playList, cancellationToken); playList.Id, pictureIntent, finalPictureKey, cancellationToken);
if (!publishResult.IsSuccess) if (!publishResult.IsSuccess)
return publishResult; return publishResult;
} }
@@ -102,35 +90,41 @@ namespace Musify.Application.PlayLists.Handlers
return Result.Created(PlayListApplicationResponse.FromEntity(playList)); return Result.Created(PlayListApplicationResponse.FromEntity(playList));
} }
async Task<Result> PublishPictureUpdateEventAsync(PlayList playList, CancellationToken cancellationToken) async Task<Result<PlayListApplicationResponse>> PublishCreatePlayListEventAsync(
Guid playListId,
UploadIntent pictureIntent,
string finalPictureKey,
CancellationToken cancellationToken)
{ {
try try
{ {
var updateEvent = new UpdatePlayListPictureEvent( await eventBus.PublishAsync(
playList.Id, new CreatePlayListResourcesEvent(
storageConfiguration.Bucket, playListId,
playListConfiguration.Routes.BuildOriginalPicturePath(playList.UserId, playList.OriginalPictureName), pictureIntent.Id,
new ImageSize( storageConfiguration.Bucket,
playListConfiguration.Routes.SmallPicturesPath, pictureIntent.Key,
playListConfiguration.PicturesSizes.SmallPictureWidth, finalPictureKey,
playListConfiguration.PicturesSizes.SmallPictureHeight), new ImageSize(
new ImageSize( playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.Routes.MediumPicturesPath, playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureWidth, playListConfiguration.PicturesSizes.SmallPictureHeight),
playListConfiguration.PicturesSizes.MediumPictureHeight), new ImageSize(
new ImageSize( playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.Routes.LargePicturesPath, playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.LargePictureWidth, playListConfiguration.PicturesSizes.MediumPictureHeight),
playListConfiguration.PicturesSizes.LargePictureHeight)); new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
await eventBus.PublishAsync(updateEvent, cancellationToken); playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken);
return Result.Success(); return Result.Success();
} }
catch (Exception exception) catch (Exception exception)
{ {
logger.LogError(exception, "Failed to publish picture update event for playlist {PlayListId}", playList.Id); logger.LogError(exception, "Failed to publish create playlist event for playlist {PlayListId}", playListId);
return Result.Error($"Failed to publish picture update event for playlist {playList.Id}"); return Result.Error($"Failed to publish create playlist event for playlist {playListId}");
} }
} }
} }
} }
@@ -17,7 +17,6 @@ namespace Musify.Application.PlayLists.Handlers
IEventBus eventBus, IEventBus eventBus,
IDatabase database, IDatabase database,
UploadIntentValidator uploadIntentValidator, UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<UpdatePlayListCommandHandler> logger, ILogger<UpdatePlayListCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration, ApplicationStorageConfiguration storageConfiguration,
PlayListConfiguration playListConfiguration, PlayListConfiguration playListConfiguration,
@@ -50,6 +49,9 @@ namespace Musify.Application.PlayLists.Handlers
playListEntity.Description = request.NewDescription; playListEntity.Description = request.NewDescription;
} }
UploadIntent? pictureIntent = null;
string? finalPictureKey = null;
if (request.NewPictureIntentId.HasValue) if (request.NewPictureIntentId.HasValue)
{ {
var validation = await uploadIntentValidator.ValidateAndLoadAsync( var validation = await uploadIntentValidator.ValidateAndLoadAsync(
@@ -58,29 +60,23 @@ namespace Musify.Application.PlayLists.Handlers
if (!validation.IsSuccess) if (!validation.IsSuccess)
return validation.As<UploadIntent, PlayListApplicationResponse>(); return validation.As<UploadIntent, PlayListApplicationResponse>();
var intent = validation.Value; pictureIntent = validation.Value;
var finalKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, intent.ObjectName); playListEntity.OriginalPictureName = pictureIntent.ObjectName;
try finalPictureKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, pictureIntent.ObjectName);
{ }
await storageService.CopyFileAsync(intent.Bucket, intent.Key, intent.Bucket, finalKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy playlist picture from temp {TempKey} to final {FinalKey}", intent.Key, finalKey);
return Result.Error("Failed to move uploaded file to its final location.");
}
playListEntity.OriginalPictureName = intent.ObjectName; database.PlayLists.Update(playListEntity);
intent.Status = UploadIntentStatus.Consumed;
var publishResult = await PublishPlayListPictureEvent(playListEntity.UserId, playListEntity.Id, playListEntity.OriginalPictureName, cancellationToken); if (pictureIntent is not null && finalPictureKey is not null)
{
var publishResult = await PublishUpdatePlayListPictureSourceEventAsync(
playListEntity.Id, pictureIntent, finalPictureKey, cancellationToken);
if (!publishResult.IsSuccess) if (!publishResult.IsSuccess)
return publishResult; return publishResult;
} }
try try
{ {
database.PlayLists.Update(playListEntity);
await database.SaveChangesAsync(cancellationToken); await database.SaveChangesAsync(cancellationToken);
} }
catch (Exception exception) catch (Exception exception)
@@ -93,34 +89,41 @@ namespace Musify.Application.PlayLists.Handlers
return Result.Success(PlayListApplicationResponse.FromEntity(playListEntity)); return Result.Success(PlayListApplicationResponse.FromEntity(playListEntity));
} }
async Task<Result> PublishPlayListPictureEvent(Guid userId, Guid playListId, string originalPictureName, CancellationToken cancellationToken) async Task<Result<PlayListApplicationResponse>> PublishUpdatePlayListPictureSourceEventAsync(
Guid playListId,
UploadIntent pictureIntent,
string finalPictureKey,
CancellationToken cancellationToken)
{ {
try try
{ {
await eventBus.PublishAsync(new UpdatePlayListPictureEvent( await eventBus.PublishAsync(
playListId, new UpdatePlayListPictureSourceEvent(
storageConfiguration.Bucket, playListId,
playListConfiguration.Routes.BuildOriginalPicturePath(userId, originalPictureName), pictureIntent.Id,
new ImageSize( storageConfiguration.Bucket,
playListConfiguration.Routes.SmallPicturesPath, pictureIntent.Key,
playListConfiguration.PicturesSizes.SmallPictureWidth, finalPictureKey,
playListConfiguration.PicturesSizes.SmallPictureHeight), new ImageSize(
new ImageSize( playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.Routes.MediumPicturesPath, playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureWidth, playListConfiguration.PicturesSizes.SmallPictureHeight),
playListConfiguration.PicturesSizes.MediumPictureHeight), new ImageSize(
new ImageSize( playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.Routes.LargePicturesPath, playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.LargePictureWidth, playListConfiguration.PicturesSizes.MediumPictureHeight),
playListConfiguration.PicturesSizes.LargePictureHeight)), new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken); cancellationToken);
return Result.Success(); return Result.Success();
} }
catch (Exception exception) catch (Exception exception)
{ {
logger.LogError(exception, "Failed to publish playlist picture update event for playlist {PlayListId}", playListId); logger.LogError(exception, "Failed to publish update playlist picture source event for playlist {PlayListId}", playListId);
return Result.Error($"Failed to publish playlist {playListId} picture update event"); return Result.Error($"Failed to publish update playlist picture source event for playlist {playListId}");
} }
} }
} }
} }
@@ -17,7 +17,6 @@ namespace Musify.Application.Tracks.Handler
IDatabase database, IDatabase database,
IEventBus eventBus, IEventBus eventBus,
UploadIntentValidator uploadIntentValidator, UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<CreateTrackCommandHandler> logger, ILogger<CreateTrackCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration, ApplicationStorageConfiguration storageConfiguration,
TrackConfiguration trackConfiguration, TrackConfiguration trackConfiguration,
@@ -51,17 +50,7 @@ namespace Musify.Application.Tracks.Handler
var finalPictureKey = trackConfiguration.Routes.BuildOriginalPicturePath(request.UserId, pictureIntent.ObjectName); var finalPictureKey = trackConfiguration.Routes.BuildOriginalPicturePath(request.UserId, pictureIntent.ObjectName);
var finalAudioKey = trackConfiguration.Routes.BuildOriginalAudioPath(request.UserId, audioIntent.ObjectName); var finalAudioKey = trackConfiguration.Routes.BuildOriginalAudioPath(request.UserId, audioIntent.ObjectName);
var audioProcessedFolderKey = trackConfiguration.Routes.BuildProcessedAudioPath(Guid.NewGuid().ToString());
try
{
await storageService.CopyFileAsync(pictureIntent.Bucket, pictureIntent.Key, pictureIntent.Bucket, finalPictureKey, cancellationToken);
await storageService.CopyFileAsync(audioIntent.Bucket, audioIntent.Key, audioIntent.Bucket, finalAudioKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy track files from temp to final location for user {UserId}", request.UserId);
return Result.Error("Failed to move uploaded files to their final locations.");
}
var trackEntity = new Track var trackEntity = new Track
{ {
@@ -78,16 +67,38 @@ namespace Musify.Application.Tracks.Handler
await database.Tracks.AddAsync(trackEntity, cancellationToken); await database.Tracks.AddAsync(trackEntity, cancellationToken);
pictureIntent.Status = UploadIntentStatus.Consumed; try
audioIntent.Status = UploadIntentStatus.Consumed; {
await eventBus.PublishAsync(
var publishPictureResult = await PublishUpdateEvent(request.UserId, trackEntity, cancellationToken); new CreateTrackResourcesEvent(
if (!publishPictureResult.IsSuccess) trackEntity.Id,
return Result.Error($"Failed to create track for {request.Title}"); pictureIntent.Id,
audioIntent.Id,
var publishTranscodeResult = await PublishTranscodeEvent(request.UserId, trackEntity, cancellationToken); storageConfiguration.Bucket,
if (!publishTranscodeResult.IsSuccess) pictureIntent.Key,
finalPictureKey,
audioIntent.Key,
finalAudioKey,
audioProcessedFolderKey,
new ImageSize(
trackConfiguration.Routes.SmallPicturesPath,
trackConfiguration.PicturesSizes.SmallPictureWidth,
trackConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
trackConfiguration.Routes.MediumPicturesPath,
trackConfiguration.PicturesSizes.MediumPictureWidth,
trackConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
trackConfiguration.Routes.LargePicturesPath,
trackConfiguration.PicturesSizes.LargePictureWidth,
trackConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish create track event for track {TrackId}", trackEntity.Id);
return Result.Error($"Failed to create track for {request.Title}"); return Result.Error($"Failed to create track for {request.Title}");
}
try try
{ {
@@ -101,55 +112,5 @@ namespace Musify.Application.Tracks.Handler
return Result.Created(TrackApplicationResponse.FromEntity(trackEntity)); return Result.Created(TrackApplicationResponse.FromEntity(trackEntity));
} }
async Task<Result> PublishUpdateEvent(Guid userId, Track track, CancellationToken cancellationToken)
{
try
{
await eventBus.PublishAsync(new UpdateTrackPictureEvent(
track.Id,
storageConfiguration.Bucket,
trackConfiguration.Routes.BuildOriginalPicturePath(userId, track.OriginalPictureName),
new ImageSize(
trackConfiguration.Routes.SmallPicturesPath,
trackConfiguration.PicturesSizes.SmallPictureWidth,
trackConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
trackConfiguration.Routes.MediumPicturesPath,
trackConfiguration.PicturesSizes.MediumPictureWidth,
trackConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
trackConfiguration.Routes.LargePicturesPath,
trackConfiguration.PicturesSizes.LargePictureWidth,
trackConfiguration.PicturesSizes.LargePictureHeight)), cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish track picture update event for track {TrackId}", track.Id);
return Result.Error($"Failed to publish track picture update event for track {track.Id}");
}
}
async Task<Result> PublishTranscodeEvent(Guid userId, Track track, CancellationToken cancellationToken)
{
var destinationFolderAudio = trackConfiguration.Routes.BuildProcessedAudioPath(Guid.NewGuid().ToString());
try
{
await eventBus.PublishAsync(new UpdateTrackAudioEvent(
track.Id,
storageConfiguration.Bucket,
trackConfiguration.Routes.BuildOriginalAudioPath(userId, track.OriginalAudioName),
storageConfiguration.Bucket,
destinationFolderAudio), cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish track audio update event for track {TrackId}", track.Id);
return Result.Error($"Failed to publish track audio update event for track {track.Id}");
}
}
} }
} }
@@ -45,7 +45,6 @@ namespace Musify.Infrastructure.MassTransit.Activities
return executeContext.CompletedWithVariables(new Dictionary<string, object> return executeContext.CompletedWithVariables(new Dictionary<string, object>
{ {
[RoutingSlipVariableNames.Workflow.TemporalDirectory] = workingDirectory, [RoutingSlipVariableNames.Workflow.TemporalDirectory] = workingDirectory,
[RoutingSlipVariableNames.Audio.WorkingDirectory] = workingDirectory,
[RoutingSlipVariableNames.Audio.SourceFilePath] = sourceFilePath, [RoutingSlipVariableNames.Audio.SourceFilePath] = sourceFilePath,
[RoutingSlipVariableNames.Audio.TranscodedDirectory] = workingDirectory [RoutingSlipVariableNames.Audio.TranscodedDirectory] = workingDirectory
} ); } );
@@ -0,0 +1,61 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Contracts.Infrastructure;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Logs;
namespace Musify.Infrastructure.MassTransit.Activities.Files
{
internal class CopyFileInBucketActivity(
IStorageService storageHandler,
ILogger<CopyFileInBucketActivity> logger)
: IActivity<CopyFileInBucketArguments, CopyFileInBucketLog>
{
public const string ExecuteEndpointName = "copy-file-in-bucket";
public async Task<ExecutionResult> Execute(ExecuteContext<CopyFileInBucketArguments> executeContext)
{
try
{
await storageHandler.CopyFileAsync(
executeContext.Arguments.SourceBucket,
executeContext.Arguments.SourceKey,
executeContext.Arguments.DestinationBucket,
executeContext.Arguments.DestinationKey,
executeContext.CancellationToken);
return executeContext.Completed(new CopyFileInBucketLog(
executeContext.Arguments.DestinationBucket,
executeContext.Arguments.DestinationKey));
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy {SourceBucket}/{SourceKey} to {DestinationBucket}/{DestinationKey}",
executeContext.Arguments.SourceBucket,
executeContext.Arguments.SourceKey,
executeContext.Arguments.DestinationBucket,
executeContext.Arguments.DestinationKey);
throw;
}
}
public async Task<CompensationResult> Compensate(CompensateContext<CopyFileInBucketLog> compensateContext)
{
try
{
await storageHandler.RemoveFileAsync(
compensateContext.Log.DestinationBucket,
compensateContext.Log.DestinationKey,
compensateContext.CancellationToken);
return compensateContext.Compensated();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to compensate copied file {Bucket}/{Key}",
compensateContext.Log.DestinationBucket,
compensateContext.Log.DestinationKey);
return compensateContext.Failed(exception);
}
}
}
}
@@ -1,42 +0,0 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Contracts.Infrastructure;
using Musify.Infrastructure.MassTransit.Arguments;
namespace Musify.Infrastructure.MassTransit.Activities.Files
{
internal class RemoveFolderFromBucketActivity(
IStorageService storageHandler,
ILogger<RemoveFolderFromBucketActivity> logger)
: IExecuteActivity<RemoveFolderFromBucketArguments>
{
public const string ExecuteEndpointName = "remove-folder-from-bucket";
public async Task<ExecutionResult> Execute(ExecuteContext<RemoveFolderFromBucketArguments> executeContext)
{
var folderKey = executeContext.GetVariable<string>(executeContext.Arguments.FolderKeyVariable);
ArgumentException.ThrowIfNullOrEmpty(folderKey, nameof(folderKey));
try
{
await storageHandler.RemoveFolderAsync(
executeContext.Arguments.Bucket,
folderKey,
executeContext.CancellationToken);
logger.LogInformation("Removed folder {FolderKey} from bucket {Bucket}",
folderKey,
executeContext.Arguments.Bucket);
return executeContext.Completed();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to remove folder {FolderKey} from bucket {Bucket}",
folderKey,
executeContext.Arguments.Bucket);
throw;
}
}
}
}
@@ -16,8 +16,7 @@ namespace Musify.Infrastructure.MassTransit.Activities
{ {
try try
{ {
var destinationFolderName = Guid.NewGuid().ToString(); var workingDirectory = Path.Combine(executeContext.Arguments.TemporaryRootDirectory, Guid.NewGuid().ToString());
var workingDirectory = Path.Combine(executeContext.Arguments.TemporaryRootDirectory, destinationFolderName);
var sourceFilePath = Path.Combine( var sourceFilePath = Path.Combine(
workingDirectory, Guid.NewGuid().ToString() + Path.GetExtension(executeContext.Arguments.SourceKey)); workingDirectory, Guid.NewGuid().ToString() + Path.GetExtension(executeContext.Arguments.SourceKey));
@@ -38,8 +37,7 @@ namespace Musify.Infrastructure.MassTransit.Activities
[RoutingSlipVariableNames.Picture.OriginalFilePath] = sourceFilePath, [RoutingSlipVariableNames.Picture.OriginalFilePath] = sourceFilePath,
[RoutingSlipVariableNames.Picture.SmallResizedFilePath] = smallPictureFilePath, [RoutingSlipVariableNames.Picture.SmallResizedFilePath] = smallPictureFilePath,
[RoutingSlipVariableNames.Picture.MediumResizedFilePath] = mediumPictureFilePath, [RoutingSlipVariableNames.Picture.MediumResizedFilePath] = mediumPictureFilePath,
[RoutingSlipVariableNames.Picture.LargeResizedFilePath] = largePictureFilePath, [RoutingSlipVariableNames.Picture.LargeResizedFilePath] = largePictureFilePath
[RoutingSlipVariableNames.Picture.DestinationFolderName] = destinationFolderName
} ); } );
} }
catch (Exception exception) catch (Exception exception)
@@ -0,0 +1,34 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.Arguments;
namespace Musify.Infrastructure.MassTransit.Activities.PlayLists
{
internal class PublishPlayListPictureProcessingEventActivity(
IPublishEndpoint publishEndpoint,
ILogger<PublishPlayListPictureProcessingEventActivity> logger)
: IExecuteActivity<PublishPlayListPictureProcessingEventArguments>
{
public const string ExecuteEndpointName = "publish-playList-picture-processing-event";
public async Task<ExecutionResult> Execute(ExecuteContext<PublishPlayListPictureProcessingEventArguments> executeContext)
{
var arguments = executeContext.Arguments;
await publishEndpoint.Publish(
new UpdatePlayListPictureEvent(
arguments.PlayListId,
arguments.Bucket,
arguments.FinalPictureKey,
arguments.Small,
arguments.Medium,
arguments.Large),
executeContext.CancellationToken);
logger.LogInformation("Published picture processing event for playlist {PlayListId}", arguments.PlayListId);
return executeContext.Completed();
}
}
}
@@ -0,0 +1,43 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.Arguments;
namespace Musify.Infrastructure.MassTransit.Activities.Tracks
{
internal class PublishTrackProcessingEventsActivity(
IPublishEndpoint publishEndpoint,
ILogger<PublishTrackProcessingEventsActivity> logger)
: IExecuteActivity<PublishTrackProcessingEventsArguments>
{
public const string ExecuteEndpointName = "publish-track-processing-events";
public async Task<ExecutionResult> Execute(ExecuteContext<PublishTrackProcessingEventsArguments> executeContext)
{
var arguments = executeContext.Arguments;
await publishEndpoint.Publish(
new UpdateTrackPictureEvent(
arguments.TrackId,
arguments.Bucket,
arguments.FinalPictureKey,
arguments.Small,
arguments.Medium,
arguments.Large),
executeContext.CancellationToken);
await publishEndpoint.Publish(
new UpdateTrackAudioEvent(
arguments.TrackId,
arguments.Bucket,
arguments.FinalAudioKey,
arguments.Bucket,
arguments.AudioDestinationFolderKey),
executeContext.CancellationToken);
logger.LogInformation("Published processing events for track {TrackId}", arguments.TrackId);
return executeContext.Completed();
}
}
}
@@ -0,0 +1,62 @@
using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Musify.Application.Contracts.Infrastructure;
using Musify.Domain.Entities;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Logs;
namespace Musify.Infrastructure.MassTransit.Activities.UploadIntents
{
internal class ConsumeUploadIntentsActivity(
IDatabase database,
ILogger<ConsumeUploadIntentsActivity> logger)
: IActivity<ConsumeUploadIntentsArguments, ConsumeUploadIntentsLog>
{
public const string ExecuteEndpointName = "consume-upload-intents";
public async Task<ExecutionResult> Execute(ExecuteContext<ConsumeUploadIntentsArguments> executeContext)
{
var intentIds = executeContext.Arguments.IntentIds;
var intents = await database.UploadIntents
.Where(i => intentIds.Contains(i.Id))
.ToListAsync(executeContext.CancellationToken);
foreach (var intent in intents)
intent.Status = UploadIntentStatus.Consumed;
await database.SaveChangesAsync(executeContext.CancellationToken);
logger.LogInformation("Marked {Count} upload intent(s) as consumed", intents.Count);
return executeContext.Completed(new ConsumeUploadIntentsLog(intentIds));
}
public async Task<CompensationResult> Compensate(CompensateContext<ConsumeUploadIntentsLog> compensateContext)
{
try
{
var intentIds = compensateContext.Log.IntentIds;
var intents = await database.UploadIntents
.Where(i => intentIds.Contains(i.Id))
.ToListAsync(compensateContext.CancellationToken);
foreach (var intent in intents)
intent.Status = UploadIntentStatus.Issued;
await database.SaveChangesAsync(compensateContext.CancellationToken);
logger.LogInformation("Reverted {Count} upload intent(s) back to Issued", intents.Count);
return compensateContext.Compensated();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to compensate upload intent consumption");
return compensateContext.Failed(exception);
}
}
}
}
@@ -0,0 +1,5 @@
namespace Musify.Infrastructure.MassTransit.Arguments
{
public record ConsumeUploadIntentsArguments(
Guid[] IntentIds);
}
@@ -0,0 +1,8 @@
namespace Musify.Infrastructure.MassTransit.Arguments
{
public record CopyFileInBucketArguments(
string SourceBucket,
string SourceKey,
string DestinationBucket,
string DestinationKey);
}
@@ -0,0 +1,12 @@
using Musify.Application.Events;
namespace Musify.Infrastructure.MassTransit.Arguments
{
public record PublishPlayListPictureProcessingEventArguments(
Guid PlayListId,
string Bucket,
string FinalPictureKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -0,0 +1,14 @@
using Musify.Application.Events;
namespace Musify.Infrastructure.MassTransit.Arguments
{
public record PublishTrackProcessingEventsArguments(
Guid TrackId,
string Bucket,
string FinalPictureKey,
string FinalAudioKey,
string AudioDestinationFolderKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -1,6 +0,0 @@
namespace Musify.Infrastructure.MassTransit.Arguments
{
public record RemoveFolderFromBucketArguments(
string Bucket,
string FolderKeyVariable);
}
@@ -0,0 +1,23 @@
using MassTransit;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
namespace Musify.Infrastructure.MassTransit.Consumers
{
public class CreatePlayListConsumer(
IBus bus,
PlayListPictureSourceRoutingSlipBuilder routingSlipBuilder)
: IConsumer<CreatePlayListResourcesEvent>
{
public const string QueueName = "create-playList";
public async Task Consume(ConsumeContext<CreatePlayListResourcesEvent> consumeContext)
{
var routingSlip = routingSlipBuilder
.Build(consumeContext.Message, consumeContext.CorrelationId)
.Build();
await bus.Execute(routingSlip);
}
}
}
@@ -0,0 +1,23 @@
using MassTransit;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
namespace Musify.Infrastructure.MassTransit.Consumers
{
public class CreateTrackConsumer(
IBus bus,
CreateTrackRoutingSlipBuilder routingSlipBuilder)
: IConsumer<CreateTrackResourcesEvent>
{
public const string QueueName = "create-track";
public async Task Consume(ConsumeContext<CreateTrackResourcesEvent> consumeContext)
{
var routingSlip = routingSlipBuilder
.Build(consumeContext.Message, consumeContext.CorrelationId)
.Build();
await bus.Execute(routingSlip);
}
}
}
@@ -0,0 +1,23 @@
using MassTransit;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.RoutingSlip.Builders;
namespace Musify.Infrastructure.MassTransit.Consumers
{
public class UpdatePlayListPictureSourceConsumer(
IBus bus,
PlayListPictureSourceRoutingSlipBuilder routingSlipBuilder)
: IConsumer<UpdatePlayListPictureSourceEvent>
{
public const string QueueName = "update-playList-picture-source";
public async Task Consume(ConsumeContext<UpdatePlayListPictureSourceEvent> consumeContext)
{
var routingSlip = routingSlipBuilder
.Build(consumeContext.Message, consumeContext.CorrelationId)
.Build();
await bus.Execute(routingSlip);
}
}
}
@@ -8,6 +8,7 @@ using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Logs; using Musify.Infrastructure.MassTransit.Activities.Logs;
using Musify.Infrastructure.MassTransit.Activities.PlayLists; using Musify.Infrastructure.MassTransit.Activities.PlayLists;
using Musify.Infrastructure.MassTransit.Activities.Tracks; using Musify.Infrastructure.MassTransit.Activities.Tracks;
using Musify.Infrastructure.MassTransit.Activities.UploadIntents;
using Musify.Infrastructure.MassTransit.Arguments; using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Consumers; using Musify.Infrastructure.MassTransit.Consumers;
using Musify.Infrastructure.MassTransit.Logs; using Musify.Infrastructure.MassTransit.Logs;
@@ -23,6 +24,8 @@ namespace Musify.Infrastructure.MassTransit
services.AddScoped<PictureWorkflowRoutingSlipBuilder>(); services.AddScoped<PictureWorkflowRoutingSlipBuilder>();
services.AddScoped<DeleteTrackRoutingSlipBuilder>(); services.AddScoped<DeleteTrackRoutingSlipBuilder>();
services.AddScoped<DeletePlayListRoutingSlipBuilder>(); services.AddScoped<DeletePlayListRoutingSlipBuilder>();
services.AddScoped<CreateTrackRoutingSlipBuilder>();
services.AddScoped<PlayListPictureSourceRoutingSlipBuilder>();
} }
static void RegisterConsumersAndActivities(IBusRegistrationConfigurator options) static void RegisterConsumersAndActivities(IBusRegistrationConfigurator options)
@@ -33,6 +36,9 @@ namespace Musify.Infrastructure.MassTransit
options.AddConsumer<UpdateTrackAudioConsumer>(); options.AddConsumer<UpdateTrackAudioConsumer>();
options.AddConsumer<DeleteTrackConsumer>(); options.AddConsumer<DeleteTrackConsumer>();
options.AddConsumer<DeletePlayListConsumer>(); options.AddConsumer<DeletePlayListConsumer>();
options.AddConsumer<CreateTrackConsumer>();
options.AddConsumer<CreatePlayListConsumer>();
options.AddConsumer<UpdatePlayListPictureSourceConsumer>();
options.AddExecuteActivity<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>(); options.AddExecuteActivity<RemoveFileFromBucketActivity, RemoveFileFromBucketArguments>();
options.AddExecuteActivity<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>(); options.AddExecuteActivity<GenerateAudioWorkflowPathsActivity, GenerateAudioWorkflowPathsArguments>();
@@ -41,6 +47,8 @@ namespace Musify.Infrastructure.MassTransit
options.AddExecuteActivity<DeleteTrackFromDbActivity, DeleteTrackFromDbArguments>(); options.AddExecuteActivity<DeleteTrackFromDbActivity, DeleteTrackFromDbArguments>();
options.AddExecuteActivity<MarkPlayListAsRemovingActivity, MarkPlayListAsRemovingArguments>(); options.AddExecuteActivity<MarkPlayListAsRemovingActivity, MarkPlayListAsRemovingArguments>();
options.AddExecuteActivity<DeletePlayListFromDbActivity, DeletePlayListFromDbArguments>(); options.AddExecuteActivity<DeletePlayListFromDbActivity, DeletePlayListFromDbArguments>();
options.AddExecuteActivity<PublishTrackProcessingEventsActivity, PublishTrackProcessingEventsArguments>();
options.AddExecuteActivity<PublishPlayListPictureProcessingEventActivity, PublishPlayListPictureProcessingEventArguments>();
options.AddActivity<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>(); options.AddActivity<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>();
options.AddActivity<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>(); options.AddActivity<UpdatePlayListPictureActivity, UpdatePlayListPictureArguments, UpdatePlayListPictureLog>();
@@ -50,6 +58,8 @@ namespace Musify.Infrastructure.MassTransit
options.AddActivity<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>(); options.AddActivity<TransferFilesToBucketActivity, TransferFilesToBucketArguments, TransferFilesToBucketLog>();
options.AddActivity<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>(); options.AddActivity<UpdateTrackAudioActivity, UpdateTrackAudioArguments, UpdateTrackAudioLog>();
options.AddActivity<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>(); options.AddActivity<UploadFileToBucketActivity, UploadFileToBucketArguments, UploadFileToBucketLog>();
options.AddActivity<CopyFileInBucketActivity, CopyFileInBucketArguments, CopyFileInBucketLog>();
options.AddActivity<ConsumeUploadIntentsActivity, ConsumeUploadIntentsArguments, ConsumeUploadIntentsLog>();
} }
static void ConfigureRabbitMqWorkerEndpoints( static void ConfigureRabbitMqWorkerEndpoints(
@@ -85,6 +95,21 @@ namespace Musify.Infrastructure.MassTransit
busRegistrationContext, busRegistrationContext,
DeletePlayListConsumer.QueueName); DeletePlayListConsumer.QueueName);
ConfigureConsumerEndpoint<CreateTrackConsumer>(
busFactoryConfigurator,
busRegistrationContext,
CreateTrackConsumer.QueueName);
ConfigureConsumerEndpoint<CreatePlayListConsumer>(
busFactoryConfigurator,
busRegistrationContext,
CreatePlayListConsumer.QueueName);
ConfigureConsumerEndpoint<UpdatePlayListPictureSourceConsumer>(
busFactoryConfigurator,
busRegistrationContext,
UpdatePlayListPictureSourceConsumer.QueueName);
ConfigureConsumerEndpoint<RoutingSlipCleanUpConsumer>( ConfigureConsumerEndpoint<RoutingSlipCleanUpConsumer>(
busFactoryConfigurator, busFactoryConfigurator,
busRegistrationContext, busRegistrationContext,
@@ -125,6 +150,16 @@ namespace Musify.Infrastructure.MassTransit
busRegistrationContext, busRegistrationContext,
DeletePlayListFromDbActivity.ExecuteEndpointName); DeletePlayListFromDbActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<PublishTrackProcessingEventsActivity, PublishTrackProcessingEventsArguments>(
busFactoryConfigurator,
busRegistrationContext,
PublishTrackProcessingEventsActivity.ExecuteEndpointName);
ConfigureExecuteActivityEndpoint<PublishPlayListPictureProcessingEventActivity, PublishPlayListPictureProcessingEventArguments>(
busFactoryConfigurator,
busRegistrationContext,
PublishPlayListPictureProcessingEventActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>( ConfigureActivityEndpoint<ResizePictureActivity, ResizePictureLocalArguments, ResizePictureLog>(
busFactoryConfigurator, busFactoryConfigurator,
busRegistrationContext, busRegistrationContext,
@@ -164,6 +199,16 @@ namespace Musify.Infrastructure.MassTransit
busFactoryConfigurator, busFactoryConfigurator,
busRegistrationContext, busRegistrationContext,
UploadFileToBucketActivity.ExecuteEndpointName); UploadFileToBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<CopyFileInBucketActivity, CopyFileInBucketArguments, CopyFileInBucketLog>(
busFactoryConfigurator,
busRegistrationContext,
CopyFileInBucketActivity.ExecuteEndpointName);
ConfigureActivityEndpoint<ConsumeUploadIntentsActivity, ConsumeUploadIntentsArguments, ConsumeUploadIntentsLog>(
busFactoryConfigurator,
busRegistrationContext,
ConsumeUploadIntentsActivity.ExecuteEndpointName);
} }
} }
} }
@@ -1,4 +0,0 @@
namespace Musify.Infrastructure.MassTransit.Activities.Logs
{
public record GenerateAudioWorkflowPathsLog(string WorkingDirectory);
}
@@ -2,26 +2,50 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip
{ {
internal static class ActivityNames internal static class ActivityNames
{ {
internal const string DeleteTrack = "DeleteTrack";
internal const string MarkTrackAsRemoving = "MarkTrackAsRemoving"; internal const string MarkTrackAsRemoving = "MarkTrackAsRemoving";
internal const string DeleteTrackFromDb = "DeleteTrackFromDb"; internal const string DeleteTrackFromDb = "DeleteTrackFromDb";
internal const string MarkPlayListAsRemoving = "MarkPlayListAsRemoving"; internal const string MarkPlayListAsRemoving = "MarkPlayListAsRemoving";
internal const string DeletePlayListFromDb = "DeletePlayListFromDb"; internal const string DeletePlayListFromDb = "DeletePlayListFromDb";
internal const string GenerateAudioWorkflowPaths = "GenerateAudioWorkflowPaths"; internal const string GenerateAudioWorkflowPaths = "GenerateAudioWorkflowPaths";
internal const string GeneratePictureWorkflowPaths = "GeneratePictureWorkflowPaths"; internal const string GeneratePictureWorkflowPaths = "GeneratePictureWorkflowPaths";
internal const string DownloadFile = "DownloadFile"; internal const string DownloadFile = "DownloadFile";
internal const string TranscodeAudio = "TranscodeAudio"; internal const string TranscodeAudio = "TranscodeAudio";
internal const string ResizeSmall = "ResizeSmall"; internal const string ResizeSmall = "ResizeSmall";
internal const string ResizeMedium = "ResizeMedium"; internal const string ResizeMedium = "ResizeMedium";
internal const string ResizeLarge = "ResizeLarge"; internal const string ResizeLarge = "ResizeLarge";
internal const string UploadSmall = "UploadSmall"; internal const string UploadSmall = "UploadSmall";
internal const string UploadMedium = "UploadMedium"; internal const string UploadMedium = "UploadMedium";
internal const string UploadLarge = "UploadLarge"; internal const string UploadLarge = "UploadLarge";
internal const string TransferFiles = "TransferFiles"; internal const string TransferFiles = "TransferFiles";
internal const string RemoveFile = "RemoveFile";
internal const string DeleteOriginal = "DeleteOriginal";
internal const string UpdateTrackPicture = "UpdateTrackPicture"; internal const string UpdateTrackPicture = "UpdateTrackPicture";
internal const string UpdatePlayListPicture = "UpdatePlayListPicture"; internal const string UpdatePlayListPicture = "UpdatePlayListPicture";
internal const string UpdateTrackAudio = "UpdateTrackAudio"; internal const string UpdateTrackAudio = "UpdateTrackAudio";
internal const string CopyPictureToFinal = "CopyPictureToFinal";
internal const string CopyAudioToFinal = "CopyAudioToFinal";
internal const string ConsumeUploadIntents = "ConsumeUploadIntents";
internal const string PublishTrackProcessingEvents = "PublishTrackProcessingEvents";
internal const string PublishPlayListPictureProcessingEvent = "PublishPlayListPictureProcessingEvent";
internal const string RemoveTrackOriginalPicture = "RemoveTrackOriginalPicture";
internal const string RemoveTrackSmallPicture = "RemoveTrackSmallPicture";
internal const string RemoveTrackMediumPicture = "RemoveTrackMediumPicture";
internal const string RemoveTrackLargePicture = "RemoveTrackLargePicture";
internal const string RemoveTrackOriginalAudio = "RemoveTrackOriginalAudio";
internal const string RemoveTrackProcessedAudio = "RemoveTrackProcessedAudio";
internal const string RemovePlayListOriginalPicture = "RemovePlayListOriginalPicture";
internal const string RemovePlayListSmallPicture = "RemovePlayListSmallPicture";
internal const string RemovePlayListMediumPicture = "RemovePlayListMediumPicture";
internal const string RemovePlayListLargePicture = "RemovePlayListLargePicture";
} }
} }
@@ -0,0 +1,63 @@
using MassTransit;
using MassTransit.Courier.Contracts;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Tracks;
using Musify.Infrastructure.MassTransit.Activities.UploadIntents;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Consumers;
namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
{
public class CreateTrackRoutingSlipBuilder
{
public RoutingSlipBuilder Build(CreateTrackResourcesEvent message, Guid? correlationId)
{
var routingSlipBuilder = new RoutingSlipBuilder(NewId.NextGuid());
routingSlipBuilder.AddVariable(RoutingSlipVariableNames.Workflow.CorrelationId, correlationId ?? Guid.Empty);
routingSlipBuilder.AddSubscription(
EndpointHelper.BuildConsumerUri(RoutingSlipCleanUpConsumer.QueueName),
RoutingSlipEvents.Completed | RoutingSlipEvents.Faulted);
routingSlipBuilder.AddActivity(
ActivityNames.CopyPictureToFinal,
EndpointHelper.BuildExecuteActivityUri(CopyFileInBucketActivity.ExecuteEndpointName),
new CopyFileInBucketArguments(
message.Bucket,
message.PictureSourceKey,
message.Bucket,
message.PictureDestinationKey));
routingSlipBuilder.AddActivity(
ActivityNames.CopyAudioToFinal,
EndpointHelper.BuildExecuteActivityUri(CopyFileInBucketActivity.ExecuteEndpointName),
new CopyFileInBucketArguments(
message.Bucket,
message.AudioSourceKey,
message.Bucket,
message.AudioDestinationKey));
routingSlipBuilder.AddActivity(
ActivityNames.ConsumeUploadIntents,
EndpointHelper.BuildExecuteActivityUri(ConsumeUploadIntentsActivity.ExecuteEndpointName),
new ConsumeUploadIntentsArguments(
[message.PictureIntentId, message.AudioIntentId]));
routingSlipBuilder.AddActivity(
ActivityNames.PublishTrackProcessingEvents,
EndpointHelper.BuildExecuteActivityUri(PublishTrackProcessingEventsActivity.ExecuteEndpointName),
new PublishTrackProcessingEventsArguments(
message.TrackId,
message.Bucket,
message.PictureDestinationKey,
message.AudioDestinationKey,
message.AudioProcessedFolderKey,
message.Small,
message.Medium,
message.Large));
return routingSlipBuilder;
}
}
}
@@ -45,7 +45,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (playList.OriginalPictureName != routes.PresetOriginalPicture) if (playList.OriginalPictureName != routes.PresetOriginalPicture)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemovePlayListOriginalPicture", ActivityNames.RemovePlayListOriginalPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -55,7 +55,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (playList.SmallPictureName != routes.PresetSmallPicture) if (playList.SmallPictureName != routes.PresetSmallPicture)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemovePlayListSmallPicture", ActivityNames.RemovePlayListSmallPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -65,7 +65,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (playList.MediumPictureName != routes.PresetMediumPicture) if (playList.MediumPictureName != routes.PresetMediumPicture)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemovePlayListMediumPicture", ActivityNames.RemovePlayListMediumPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -75,7 +75,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (playList.LargePictureName != routes.PresetLargePicture) if (playList.LargePictureName != routes.PresetLargePicture)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemovePlayListLargePicture", ActivityNames.RemovePlayListLargePicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -3,8 +3,8 @@ using MassTransit.Courier.Contracts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Musify.Application.Contracts.Infrastructure; using Musify.Application.Contracts.Infrastructure;
using Musify.Application.Configuration; using Musify.Application.Configuration;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Arguments; using Musify.Infrastructure.MassTransit.Activities.Arguments;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.Tracks; using Musify.Infrastructure.MassTransit.Activities.Tracks;
using Musify.Infrastructure.MassTransit.Consumers; using Musify.Infrastructure.MassTransit.Consumers;
@@ -42,7 +42,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
var bucket = storageConfiguration.Bucket; var bucket = storageConfiguration.Bucket;
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackOriginalPicture", ActivityNames.RemoveTrackOriginalPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -51,21 +51,21 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (track.IsPicturesProcessed) if (track.IsPicturesProcessed)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackSmallPicture", ActivityNames.RemoveTrackSmallPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
trackConfiguration.Routes.BuildSmallPicturePath(track.SmallPictureName))); trackConfiguration.Routes.BuildSmallPicturePath(track.SmallPictureName)));
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackMediumPicture", ActivityNames.RemoveTrackMediumPicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
trackConfiguration.Routes.BuildMediumPicturePath(track.MediumPictureName))); trackConfiguration.Routes.BuildMediumPicturePath(track.MediumPictureName)));
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackLargePicture", ActivityNames.RemoveTrackLargePicture,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -73,7 +73,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
} }
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackOriginalAudio", ActivityNames.RemoveTrackOriginalAudio,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -82,7 +82,7 @@ namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
if (track.IsAudioProcessed) if (track.IsAudioProcessed)
{ {
routingSlipBuilder.AddActivity( routingSlipBuilder.AddActivity(
"RemoveTrackProcessedAudio", ActivityNames.RemoveTrackProcessedAudio,
EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName), EndpointHelper.BuildExecuteActivityUri(RemoveFileFromBucketActivity.ExecuteEndpointName),
new RemoveFileFromBucketArguments( new RemoveFileFromBucketArguments(
bucket, bucket,
@@ -0,0 +1,84 @@
using MassTransit;
using MassTransit.Courier.Contracts;
using Musify.Application.Events;
using Musify.Infrastructure.MassTransit.Activities.Files;
using Musify.Infrastructure.MassTransit.Activities.PlayLists;
using Musify.Infrastructure.MassTransit.Activities.UploadIntents;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.MassTransit.Consumers;
namespace Musify.Infrastructure.MassTransit.RoutingSlip.Builders
{
public class PlayListPictureSourceRoutingSlipBuilder
{
public RoutingSlipBuilder Build(CreatePlayListResourcesEvent message, Guid? correlationId)
=> BuildSlip(
message.PlayListId,
message.PictureIntentId,
message.Bucket,
message.PictureSourceKey,
message.PictureDestinationKey,
message.Small,
message.Medium,
message.Large,
correlationId);
public RoutingSlipBuilder Build(UpdatePlayListPictureSourceEvent message, Guid? correlationId)
=> BuildSlip(
message.PlayListId,
message.PictureIntentId,
message.Bucket,
message.PictureSourceKey,
message.PictureDestinationKey,
message.Small,
message.Medium,
message.Large,
correlationId);
static RoutingSlipBuilder BuildSlip(
Guid playListId,
Guid pictureIntentId,
string bucket,
string pictureSourceKey,
string pictureDestinationKey,
ImageSize small,
ImageSize medium,
ImageSize large,
Guid? correlationId)
{
var routingSlipBuilder = new RoutingSlipBuilder(NewId.NextGuid());
routingSlipBuilder.AddVariable(RoutingSlipVariableNames.Workflow.CorrelationId, correlationId ?? Guid.Empty);
routingSlipBuilder.AddSubscription(
EndpointHelper.BuildConsumerUri(RoutingSlipCleanUpConsumer.QueueName),
RoutingSlipEvents.Completed | RoutingSlipEvents.Faulted);
routingSlipBuilder.AddActivity(
ActivityNames.CopyPictureToFinal,
EndpointHelper.BuildExecuteActivityUri(CopyFileInBucketActivity.ExecuteEndpointName),
new CopyFileInBucketArguments(
bucket,
pictureSourceKey,
bucket,
pictureDestinationKey));
routingSlipBuilder.AddActivity(
ActivityNames.ConsumeUploadIntents,
EndpointHelper.BuildExecuteActivityUri(ConsumeUploadIntentsActivity.ExecuteEndpointName),
new ConsumeUploadIntentsArguments([pictureIntentId]));
routingSlipBuilder.AddActivity(
ActivityNames.PublishPlayListPictureProcessingEvent,
EndpointHelper.BuildExecuteActivityUri(PublishPlayListPictureProcessingEventActivity.ExecuteEndpointName),
new PublishPlayListPictureProcessingEventArguments(
playListId,
bucket,
pictureDestinationKey,
small,
medium,
large));
return routingSlipBuilder;
}
}
}
@@ -11,9 +11,7 @@ namespace Musify.Infrastructure.MassTransit
internal static class Audio internal static class Audio
{ {
internal const string SourceFilePath = "Audio.SourceFilePath"; internal const string SourceFilePath = "Audio.SourceFilePath";
internal const string WorkingDirectory = "Audio.WorkingDirectory";
internal const string TranscodedDirectory = "Audio.TranscodedDirectory"; internal const string TranscodedDirectory = "Audio.TranscodedDirectory";
internal const string PreviousAudioFolderName = "Audio.PreviousAudioFolderName";
} }
internal static class Picture internal static class Picture
@@ -22,7 +20,6 @@ namespace Musify.Infrastructure.MassTransit
internal const string SmallResizedFilePath = "Picture.SmallResizedFilePath"; internal const string SmallResizedFilePath = "Picture.SmallResizedFilePath";
internal const string MediumResizedFilePath = "Picture.MediumResizedFilePath"; internal const string MediumResizedFilePath = "Picture.MediumResizedFilePath";
internal const string LargeResizedFilePath = "Picture.LargeResizedFilePath"; internal const string LargeResizedFilePath = "Picture.LargeResizedFilePath";
internal const string DestinationFolderName = "Picture.DestinationFolderName";
} }
} }
} }