diff --git a/dotnet/AipsCore/Application/Abstract/IWhiteboardAwareContext.cs b/dotnet/AipsCore/Application/Abstract/IWhiteboardAwareContext.cs new file mode 100644 index 0000000..a391986 --- /dev/null +++ b/dotnet/AipsCore/Application/Abstract/IWhiteboardAwareContext.cs @@ -0,0 +1,6 @@ +namespace AipsCore.Application.Abstract; + +public interface IWhiteboardAwareContext +{ + Guid GetWhiteboardId(); +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/AddArrow/AddArrowMessage.cs b/dotnet/AipsCore/Application/Common/Message/AddArrow/AddArrowMessage.cs index ee857f3..e9920b7 100644 --- a/dotnet/AipsCore/Application/Common/Message/AddArrow/AddArrowMessage.cs +++ b/dotnet/AipsCore/Application/Common/Message/AddArrow/AddArrowMessage.cs @@ -1,6 +1,13 @@ +using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Models.Shape.Command.CreateArrow; namespace AipsCore.Application.Common.Message.AddArrow; -public record AddArrowMessage(CreateArrowCommand Command) : IMessage; \ No newline at end of file +public record AddArrowMessage(CreateArrowCommand Command) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return Guid.Parse(Command.WhiteboardId); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/AddLine/AddLineMessage.cs b/dotnet/AipsCore/Application/Common/Message/AddLine/AddLineMessage.cs index e7769b5..19060c8 100644 --- a/dotnet/AipsCore/Application/Common/Message/AddLine/AddLineMessage.cs +++ b/dotnet/AipsCore/Application/Common/Message/AddLine/AddLineMessage.cs @@ -1,6 +1,13 @@ +using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Models.Shape.Command.CreateLine; namespace AipsCore.Application.Common.Message.AddLine; -public record AddLineMessage(CreateLineCommand Command) : IMessage; \ No newline at end of file +public record AddLineMessage(CreateLineCommand Command) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return Guid.Parse(Command.WhiteboardId); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/AddRectangle/AddRectangleMessage.cs b/dotnet/AipsCore/Application/Common/Message/AddRectangle/AddRectangleMessage.cs index 0277ee1..a406708 100644 --- a/dotnet/AipsCore/Application/Common/Message/AddRectangle/AddRectangleMessage.cs +++ b/dotnet/AipsCore/Application/Common/Message/AddRectangle/AddRectangleMessage.cs @@ -1,6 +1,13 @@ +using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Models.Shape.Command.CreateRectangle; namespace AipsCore.Application.Common.Message.AddRectangle; -public record AddRectangleMessage(CreateRectangleCommand Command) : IMessage; \ No newline at end of file +public record AddRectangleMessage(CreateRectangleCommand Command) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return Guid.Parse(Command.WhiteboardId); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/AddTextShape/AddTextShapeMessage.cs b/dotnet/AipsCore/Application/Common/Message/AddTextShape/AddTextShapeMessage.cs index d65a896..3366057 100644 --- a/dotnet/AipsCore/Application/Common/Message/AddTextShape/AddTextShapeMessage.cs +++ b/dotnet/AipsCore/Application/Common/Message/AddTextShape/AddTextShapeMessage.cs @@ -1,6 +1,13 @@ +using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Models.Shape.Command.CreateTextShape; namespace AipsCore.Application.Common.Message.AddTextShape; -public record AddTextShapeMessage(CreateTextShapeCommand Command) : IMessage; \ No newline at end of file +public record AddTextShapeMessage(CreateTextShapeCommand Command) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return Guid.Parse(Command.WhiteboardId); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessage.cs b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessage.cs new file mode 100644 index 0000000..18e411e --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessage.cs @@ -0,0 +1,13 @@ +using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; +using AipsCore.Domain.Common.Validation; + +namespace AipsCore.Application.Common.Message.ErrorMessage; + +public record ErrorMessage(Guid WhiteboardId, ICollection Errors) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return WhiteboardId; + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessageHandler.cs b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessageHandler.cs new file mode 100644 index 0000000..d1e2152 --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/ErrorMessageHandler.cs @@ -0,0 +1,18 @@ +using AipsCore.Application.Abstract.MessageBroking; + +namespace AipsCore.Application.Common.Message.ErrorMessage; + +public class ErrorMessageHandler : IMessageHandler +{ + private readonly IErrorMessageHandleStrategy _handleStrategy; + + public ErrorMessageHandler(IErrorMessageHandleStrategy handleStrategy) + { + _handleStrategy = handleStrategy; + } + + public async Task Handle(ErrorMessage message, CancellationToken cancellationToken) + { + await _handleStrategy.Handle(message, cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/ErrorMessage/IErrorMessageHandleStrategy.cs b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/IErrorMessageHandleStrategy.cs new file mode 100644 index 0000000..027710c --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Message/ErrorMessage/IErrorMessageHandleStrategy.cs @@ -0,0 +1,6 @@ +namespace AipsCore.Application.Common.Message.ErrorMessage; + +public interface IErrorMessageHandleStrategy +{ + Task Handle(ErrorMessage message, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Message/MoveShape/MoveShapeMessage.cs b/dotnet/AipsCore/Application/Common/Message/MoveShape/MoveShapeMessage.cs index eb97ad7..8eb27b7 100644 --- a/dotnet/AipsCore/Application/Common/Message/MoveShape/MoveShapeMessage.cs +++ b/dotnet/AipsCore/Application/Common/Message/MoveShape/MoveShapeMessage.cs @@ -1,6 +1,13 @@ +using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Models.Shape.Command.MoveShape; namespace AipsCore.Application.Common.Message.MoveShape; -public record MoveShapeMessage(MoveShapeCommand Command) : IMessage; \ No newline at end of file +public record MoveShapeMessage(Guid WhiteboardId, MoveShapeCommand Command) : IMessage, IWhiteboardAwareContext +{ + public Guid GetWhiteboardId() + { + return WhiteboardId; + } +} \ No newline at end of file diff --git a/dotnet/AipsRT/Hubs/WhiteboardHub.cs b/dotnet/AipsRT/Hubs/WhiteboardHub.cs index ec22db5..38e49f7 100644 --- a/dotnet/AipsRT/Hubs/WhiteboardHub.cs +++ b/dotnet/AipsRT/Hubs/WhiteboardHub.cs @@ -25,7 +25,7 @@ public class WhiteboardHub : Hub public async Task JoinWhiteboard(Guid whiteboardId) { if (!_whiteboardManager.WhiteboardExists(whiteboardId)) - await _whiteboardManager.AddWhiteboard(whiteboardId); + await _whiteboardManager.LoadWhiteboard(whiteboardId); await Groups.AddToGroupAsync(Context.ConnectionId, whiteboardId.ToString()); @@ -127,6 +127,6 @@ public class WhiteboardHub : Hub { await MoveShape(moveShape); - await _messagingService.MoveShape(moveShape); + await _messagingService.MoveShape(CurrentWhiteboard.WhiteboardId, moveShape); } } \ No newline at end of file diff --git a/dotnet/AipsRT/Model/Whiteboard/WhiteboardManager.cs b/dotnet/AipsRT/Model/Whiteboard/WhiteboardManager.cs index 10c19dc..75125e6 100644 --- a/dotnet/AipsRT/Model/Whiteboard/WhiteboardManager.cs +++ b/dotnet/AipsRT/Model/Whiteboard/WhiteboardManager.cs @@ -14,7 +14,7 @@ public class WhiteboardManager _scopeFactory = scopeFactory; } - public async Task AddWhiteboard(Guid whiteboardId) + public async Task LoadWhiteboard(Guid whiteboardId) { var getWhiteboardService = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService(); var whiteboard = await getWhiteboardService.GetWhiteboard(whiteboardId); diff --git a/dotnet/AipsRT/Program.cs b/dotnet/AipsRT/Program.cs index 0995a0a..97c3f0b 100644 --- a/dotnet/AipsRT/Program.cs +++ b/dotnet/AipsRT/Program.cs @@ -1,3 +1,4 @@ +using AipsCore.Application.Common.Message.ErrorMessage; using AipsCore.Infrastructure.DI; using AipsRT.Hubs; using AipsRT.Model.Whiteboard; @@ -15,6 +16,10 @@ builder.Configuration.AddEnvironmentVariables(); builder.Services.AddSignalR(); builder.Services.AddAips(builder.Configuration); +builder.Services.AddAipsMessageHandlers(); + +builder.Services.AddSingleton(); +builder.Services.AddHostedService(); builder.Services.AddScoped(); builder.Services.AddSingleton(); diff --git a/dotnet/AipsRT/Services/ErrorSubscriberBackgroundService.cs b/dotnet/AipsRT/Services/ErrorSubscriberBackgroundService.cs new file mode 100644 index 0000000..36146df --- /dev/null +++ b/dotnet/AipsRT/Services/ErrorSubscriberBackgroundService.cs @@ -0,0 +1,25 @@ +using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; +using AipsCore.Application.Common.Message.ErrorMessage; + +namespace AipsRT.Services; + +public class ErrorSubscriberBackgroundService : BackgroundService +{ + private readonly IMessageSubscriber _subscriber; + private readonly IDispatcher _dispatcher; + + public ErrorSubscriberBackgroundService(IMessageSubscriber subscriber, IDispatcher dispatcher) + { + _subscriber = subscriber; + _dispatcher = dispatcher; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await _subscriber.SubscribeAsync(async (errorMessage, ct) => + { + await _dispatcher.Execute(errorMessage, ct); + }); + } +} \ No newline at end of file diff --git a/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs b/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs index 3bbf790..97838e0 100644 --- a/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs +++ b/dotnet/AipsRT/Services/Interfaces/IMessagingService.cs @@ -11,5 +11,5 @@ public interface IMessagingService Task CreateLine(Guid whiteboardId, Line line); Task CreateTextShape(Guid whiteboardId, TextShape textShape); - Task MoveShape(MoveShapeCommand moveShape); + Task MoveShape(Guid whiteboardId, MoveShapeCommand moveShape); } \ No newline at end of file diff --git a/dotnet/AipsRT/Services/MessagingService.cs b/dotnet/AipsRT/Services/MessagingService.cs index 3ad2aa6..3f139bd 100644 --- a/dotnet/AipsRT/Services/MessagingService.cs +++ b/dotnet/AipsRT/Services/MessagingService.cs @@ -95,9 +95,9 @@ public class MessagingService : IMessagingService await _messagePublisher.PublishAsync(message); } - public async Task MoveShape(MoveShapeCommand moveShape) + public async Task MoveShape(Guid whiteboardId, MoveShapeCommand moveShape) { - var message = new MoveShapeMessage(moveShape); + var message = new MoveShapeMessage(whiteboardId, moveShape); await _messagePublisher.PublishAsync(message); } } \ No newline at end of file diff --git a/dotnet/AipsRT/Services/RtErrorHandleStrategy.cs b/dotnet/AipsRT/Services/RtErrorHandleStrategy.cs new file mode 100644 index 0000000..3f14796 --- /dev/null +++ b/dotnet/AipsRT/Services/RtErrorHandleStrategy.cs @@ -0,0 +1,29 @@ +using AipsCore.Application.Common.Message.ErrorMessage; +using AipsRT.Hubs; +using AipsRT.Model.Whiteboard; +using Microsoft.AspNetCore.SignalR; + +namespace AipsRT.Services; + +public class RtErrorHandleStrategy : IErrorMessageHandleStrategy +{ + private readonly IHubContext _hubContext; + private readonly WhiteboardManager _whiteboardManager; + + public RtErrorHandleStrategy(IHubContext hubContext, WhiteboardManager whiteboardManager) + { + _hubContext = hubContext; + _whiteboardManager = whiteboardManager; + } + + public async Task Handle(ErrorMessage message, CancellationToken cancellationToken) + { + await _whiteboardManager.LoadWhiteboard(message.WhiteboardId); + + var whiteboard = _whiteboardManager.GetWhiteboard(message.WhiteboardId)!; + + await _hubContext.Clients + .Group(whiteboard.WhiteboardId.ToString()) + .SendAsync("InitWhiteboard", whiteboard, cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsWorker/WorkerService.cs b/dotnet/AipsWorker/WorkerService.cs index 5f6d8a8..b7689ec 100644 --- a/dotnet/AipsWorker/WorkerService.cs +++ b/dotnet/AipsWorker/WorkerService.cs @@ -1,6 +1,7 @@ using System.Reflection; using AipsCore.Application.Abstract; using AipsCore.Application.Abstract.MessageBroking; +using AipsCore.Application.Common.Message.ErrorMessage; using AipsCore.Application.Common.Message.TestMessage; using AipsCore.Domain.Common.Validation; using AipsWorker.Utilities; @@ -12,12 +13,14 @@ public class WorkerService : BackgroundService { private readonly IDispatcher _dispatcher; private readonly IMessageTypesProvider _messageTypesProvider; + private readonly IMessagePublisher _publisher; private readonly SubscribeMethodUtility _subscribeMethodUtility; - public WorkerService(IMessageSubscriber subscriber, IDispatcher dispatcher, IMessageTypesProvider messageTypesProvider) + public WorkerService(IMessageSubscriber subscriber, IDispatcher dispatcher, IMessageTypesProvider messageTypesProvider, IMessagePublisher publisher) { _dispatcher = dispatcher; _messageTypesProvider = messageTypesProvider; + _publisher = publisher; _subscribeMethodUtility = new SubscribeMethodUtility(subscriber); } @@ -37,15 +40,26 @@ public class WorkerService : BackgroundService private async Task HandleMessage(T message, CancellationToken ct) where T : IMessage { + Console.WriteLine($"*--------{message.GetType().Name}--------*"); + try { await _dispatcher.Execute(message, ct); - Console.WriteLine($"OK: {message.GetType().Name}"); + Console.WriteLine("OK!"); } catch (ValidationException validationException) { - Console.WriteLine("===Validation Exception: "); + if (message is IWhiteboardAwareContext) + { + var whiteboardId = ((IWhiteboardAwareContext)message).GetWhiteboardId(); + + var errorMessage = new ErrorMessage(whiteboardId, validationException.ValidationErrors); + + await _publisher.PublishAsync(errorMessage, ct); + } + + Console.WriteLine("Validation Exception: "); foreach (var error in validationException.ValidationErrors) { Console.WriteLine(" * Code: " + error.Code); diff --git a/front/src/stores/whiteboard.ts b/front/src/stores/whiteboard.ts index 758f350..01c7c17 100644 --- a/front/src/stores/whiteboard.ts +++ b/front/src/stores/whiteboard.ts @@ -36,6 +36,7 @@ export const useWhiteboardStore = defineStore('whiteboard', () => { isConnected.value = true whiteboardHubService.onInitWhiteboard((wb) => { + deselectShape() whiteboard.value = wb isLoading.value = false })