文件内容 ChannelHelper.cs 9 KB 9488 字符
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PasteApeart.Application.Contracts;
using PasteApeart.Handler;
using System.Collections.Concurrent;
using System.Text.Json;
using System.Threading.Channels;

namespace PasteApeart
{
    /// <summary>
    /// 
    /// </summary>
    public class ChannelHelper : ISingletonDependency
    {

        private readonly Channel<ChannelNoticeModel> _channelnotice;
        private readonly Channel<IEventModel> _channelLocationQueue;
        private readonly ILogger<ChannelHelper> _logger;
        private readonly AppConfig _config;
        private readonly ConcurrentDictionary<long, List<IEventModel>> queueList;
        private readonly RabbitMQProducer _producer;
        private readonly RabbitConfig _rabbitConfig;
        /// <summary>
        /// 
        /// </summary>
        public ChannelHelper(
            ILogger<ChannelHelper> logger,
            IOptions<AppConfig> config,
            RabbitMQProducer producer,
            IOptions<RabbitConfig> rabbitConfig
            )
        {
            _channelnotice = Channel.CreateBounded<ChannelNoticeModel>(1000);
            _channelLocationQueue = Channel.CreateBounded<IEventModel>(10000);
            queueList = new ConcurrentDictionary<long, List<IEventModel>>();
            _logger = logger;
            _config = config.Value;
            if (!_config.RabbitQueue)
            {
                _ = PeriodicTimerHandlerAsync(default);
            }
            else
            {
                _producer = producer;
            }
            _rabbitConfig = rabbitConfig.Value;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        public async Task Write(ChannelNoticeModel input)
        {
            await _channelnotice.Writer.WriteAsync(input);
        }

        /// <summary>
        /// 自动写入最近的延迟队列 本地或者远端
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task WriteAutoQueueAsync(IEventModel input)
        {
            if (String.IsNullOrEmpty(input.EventName))
            {
                input.EventName = input.GetType().Name;
            }
            if (input.ExpireSecond <= 0)
            {
                await SendQueueMessageAsync(input);
            }
            else
            {
                if (_config.RabbitQueue)
                {
                    var send = false;
                    if (_rabbitConfig.ExpireTimeList != null)
                    {
                        var find = _rabbitConfig.ExpireTimeList.Where(x => x.ExpireSecond <= input.ExpireSecond).OrderByDescending(x => x.ExpireSecond).FirstOrDefault();
                        if (find != null)
                        {
                            input.ExpireSecond = input.ExpireSecond - find.ExpireSecond;
                            await this.SendRemoteMessageAsync(input, find.ExpireExchange);
                            send = true;
                        }
                    }
                    if (!send)
                    {
                        input.ExpireSecond = 0;
                        await this.SendQueueMessageAsync(input);
                    }
                }
                else
                {
                    await this.WriteLocationMessageAsync(input, input.ExpireSecond);
                }
            }
        }

        /// <summary>
        /// 处理本地延迟队列
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task PeriodicTimerHandlerAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                TimeSpan inter = TimeSpan.FromSeconds(1);
                using var timer = new PeriodicTimer(inter);
                while (await timer.WaitForNextTickAsync(cancellationToken))
                {
                    //每隔1秒钟这里会一直重复执行么? 不考虑执行任务耗时
                    #region
                    var now = DateTime.Now.ToUnixTimeSeconds();
                    var finds = queueList.Keys.Where(x => x < now).ToArray();
                    if (finds?.Length > 0)
                    {
                        var findValues = queueList.Where(x => finds.Contains(x.Key)).ToArray();
                        if (findValues?.Length > 0)
                        {
                            foreach (var item in findValues)
                            {
                                if (item.Value != null)
                                {
                                    foreach (var ival in item.Value)
                                    {
                                        await WriteLocationMessageAsync(ival);
                                    }
                                }
                            }
                        }
                        foreach (var item in findValues)
                        {
                            queueList.TryRemove(item.Key, out _);
                        }
                    }
                    //查找是否有过期的任务,进行执行!
                    #endregion
                }
            }
            catch (Exception exlAll)
            {
                _logger.LogException(exlAll);
            }
        }

