
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Configuration\XEventServiceConfiguration.cs

using System.Collections.Generic;
using RabbitMQ.Client;
using xEventService.Constants;

namespace xEventService.Configuration
{
    /// <summary>
    /// a configuration class for describing how to connect rabbit mq server
    /// and how channels must be declared ...
    /// </summary>
    public class XEventServiceConfiguration
    {
        /// <summary>
        /// Message Broker Address ...
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// Max Retries to Sending Message ...
        /// </summary>
        public int MaxRetries { get; set; } = 3;

        /// <summary>
        /// Allowed Message Broker ...
        /// </summary>
        public XEventBroker Broker { get; set; } = XEventBroker.None;
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Constants\ConfigurationNodeNames.cs

namespace xEventService.Constants
{
    public partial struct ConfigurationNodeNames {
        public const string EVENT_SERVICE_NODE_NAME = "EventServiceConfiguration";
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Constants\XEventBroker.cs

using xExceptions.Attributes;

namespace xEventService.Constants
{
    /// <summary>
    /// Available Brokers ...
    /// </summary>
    public enum XEventBroker
    {
        [StringValue("None")]
        None,

        [StringValue("XKafka")]
        XKafka,

        [StringValue("XRabbitMQ")]
        XRabbitMQ        
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Constants\XEventServiceConstants.cs

namespace xEventService.Constants
{
    public struct XEventServiceConstants
    {
        //
        // Service Extensions Log Tag ...
        public const string XEventServiceDILogTag = "XEventService";

        //
        // Defaults ...
        public const string XDefaultTopic = "XSaherelm";  
        public const string XDefaultConsumerGroup = "XSaherElmGroup";      
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\DI\XDIHelperExtension.cs

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using xCommons.Extensions;
using xEventService.Configuration;
using xEventService.Constants;
using xEventService.Extensions;
using xExceptions.Constants;

namespace xEventService.DI
{
    public static partial class XDIHelperExtension
    {
        /// <summary>
        /// Extract EventService Configurations ...
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static XEventServiceConfiguration GetXEventServiceConfigurations(
            this IConfiguration source
        )
        {
            //
            var configSection = source
                .GetSection(ConfigurationNodeNames.EVENT_SERVICE_NODE_NAME);
            var result = configSection.Get<XEventServiceConfiguration>();

            //
            return result;
        }

        /// <summary>
        /// Register Event Service Configurations ...
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddXEventServiceConfigurations(
            this IServiceCollection services,
            IConfiguration configuration
        )
        {
            //
            var config = configuration.GetXEventServiceConfigurations();
            services.AddXEventServiceConfigurations(config);
        }

        /// <summary>
        /// Register Event Service Configurations ...
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddXEventServiceConfigurations(
            this IServiceCollection services,
            XEventServiceConfiguration configuration
        )
        {
            //
            // Validate ...
            if (!configuration.IsValid())
            {
                //
                Log("Registration Failed, due Invalid Configuration ...");
                XException.InvalidConfiguration.Throw();
            }

            //
            // Register Configuration as Singleton ...
            services.AddSingleton(configuration);
        }

        //
        #region Private ...
        /// <summary>
        /// a LogTag for Service ...
        /// </summary>
        private static string XLogTag = XEventServiceConstants.XEventServiceDILogTag;

        /// <summary>
        /// print a log in Console ...
        /// </summary>
        /// <param name="message"></param>
        private static void Log(string message)
        {
            Console.WriteLine($"{XLogTag} => {message}");
        }
        #endregion
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Extensions\XEventServiceExtensions.cs

using xCommons.Extensions;
using xEventService.Configuration;
using xEventService.Constants;
using xEventService.Models;

namespace xEventService.Extensions
{
    /// <summary>
    /// Extensions for Event Service ...
    /// </summary>
    public static class XEventServiceExtensions
    {
        /// <summary>
        /// Validate Event Broker ...
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValid(this XEventBroker source)
        {
            //
            var result =
                !source.IsNull() &&
                source != XEventBroker.None;

            //
            return result;
        }

