Merge branch 'main' into feature-refresh-tokens

# Conflicts:
#	dotnet/AipsWebApi/Controllers/UserController.cs
This commit is contained in:
Veljko Tosic
2026-02-14 18:55:55 +01:00
9 changed files with 133 additions and 0 deletions

View File

@@ -16,6 +16,7 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<PackageReference Include="RabbitMQ.Client" Version="7.2.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,6 @@
namespace AipsCore.Application.Abstract.MessageBroking;
public interface IMessagePublisher
{
Task PublishAsync<T>(T message, CancellationToken cancellationToken = default);
}

View File

@@ -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<IRabbitMqConnection, RabbitMqConnection>();
services.AddSingleton<IMessagePublisher, RabbitMqPublisher>();
return services;
}

View File

@@ -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";
@@ -19,6 +22,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);

View File

@@ -0,0 +1,8 @@
using RabbitMQ.Client;
namespace AipsCore.Infrastructure.MessageBroking.RabbitMQ;
public interface IRabbitMqConnection
{
Task<IChannel> CreateChannelAsync(CancellationToken cancellationToken = default);
}

View File

@@ -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<IChannel> 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;
}
}

View File

@@ -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>(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>(T message)
{
return JsonSerializer.SerializeToUtf8Bytes(message);
}
private string GetExchange() => _configuration.GetEnvRabbitMqExchange();
}