using System; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using RabbitMQ.Client; using xCommons.Extensions; using xEventService.Configuration; using xEventService.Constants; using xEventService.Extensions; using xEventService.Interfaces; using xEventService.Models; using xExceptions.Constants; namespace xEventService.Providers { /// /// RabbitMQ Producer Service Implementation ... /// public class XRabbitMQProducerService : IXRabbitMQProducerService { private IModel channel; private IConnection connection; private readonly object connectionLock = new(); private readonly ILogger logger; private readonly XEventServiceConfiguration configuration; public XRabbitMQProducerService( ILogger logger, XEventServiceConfiguration configuration ) { // this.logger = logger; this.configuration = configuration; // // Validate Configurations ... if (!configuration.IsValid() || !configuration.RabbitMQ.IsValid() || configuration.Broker != XEventBroker.XRabbitMQ ) { XException.InvalidConfiguration.Throw(); } // // Initialize Connection ... CreateConnection(); } /// /// Sending Message with Full Request Descriptor ... /// public async Task SendMessageAsync( XEventRequest request, CancellationToken cancellationToken = default ) { // // Validate ... var result = request.IsValid(); if (!result) { XException.InvalidArgs.Throw(); } // result = await SendMessageAsync( message: request.Message, exchange: request.Topic, cancellationToken: cancellationToken, routingKey: configuration.RabbitMQ.RoutingKey ); // return result; } /// /// Sending a Message to Exchange ... /// public async Task SendMessageAsync( XEventMessage message, string exchange = null, string routingKey = null, CancellationToken cancellationToken = default ) { // // Validate ... var result = message.IsValid(); if (!result) { XException.InvalidArgs.Throw(); } // // Normalize Exchange ... if (exchange.IsNullOrEmpty()) { exchange = configuration.RabbitMQ.Exchange; } // // Normalize Routing Key ... if (routingKey.IsNull()) { routingKey = configuration.RabbitMQ.RoutingKey; } // try { // // Ensure Connection is Alive ... await EnsureChannelAsync(cancellationToken); // // Serialize Message ... var body = Encoding.UTF8.GetBytes( message.ToJSON(camelCase: true) ); // // Prepare Message Properties ... var properties = channel.CreateBasicProperties(); properties.Persistent = true; properties.ContentType = "application/json"; properties.Timestamp = new AmqpTimestamp( DateTimeOffset.UtcNow.ToUnixTimeSeconds() ); properties.MessageId = Guid.NewGuid().ToString(); properties.Type = message.Action; properties.AppId = message.Sender; // // Publish Message ... await Task.Run(() => { // channel.BasicPublish( exchange: exchange, routingKey: routingKey, mandatory: false, basicProperties: properties, body: body ); }, cancellationToken: cancellationToken); // result = true; } catch { result = false; } // return result; } /// /// Dispose Object ... /// public void Dispose() { // try { // channel.Close(); channel.Dispose(); channel = null; // connection.Close(); connection.Dispose(); connection = null; } catch { } // GC.SuppressFinalize(this); } // #region Private ... /// /// Create Connection to RabbitMQ Server ... /// private void CreateConnection() { // var factory = new ConnectionFactory { Port = configuration.GetRabbitMQPort(), HostName = configuration.GetRabbitMQHost(), UserName = configuration.RabbitMQ.Username, Password = configuration.RabbitMQ.Password, VirtualHost = configuration.RabbitMQ.VirtualHost, AutomaticRecoveryEnabled = configuration.RabbitMQ.AutomaticRecoveryEnabled, NetworkRecoveryInterval = TimeSpan.FromSeconds( configuration.RabbitMQ.NetworkRecoveryIntervalSeconds ), DispatchConsumersAsync = true }; // connection = factory.CreateConnection(); } /// /// Check Connection is Alive ... /// private bool IsConnected() { // var result = !connection.IsNullOrDefault() && connection.IsOpen && !channel.IsNull() && channel.IsOpen; // return result; } /// /// Ensure Connection Established ... /// private async Task EnsureConnectionAsync() { // try { await EnsureChannelAsync(); return true; } catch { return false; } } /// /// Ensure Channel is Open and Exchange/Queue Declared ... /// private async Task EnsureChannelAsync( CancellationToken cancellationToken = default ) { // if (IsConnected()) { return; } // lock (connectionLock) { // // Double Check after Lock ... if (IsConnected()) { return; } // // Recreate Connection if Dead ... if (connection is null || !connection.IsOpen) { CreateConnection(); } // // Create Channel ... channel = connection.CreateModel(); // // Declare Exchange ... channel.ExchangeDeclare( arguments: null, exchange: configuration.RabbitMQ.Exchange, durable: configuration.RabbitMQ.ExchangeDurable, autoDelete: configuration.RabbitMQ.ExchangeAutoDelete, type: configuration.RabbitMQ.ExchangeType.GetStringValue() ); } } #endregion } }