        /// <summary>
        /// Validate Event Service Configuration ...
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValid(this XEventServiceConfiguration source)
        {
            //
            var result =
                !source.IsNullOrDefault() &&
                source.Broker.IsValid() &&
                !source.Url.IsNullOrEmpty() &&
                source.Url.IsValidUrl();

            //
            return result;
        }

        /// <summary>
        /// Validate an Event Message ...
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValid(this XEventMessage source)
        {
            //
            var result =
                !source.IsNullOrDefault() &&
                !source.Action.IsNullOrEmpty() &&
                !source.Sender.IsNullOrEmpty();

            //
            return result;
        }

        /// <summary>
        /// Validate an Event Request ...
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValid(this XEventRequest source)
        {
            //
            var result =
                !source.IsNullOrDefault() &&
                !source.Topic.IsNullOrEmpty() &&
                source.Message.IsValid();

            //
            return result;
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Interfaces\IXKafkaProducerService.cs

using System;
using System.Threading;
using System.Threading.Tasks;
using xEventService.Constants;
using xEventService.Models;

namespace xEventService.Interfaces
{
    /// <summary>
    /// a Service for Produce Kafka Messages ...
    /// </summary>
    public interface IXKafkaProducerService : IDisposable
    {
        /// <summary>
        /// Sending Message ...
        /// </summary>
        /// <param name="request">an Instance of <see cref="XEventRequest"/> to Provides Kafka Messaging requirement ...</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task<bool> SendMessageAsync(
            XEventRequest request,
            CancellationToken cancellationToken = default
        );

        /// <summary>
        /// Sending a Message ...
        /// </summary>
        /// <param name="message">an Instance of <see cref="XEventMessage"/> to Provides Kafka Messaging requirement ...</param>
        /// <param name="topic">Topic for Sending Message ...</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task<bool> SendMessageAsync(
            XEventMessage message,
            string topic = XEventServiceConstants.XDefaultTopic,
            CancellationToken cancellationToken = default
        );
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Models\XEventMessage.cs

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace xEventService.Models
{
    /// <summary>
    /// a Message Descriptor for Events ...
    /// </summary>
    public class XEventMessage
    {
        /// <summary>
        /// Specified Action for Fire ...
        /// </summary>
        [JsonRequired]
        public string Action { get; set; }

        /// <summary>
        /// Specified Action Sender ...
        /// </summary>
        [JsonRequired]
        public string Sender { get; set; }

        /// <summary>
        /// Sending Time ...
        /// </summary>
        [JsonRequired]
        public DateTime Offset { get; set; }

        /// <summary>
        /// Specified Message ...
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// Metadata for Message ...
        /// </summary>
        public IDictionary<string, string> Payload { get; set; } = new Dictionary<string, string>();
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Models\XEventRequest.cs

using xEventService.Constants;

namespace xEventService.Models
{
    /// <summary>
    /// a Request for Sending an Event ...
    /// </summary>
    public class XEventRequest
    {
        /// <summary>
        /// Specified Which Kafka Topic ...
        /// </summary>
        public string Topic { get; set; } = XEventServiceConstants.XDefaultTopic;

        /// <summary>
        /// Specified Kafka Meesage to Send ...
        /// </summary>
        public XEventMessage Message { get; set; }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Providers\XKafkaConsumerServiceBase.cs

using System;
using Confluent.Kafka;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using xEventService.Configuration;
using xEventService.Constants;

namespace xEventService.Providers
{
    /// <summary>
    /// an Abstract Kafka Consumer Service ...
    /// </summary>
    public abstract class XKafkaConsumerServiceBase : BackgroundService
    {
        /// <summary>
        /// Consumed Topic Messages ...
        /// </summary>
        private readonly string topic;

        /// <summary>
        /// Kafka Consumer Class ...
        /// </summary>
        public readonly IConsumer<Ignore, string> consumer;

        private readonly XEventServiceConfiguration configuration;

        private readonly ILogger<XKafkaConsumerServiceBase> logger;

        protected XKafkaConsumerServiceBase(
            XEventServiceConfiguration configuration,
            ILogger<XKafkaConsumerServiceBase> logger,
            string topic = XEventServiceConstants.XDefaultTopic
        )
        {
            //
            this.topic = topic;
            this.logger = logger;
            this.configuration = configuration;

            //
            // Prepare Kafka Consumer Configuration ...
            var config = new ConsumerConfig
            {
                EnableAutoCommit = false,
                BootstrapServers = configuration.Url,
                AutoOffsetReset = AutoOffsetReset.Earliest,
                GroupId = XEventServiceConstants.XDefaultConsumerGroup,
            };
            consumer = new ConsumerBuilder<Ignore, string>(config).Build();
        }

        /// <summary>
        /// Dispose Implementation ...
        /// </summary>
        public override void Dispose()
        {
            //
            consumer.Close();
            consumer.Dispose();
            GC.SuppressFinalize(this);
            base.Dispose();
        }
    }
}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xEventService\Providers\XKafkaProducerService.cs

using xCommons.Extensions;
using xExceptions.Constants;
using xEventService.Extensions;
using xEventService.Interfaces;
using xEventService.Configuration;
using xEventService.Models;
using Confluent.Kafka;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using System.Threading;
using xEventService.Constants;
using System;

namespace xEventService.Providers
{
    public class XKafkaProducerService : IXKafkaProducerService
    {
        private readonly IProducer<Null, string> producer;
        private readonly ILogger<XKafkaProducerService> logger;
        private readonly XEventServiceConfiguration configuration;

        public XKafkaProducerService(
            ILogger<XKafkaProducerService> logger,
            XEventServiceConfiguration configuration
        )
        {
            //
            this.logger = logger;
            this.configuration = configuration;

            //
            // Validate Configurations ...
            if (!configuration.IsValid() ||
                configuration.Broker != XEventBroker.XKafka
            )
            {
                XException.InvalidConfiguration.Throw();
            }

            //
            // Prepare Kafka Producer Configuration ...
            var config = new ProducerConfig
            {
                Acks = Acks.All,
                BootstrapServers = configuration.Url,
                MessageSendMaxRetries = configuration.MaxRetries,
            };
            producer = new ProducerBuilder<Null, string>(config).Build();
        }

        /// <summary>
        /// Sending Message ...
        /// </summary>
        /// <param name="request">an Instance of <see cref="XEventRequest"/> to Provides Kafka Messaging requirement ...</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<bool> SendMessageAsync(
            XEventRequest request,
            CancellationToken cancellationToken = default
        )
        {
            //
            // Validate ...
            var result = request.IsValid();
            if (!result)
            {
                XException.InvalidArgs.Throw();
            }

            //
            result = await SendMessageAsync(
                message: request.Message,
                topic: request.Topic,
                cancellationToken: cancellationToken
            );

            //
            return result;
        }

        /// <summary>
        /// Sending a Message ...
        /// </summary>
        /// <param name="message">an Instance of <see cref="XEventMessage"/> to Provides Kafka Messaging requirement ...</param>
        /// <param name="topic">Topic for Sending Message ...</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<bool> SendMessageAsync(
            XEventMessage message,
            string topic = XEventServiceConstants.XDefaultTopic,
            CancellationToken cancellationToken = default
        )
        {
            //
            // Validate ...
            var result = message.IsValid() &&
                !topic.IsNullOrEmpty();
            if (!result)
            {
                XException.InvalidArgs.Throw();
            }

            //
            try
            {
                //
                var response = await producer.ProduceAsync(
                    topic: topic,
                    message: new Message<Null, string>
                    {
                        Value = message
                            .ToJSON(camelCase: true)
                    },
                    cancellationToken: cancellationToken
                );

                //
                result = true;
            }
            catch
            {
                result = false;
            }

            //
            return result;
        }

        /// <summary>
        /// Dispose Required Objects ...
        /// </summary>
        public void Dispose()
        {
            //
            producer.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