        /// <summary>
        /// 写入本地 延迟队列
        /// </summary>
        /// <param name="input"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        private async Task WriteLocationMessageAsync(IEventModel input, long second)
        {
            if (input.ExpireSecond > 0)
            {
                input.ExpireSecond = 0;
            }
            if (second > 0)
            {
                var distionTime = DateTime.Now.ToUnixTimeSeconds() + second;
                queueList.AddOrUpdate(distionTime, (a) => new List<IEventModel> { input }
                , (c, d) =>
                {
                    d.Add(input);
                    return d;
                });
            }
            else
            {
                await WriteLocationMessageAsync(input);
            }
        }

        /// <summary>
        /// 直接发送本地
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task WriteLocationMessageAsync(IEventModel input)
        {
            //_logger.LogInformation($"本地MQ写入:{JsonSerializer.Serialize(input, input.GetType(), JsonConfig.Options)}");
            await _channelLocationQueue.Writer.WriteAsync(input);
        }

        /// <summary>
        /// 写入队列 本地或者远程
        /// </summary>
        /// <param name="_info"></param>
        /// <returns></returns>
        private async Task SendQueueMessageAsync(IEventModel _info)
        {
            if (_config.RabbitQueue)
            {
                await _producer.SendWithRetryAsync(_rabbitConfig.ExpiredExchange, JsonSerializer.Serialize(_info, _info.GetType(), JsonConfig.Options), _rabbitConfig.ExpireRouteKey);
            }
            else
            {
                //await _channelLocationQueue.Writer.WriteAsync(_info);
                await WriteLocationMessageAsync(_info);
            }
        }

        /// <summary>
        /// 直接发送远端
        /// </summary>
        /// <param name="info"></param>
        /// <param name="exchange"></param>
        /// <returns></returns>
        private async Task SendRemoteMessageAsync(IEventModel info, string exchange)
        {
            await _producer.SendWithRetryAsync(exchange, JsonSerializer.Serialize(info, info.GetType(), JsonConfig.Options), _rabbitConfig.ExpireRouteKey);
        }

        /// <summary>
        /// 写入广播事件
        /// </summary>
        /// <param name="input"></param>
        /// <param name="isremove"></param>
        /// <returns></returns>
        public async Task WriteBroadcastMessageAsync(IEventModel input, bool isremove)
        {
            if (input == null) { return; }
            input.EventName = input.GetType().Name;
            if (_rabbitConfig.SubscribeEnable)
            {
                await _producer.WriteSubscribeAsync(System.Text.Json.JsonSerializer.Serialize(input, input.GetType(), JsonConfig.Options));
            }
            else
            {
                _logger.LogError("没有配置广播模式,当前消息是发给广播模式的");
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public Channel<ChannelNoticeModel> Notice { get { return _channelnotice; } }

        /// <summary>
        /// 
        /// </summary>
        public Channel<IEventModel> ChannelEventModel { get { return _channelLocationQueue; } }

    }

    /// <summary>
    /// 
    /// </summary>
    public class ChannelNoticeModel
    {
        /// <summary>
        /// 内容
        /// </summary>
        public string body { get; set; }

        /// <summary>
        /// 动作名称 waitrevice:任务待领取 finish:任务完成 cannel:任务取消 waithand:待处理 waitreply:待反馈
        /// </summary>
        public string action { get; set; }

        /// <summary>
        /// 用户id
        /// </summary>
        public int userid { get; set; }

        /// <summary>
        /// 部门ID
        /// </summary>
        public int partid { get; set; }

        /// <summary>
        /// 整个项目组
        /// </summary>
        public int projectid { get; set; }

        /// <summary>
        /// 排除谁
        /// </summary>
        public int exceptuid { get; set; }
    }
}
​ ​