diff --git a/docker/start.sh b/docker/start.sh new file mode 100755 index 0000000..29e508d --- /dev/null +++ b/docker/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker compose -p aips --env-file ../.env up diff --git a/dotnet/AipsCore/AipsCore.csproj b/dotnet/AipsCore/AipsCore.csproj index fbd60df..a733dcb 100644 --- a/dotnet/AipsCore/AipsCore.csproj +++ b/dotnet/AipsCore/AipsCore.csproj @@ -16,6 +16,7 @@ + diff --git a/dotnet/AipsCore/Application/Abstract/MessageBroking/IMessagePublisher.cs b/dotnet/AipsCore/Application/Abstract/MessageBroking/IMessagePublisher.cs new file mode 100644 index 0000000..c631d91 --- /dev/null +++ b/dotnet/AipsCore/Application/Abstract/MessageBroking/IMessagePublisher.cs @@ -0,0 +1,6 @@ +namespace AipsCore.Application.Abstract.MessageBroking; + +public interface IMessagePublisher +{ + Task PublishAsync(T message, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/dotnet/AipsCore/Infrastructure/DI/AipsRegistrationExtensions.cs b/dotnet/AipsCore/Infrastructure/DI/AipsRegistrationExtensions.cs index 351ea14..49101de 100644 --- a/dotnet/AipsCore/Infrastructure/DI/AipsRegistrationExtensions.cs +++ b/dotnet/AipsCore/Infrastructure/DI/AipsRegistrationExtensions.cs @@ -1,5 +1,7 @@ using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Common.Dispatcher; +using AipsCore.Infrastructure.MessageBroking.RabbitMQ; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -15,6 +17,9 @@ public static class AipsRegistrationExtensions services.AddPersistence(configuration); services.AddUserContext(configuration); + + services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/dotnet/AipsCore/Infrastructure/DI/Configuration/ConfigurationEnvExtensions.cs b/dotnet/AipsCore/Infrastructure/DI/Configuration/ConfigurationEnvExtensions.cs index 8c56742..da94672 100644 --- a/dotnet/AipsCore/Infrastructure/DI/Configuration/ConfigurationEnvExtensions.cs +++ b/dotnet/AipsCore/Infrastructure/DI/Configuration/ConfigurationEnvExtensions.cs @@ -6,6 +6,9 @@ public static class ConfigurationEnvExtensions { private const string DbConnStringKey = "DB_CONN_STRING"; + private const string RabbitMqAmqpUriKey = "RABBITMQ_AMQP_URI"; + private const string RabbitMqExchange = "RABBITMQ_EXCHANGE"; + private const string JwtIssuer = "JWT_ISSUER"; private const string JwtAudience = "JWT_AUDIENCE"; private const string JwtKey = "JWT_KEY"; @@ -18,6 +21,16 @@ public static class ConfigurationEnvExtensions return configuration.GetEnvForSure(DbConnStringKey); } + public string GetEnvRabbitMqAmqpUri() + { + return configuration.GetEnvForSure(RabbitMqAmqpUriKey); + } + + public string GetEnvRabbitMqExchange() + { + return configuration.GetEnvForSure(RabbitMqExchange); + } + public string GetEnvJwtIssuer() { return configuration.GetEnvForSure(JwtIssuer); diff --git a/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/IRabbitMQConnection.cs b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/IRabbitMQConnection.cs new file mode 100644 index 0000000..d4d0efb --- /dev/null +++ b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/IRabbitMQConnection.cs @@ -0,0 +1,8 @@ +using RabbitMQ.Client; + +namespace AipsCore.Infrastructure.MessageBroking.RabbitMQ; + +public interface IRabbitMqConnection +{ + Task CreateChannelAsync(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqConnection.cs b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqConnection.cs new file mode 100644 index 0000000..0a41c8d --- /dev/null +++ b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqConnection.cs @@ -0,0 +1,44 @@ +using AipsCore.Infrastructure.DI.Configuration; +using Microsoft.Extensions.Configuration; +using RabbitMQ.Client; + +namespace AipsCore.Infrastructure.MessageBroking.RabbitMQ; + +public class RabbitMqConnection : IRabbitMqConnection +{ + private readonly IConfiguration _configuration; + private IConnection? _connection; + + public RabbitMqConnection(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task CreateChannelAsync(CancellationToken cancellationToken = default) + { + if (_connection is null) + { + await CreateConnectionAsync(); + //throw new InvalidOperationException($"RabbitMQ connection not created for {_configuration.GetEnvRabbitMqAmqpUri()}"); + } + + return await _connection!.CreateChannelAsync(null, cancellationToken); + } + + public async Task CreateConnectionAsync() + { + var factory = CreateConnectionFactory(); + + _connection = await factory.CreateConnectionAsync(); + } + + private IConnectionFactory CreateConnectionFactory() + { + var factory = new ConnectionFactory + { + Uri = new Uri(_configuration.GetEnvRabbitMqAmqpUri()) + }; + + return factory; + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqPublisher.cs b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqPublisher.cs new file mode 100644 index 0000000..c7d7dfa --- /dev/null +++ b/dotnet/AipsCore/Infrastructure/MessageBroking/RabbitMQ/RabbitMqPublisher.cs @@ -0,0 +1,44 @@ +using System.Text; +using System.Text.Json; +using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; +using AipsCore.Infrastructure.DI.Configuration; +using Microsoft.Extensions.Configuration; +using RabbitMQ.Client; + +namespace AipsCore.Infrastructure.MessageBroking.RabbitMQ; + +public class RabbitMqPublisher : IMessagePublisher +{ + private readonly IRabbitMqConnection _connection; + private readonly IConfiguration _configuration; + + public RabbitMqPublisher(IRabbitMqConnection connection, IConfiguration configuration) + { + _connection = connection; + _configuration = configuration; + } + + public async Task PublishAsync(T message, CancellationToken cancellationToken = default) + { + var channel = await _connection.CreateChannelAsync(cancellationToken); + + await channel.ExchangeDeclareAsync(GetExchange(), ExchangeType.Topic, durable: true, cancellationToken: cancellationToken); + + var bytes = Serialize(message); + await channel.BasicPublishAsync( + GetExchange(), + typeof(T).Name, + bytes, + cancellationToken); + + await channel.CloseAsync(cancellationToken); + } + + private byte[] Serialize(T message) + { + return JsonSerializer.SerializeToUtf8Bytes(message); + } + + private string GetExchange() => _configuration.GetEnvRabbitMqExchange(); +} \ No newline at end of file diff --git a/dotnet/AipsWebApi/Controllers/UserController.cs b/dotnet/AipsWebApi/Controllers/UserController.cs index 746887f..7c3f705 100644 --- a/dotnet/AipsWebApi/Controllers/UserController.cs +++ b/dotnet/AipsWebApi/Controllers/UserController.cs @@ -1,4 +1,5 @@ using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.MessageBroking; using AipsCore.Application.Common.Authentication; using AipsCore.Application.Models.User.Command.LogIn; using AipsCore.Application.Models.User.Command.SignUp; @@ -34,4 +35,11 @@ public class UserController : ControllerBase var result = await _dispatcher.Execute(command, cancellationToken); return Ok(result.Value); } + + [AllowAnonymous] + [HttpPost("test")] + public async Task Test(IMessagePublisher publisher) + { + await publisher.PublishAsync("Test poruka"); + } } \ No newline at end of file