using FreeRedis;
using SJZY.Expand.ABP.Core;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Dtos.Forewarning;
using SJZY.Track.Domain.Enums;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.Services.ForewarningServices;
///
/// 用于处理预警通知
///
public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency
{
private IRuleFactorCacheService _ruleFactorCache;
IReadOnlyDictionary> _ruleGroupDict;
IReadOnlyDictionary> _factorDict;
private IReadOnlyDictionary _rules;
readonly INotifyService _notifyService;
public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService)
{
_ruleFactorCache = ruleFactorCache;
_notifyService = notifyService;
}
///
/// 创建预警通知
///
/// 创建预警通知需要的订单信息
/// 创建的通知总量,0表示没有规则
public async Task CreateForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
return await ExecuteRule(rules, order.Id);
}
///
/// 清除预警通知
///
/// 订单信息
/// 清理的行数
public async Task DeleteForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
var willDeleteMembers = new List();
foreach (var rule in rules)
{
var allRuleNotities = DeleteNotifyValue(rule, order.Id);
willDeleteMembers.AddRange(allRuleNotities);
}
await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKeyPrefix, willDeleteMembers.ToArray());
return willDeleteMembers.Count;
}
public void SendNotification(int intervalMinute)
{
var currentTimestamp = GetTimestamp(DateTime.Now);
var notifyMembers =
RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp);
if (notifyMembers == null || notifyMembers.Length == 0)
return;
var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val));
foreach (var notifyValue in notifyValues)
{
if (!_rules.TryGetValue(notifyValue.RuleId, out var rule))
continue;
//todo 发送通知
_notifyService.SendNotification("");
}
}
public void ClearCache()
{
_ruleGroupDict = null;
_factorDict = null;
_rules = null;
}
private List DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId)
{
var members = new List();
for (var index = 0; index < ruleItem.Count; index++)
{
var notifyValue = NotifyValue(ruleItem, orderId, index);
members.Add(notifyValue);
}
return members;
}
///
/// 获取规则
///
///
///
private List GetRule(ForewarningOrderModel order)
{
if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SystemId), out var factors))
{
return null;
}
var keys = GetForewarningKeys(factors, order);
var result = new List();
foreach (var item in keys)
{
if (!_ruleGroupDict.TryGetValue(item, out var rules))
continue;
var allRules = rules.Where(val => val.TrackStart <= order.Track && val.TrackEnd >= order.Track);
result.AddRange(allRules);
}
return result;
}
private async ValueTask ExecuteRule(List rules, int orderId)
{
var members = new List();
foreach (var rule in rules)
{
var notifys = ExecuteRule(rule, orderId);
members.AddRange(notifys);
}
await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKeyPrefix, members.ToArray());
return members.Count;
}
private List ExecuteRule(ForewarningRuleItem ruleItem, int orderId)
{
var members = new List();
var intervalMinute = 60 * ((ruleItem.Timeliness - ruleItem.Remind) / ruleItem.Count); // 间隔多少分钟
for (var index = 0; index < ruleItem.Count; index++)
{
var notifyTime = (ruleItem.Remind * 60) + intervalMinute * index;
var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(notifyTime));
var notifyValue = new ZMember(NotifyValue(ruleItem, orderId, index), notifyTimestamp);
members.Add(notifyValue);
}
return members;
}
private long GetTimestamp(DateTime dateTime)
{
return new DateTimeOffset(dateTime).ToUnixTimeSeconds();
}
private string NotifyValue(ForewarningRuleItem ruleItem, int orderId, int sort)
{
var result = new RuleNotifyValue(ruleItem.Id, orderId, sort, ruleItem.TrackEnd);
return result.ToString();
}
private List GetForewarningKeys(List factors, IForewarningFactorValue rule)
{
var keys = new List();
foreach (var factor in factors)
{
var key = GetRuleKey(rule, factor);
keys.Add(key);
}
return keys;
}
private async Task Init()
{
// todo:缓存设计有问题 重构 120s 10w 30w 3000k/s
var allFactorCollect = await _ruleFactorCache.GetAllFactorCollect();
var factors = await _ruleFactorCache.GetAllRuleFactor();
var factorsMap = factors.GroupBy(val => val.RuleId)
.ToDictionary(val => val.Key, val => val.First());
_rules = allFactorCollect.ToDictionary(val => val.Id);
_factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId, val.SystemId))
.ToDictionary(val => val.Key, val => val.ToList());
_ruleGroupDict = allFactorCollect.GroupBy(x => GetRuleKey(x, factorsMap[x.RuleId]))
.ToDictionary(val => val.Key, val => val.ToList());
}
private string GetFactorKey(int customerId, int systemId)
{
return $"{customerId}:{systemId}";
}
private string GetRuleKey(IForewarningFactorValue rule, RuleFactor factors)
{
var key = "";
foreach (var factorItem in factors.FactorItems)
{
key += GetFactorValue(factorItem, rule);
}
return key;
}
private string GetFactorValue(FactorItemModel factorItem, IForewarningFactorValue rule)
{
switch (factorItem.FactorType)
{
case RuleFactorType.Areas:
return rule.Area.HasValue ? rule.Area.Value.ToString() : throw new Exception("区域不能为空");
case RuleFactorType.CargoType:
return rule.CargoType;
case RuleFactorType.LeavePort:
return rule.LeavePort;
case RuleFactorType.Months:
return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空");
case RuleFactorType.ProductCode:
return rule.ProductCode;
case RuleFactorType.IsTransit:
return rule.IsTransit.HasValue ? "1" : "0";
// Add additional cases for other RuleFactorTypes as needed
default:
throw new Exception("未知的规则类型");
}
}
}