using dodohold.core; using System.Threading.Channels; namespace molilian.core { public partial class CpsPoolCore { private static string _end_point; private static Dictionary _incomeAmt = new(); private static Dictionary _calls = new(); static Random _random = new Random(); static CpsPoolCore() { _end_point = Environment.GetEnvironmentVariable("EndPoint"); } private static readonly object _lockObj = new(); private static IEnumerable _links_cached; private static IEnumerable _cached; public static CpsLinksDTO? GetOne(string channel) { var list = List(); if (!list.Any()) return null; var pool = list.Where(e => e.channel_code == channel && e.status).FirstOrDefault(); if (pool == null) return null; var links = LinksList(); if (!links.Any()) return null; // 获取符合条件的链接 var eligibleLinks = links.Where(e => IsEligible(e, channel)).ToList(); if (!eligibleLinks.Any()) return null; // 计算总权重 int totalWeight = eligibleLinks.Sum(item => item.priority_weight); if (totalWeight == 0) return null; int randomValue = _random.Next(totalWeight); // 按权重查找 int accumulatedWeight = 0; foreach (var link in eligibleLinks.OrderByDescending(e => e.priority_weight)) { accumulatedWeight += link.priority_weight; if (randomValue < accumulatedWeight) return link; } // 保险起见返回第一个 return eligibleLinks.First(); } public static CpsLinksDTO? GetOne2(string channel) { var list = List(); if (!list.Any()) return null; var pool = list.Where(e => e.channel_code == channel && e.status).FirstOrDefault(); if (pool == null) return null; var links = LinksList(); if (!links.Any()) return null; //int totalWeight = links.Sum(item => item.priority_weight); //int randomValue = _random.Next(0,totalWeight); //// 累积权重直到找到选中项 //double accumulatedWeight = 0; //foreach (var item in items) //{ // accumulatedWeight += Math.Pow(2, weightSelector(item)); // if (randomValue <= accumulatedWeight) // return item; //} return links.Where(e => IsEligible(e, channel)) .OrderByDescending(e => e.priority_weight) .ThenBy(l => Guid.NewGuid()) .FirstOrDefault(); } private static bool IsEligible(CpsLinksDTO item, string channel) { if (item.channel_code != channel) return false; // 使用初始化参数创建工作时间表 if (!new WorkSchedule(item.time_range).IsWorkHour()) return false; var now = DateTime.Now; if (item.start_time > now || now > item.end_time) return false; if (item.daily_calls_limit > 0) { int daily_num = RiskControlCore.GetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd")); if (daily_num >= item.daily_calls_limit) return false; } if (item.hourly_calls_limit > 0) { int hourly_num = RiskControlCore.GetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH")); if (hourly_num >= item.hourly_calls_limit) return false; } return true; } public static IEnumerable List(bool force = false) { #if DEBUG return new DBContext.Table("cps_pool") .Where("status=@status", new { status = 1 }) .Select(); #else if (!force && _cached != null) return _cached; string cache_key = $"cache:cps_pool"; var list = RedisHelper.Get>(cache_key); if (force || list == null) { lock (_lockObj) { list = new DBContext.Table("cps_pool") .Where("status=@status", new { status = 1 }) .Select(); if (list == null) return default; RedisHelper.Set(cache_key, list, 30 * 86400); } } _cached = list; return list; #endif } public static IEnumerable LinksList(bool force = false) { #if DEBUG var list = new DBContext.Table("cps_links") .Where("status=@status", new { status = 1 }) .Select(); foreach (var item in list) { RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls); RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls); } return list; #else if (!force && _links_cached != null) return _links_cached; string cache_key = $"cache:cps_links"; var list = RedisHelper.Get>(cache_key); if (force || list == null) { lock (_lockObj) { list = new DBContext.Table("cps_links") .Where("status=@status", new { status = 1 }) .Select(); if (list == null) return default; foreach (var item in list) { RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls); RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls); } RedisHelper.Set(cache_key, list, 30 * 86400); } } _links_cached = list; return list; #endif } public static int Update(CpsLinksDTO account) { return new DBContext.Table("cps_links") .Add("current_hourly_calls", account.current_hourly_calls) .Add("current_daily_calls", account.current_daily_calls) .Where("id=@id", new { account.id }) .Update(); } public static void Refresh() { _ = List(true); _ = LinksList(true); } internal static void AccountExhausted() { string cache_key = $"cache:tk_pool:account:exhausted"; long count = RedisHelper.IncrBy(cache_key); if (count > 1) return; RedisHelper.Expire(cache_key, 3600); NotifyCore.Notify(new NifyMessage { message = $"【CPS优惠券】没有匹配账号", priority = NifyMessagePriority.high, tags = ["red_circle"] }); NotifyCore.AnPushNotify("没账号", $"【CPS优惠券】没有匹配账号"); } } }