CpsPoolCore.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. using dodohold.core;
  2. using System.Threading.Channels;
  3. namespace molilian.core
  4. {
  5. public partial class CpsPoolCore
  6. {
  7. private static string _end_point;
  8. private static Dictionary<string, decimal> _incomeAmt = new();
  9. private static Dictionary<string, int> _calls = new();
  10. static Random _random = new Random();
  11. static CpsPoolCore()
  12. {
  13. _end_point = Environment.GetEnvironmentVariable("EndPoint");
  14. }
  15. private static readonly object _lockObj = new();
  16. private static IEnumerable<CpsLinksDTO> _links_cached;
  17. private static IEnumerable<CpsPoolDTO> _cached;
  18. public static CpsLinksDTO? GetOne(string channel)
  19. {
  20. var list = List();
  21. if (!list.Any()) return null;
  22. var pool = list.Where(e => e.channel_code == channel && e.status).FirstOrDefault();
  23. if (pool == null) return null;
  24. var links = LinksList();
  25. if (!links.Any()) return null;
  26. // 获取符合条件的链接
  27. var eligibleLinks = links.Where(e => IsEligible(e, channel)).ToList();
  28. if (!eligibleLinks.Any()) return null;
  29. // 计算总权重
  30. int totalWeight = eligibleLinks.Sum(item => item.priority_weight);
  31. if (totalWeight == 0) return null;
  32. int randomValue = _random.Next(totalWeight);
  33. // 按权重查找
  34. int accumulatedWeight = 0;
  35. foreach (var link in eligibleLinks.OrderByDescending(e => e.priority_weight))
  36. {
  37. accumulatedWeight += link.priority_weight;
  38. if (randomValue < accumulatedWeight)
  39. return link;
  40. }
  41. // 保险起见返回第一个
  42. return eligibleLinks.First();
  43. }
  44. public static CpsLinksDTO? GetOne2(string channel)
  45. {
  46. var list = List();
  47. if (!list.Any()) return null;
  48. var pool = list.Where(e => e.channel_code == channel && e.status).FirstOrDefault();
  49. if (pool == null) return null;
  50. var links = LinksList();
  51. if (!links.Any()) return null;
  52. //int totalWeight = links.Sum(item => item.priority_weight);
  53. //int randomValue = _random.Next(0,totalWeight);
  54. //// 累积权重直到找到选中项
  55. //double accumulatedWeight = 0;
  56. //foreach (var item in items)
  57. //{
  58. // accumulatedWeight += Math.Pow(2, weightSelector(item));
  59. // if (randomValue <= accumulatedWeight)
  60. // return item;
  61. //}
  62. return links.Where(e => IsEligible(e, channel))
  63. .OrderByDescending(e => e.priority_weight)
  64. .ThenBy(l => Guid.NewGuid())
  65. .FirstOrDefault();
  66. }
  67. private static bool IsEligible(CpsLinksDTO item, string channel)
  68. {
  69. if (item.channel_code != channel) return false;
  70. // 使用初始化参数创建工作时间表
  71. if (!new WorkSchedule(item.time_range).IsWorkHour()) return false;
  72. var now = DateTime.Now;
  73. if (item.start_time > now || now > item.end_time) return false;
  74. if (item.daily_calls_limit > 0)
  75. {
  76. int daily_num = RiskControlCore.GetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"));
  77. if (daily_num >= item.daily_calls_limit) return false;
  78. }
  79. if (item.hourly_calls_limit > 0)
  80. {
  81. int hourly_num = RiskControlCore.GetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"));
  82. if (hourly_num >= item.hourly_calls_limit) return false;
  83. }
  84. return true;
  85. }
  86. public static IEnumerable<CpsPoolDTO> List(bool force = false)
  87. {
  88. #if DEBUG
  89. return new DBContext.Table("cps_pool")
  90. .Where("status=@status", new { status = 1 })
  91. .Select<CpsPoolDTO>();
  92. #else
  93. if (!force && _cached != null) return _cached;
  94. string cache_key = $"cache:cps_pool";
  95. var list = RedisHelper.Get<IEnumerable<CpsPoolDTO>>(cache_key);
  96. if (force || list == null)
  97. {
  98. lock (_lockObj)
  99. {
  100. list = new DBContext.Table("cps_pool")
  101. .Where("status=@status", new { status = 1 })
  102. .Select<CpsPoolDTO>();
  103. if (list == null) return default;
  104. RedisHelper.Set(cache_key, list, 30 * 86400);
  105. }
  106. }
  107. _cached = list;
  108. return list;
  109. #endif
  110. }
  111. public static IEnumerable<CpsLinksDTO> LinksList(bool force = false)
  112. {
  113. #if DEBUG
  114. var list = new DBContext.Table("cps_links")
  115. .Where("status=@status", new { status = 1 })
  116. .Select<CpsLinksDTO>();
  117. foreach (var item in list)
  118. {
  119. RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
  120. RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
  121. }
  122. return list;
  123. #else
  124. if (!force && _links_cached != null) return _links_cached;
  125. string cache_key = $"cache:cps_links";
  126. var list = RedisHelper.Get<IEnumerable<CpsLinksDTO>>(cache_key);
  127. if (force || list == null)
  128. {
  129. lock (_lockObj)
  130. {
  131. list = new DBContext.Table("cps_links")
  132. .Where("status=@status", new { status = 1 })
  133. .Select<CpsLinksDTO>();
  134. if (list == null) return default;
  135. foreach (var item in list)
  136. {
  137. RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
  138. RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
  139. }
  140. RedisHelper.Set(cache_key, list, 30 * 86400);
  141. }
  142. }
  143. _links_cached = list;
  144. return list;
  145. #endif
  146. }
  147. public static int Update(CpsLinksDTO account)
  148. {
  149. return new DBContext.Table("cps_links")
  150. .Add("current_hourly_calls", account.current_hourly_calls)
  151. .Add("current_daily_calls", account.current_daily_calls)
  152. .Where("id=@id", new { account.id })
  153. .Update();
  154. }
  155. public static void Refresh()
  156. {
  157. _ = List(true);
  158. _ = LinksList(true);
  159. }
  160. internal static void AccountExhausted()
  161. {
  162. string cache_key = $"cache:tk_pool:account:exhausted";
  163. long count = RedisHelper.IncrBy(cache_key);
  164. if (count > 1) return;
  165. RedisHelper.Expire(cache_key, 3600);
  166. NotifyCore.Notify(new NifyMessage
  167. {
  168. message = $"【CPS优惠券】没有匹配账号",
  169. priority = NifyMessagePriority.high,
  170. tags = ["red_circle"]
  171. });
  172. NotifyCore.AnPushNotify("没账号", $"【CPS优惠券】没有匹配账号");
  173. }
  174. }
  175. }