TkEndpointCore.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using dodohold.core;
  2. using molilian.core;
  3. using System;
  4. using System.Collections.Concurrent;
  5. using System.Linq;
  6. using YunhuiKit;
  7. using static molilian.core.TkPoolCore;
  8. public partial class TkEndpointCore
  9. {
  10. private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
  11. private static IEnumerable<TkEndpointConfigDTO> _cached;
  12. // 添加到 TkEndpointCore 类中
  13. private static readonly ConcurrentDictionary<int, List<TkEndpointConfigDTO>> _accountEndpointCache = new();
  14. private static async Task<IEnumerable<TkEndpointConfigDTO>> ListAsync(bool force = false)
  15. {
  16. // 内存缓存检查
  17. if (!force && _cached != null) return _cached;
  18. string cache_key = "cache:tk_endpoint_config";
  19. if (!force)
  20. {
  21. var cachedList = await RedisHelper.GetAsync<IEnumerable<TkEndpointConfigDTO>>(cache_key);
  22. if (cachedList != null)
  23. {
  24. _cached = cachedList;
  25. return cachedList;
  26. }
  27. }
  28. // 获取新数据
  29. await _semaphore.WaitAsync();
  30. try
  31. {
  32. // 双重检查,防止并发情况下重复加载
  33. if (!force)
  34. {
  35. var cachedList = await RedisHelper.GetAsync<IEnumerable<TkEndpointConfigDTO>>(cache_key);
  36. if (cachedList != null)
  37. {
  38. _cached = cachedList;
  39. return cachedList;
  40. }
  41. }
  42. // 从数据库加载数据
  43. var list = new DBContext.Table("tk_endpoint_config")
  44. .Where("status=@status", new { status = 1 })
  45. .Select<TkEndpointConfigDTO>();
  46. if (list == null) return default;
  47. // 更新调用次数
  48. //foreach (var item in list)
  49. //{
  50. // item.current_daily_calls = await RiskControlCore.GetAllNodesTkEndpointCallsAsync(item.id, DateTime.Now.ToString("yyyyMMdd"));
  51. // item.current_hourly_calls = await RiskControlCore.GetAllNodesTkEndpointCallsAsync(item.id, DateTime.Now.ToString("yyyyMMddHH"));
  52. //}
  53. // 更新缓存
  54. await RedisHelper.SetAsync(cache_key, list, 30 * 86400);
  55. _cached = list;
  56. _accountEndpointCache.Clear();
  57. return list;
  58. }
  59. finally
  60. {
  61. _semaphore.Release();
  62. }
  63. }
  64. public static async Task<List<TkEndpointConfigDTO>> GetEndpointsByAccountAsync(int accountId)
  65. {
  66. // 1. 从缓存读取(直接返回副本)
  67. if (_accountEndpointCache.TryGetValue(accountId, out var cached))
  68. return cached.Select(x => x.DeepCopy()).ToList();
  69. // 2. 获取所有端点(包含全局和专属)
  70. var allEndpoints = (await ListAsync())?.Where(e => e.status).ToList() ?? [];
  71. // 3. 合并逻辑:专属配置覆盖全局配置(关键!)
  72. var mergedEndpoints = allEndpoints
  73. .GroupBy(e => e.endpoint)
  74. .Select(g =>
  75. {
  76. // 优先取专属配置
  77. var accountSpecific = g.FirstOrDefault(e => e.tk_pool_id == accountId);
  78. if (accountSpecific != null)
  79. return accountSpecific.DeepCopy(); // 深拷贝专属配置
  80. // 否则取全局配置(tk_pool_id=0)
  81. var global = g.FirstOrDefault(e => e.tk_pool_id == 0);
  82. return global?.DeepCopy(); // 深拷贝全局配置
  83. })
  84. .Where(e => e != null)
  85. .ToList();
  86. // 4. 存入缓存(存储深拷贝后的组合配置)
  87. _accountEndpointCache.TryAdd(accountId, mergedEndpoints.Select(x => x.DeepCopy()).ToList());
  88. return mergedEndpoints;
  89. }
  90. // 添加缓存清理方法
  91. public static void ClearEndpointCache(int accountId)
  92. {
  93. _accountEndpointCache.TryRemove(accountId, out _);
  94. }
  95. public static void Refresh()
  96. {
  97. _ = AllListAsync(true);
  98. _ = ListAsync(true);
  99. _accountEndpointCache.Clear();
  100. }
  101. }