| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- using dodohold.core;
- using molilian.core;
- using Org.BouncyCastle.Crypto;
- using System;
- using System.Collections.Concurrent;
- using System.Linq;
- using YunhuiKit;
- using static molilian.core.TkPoolCore;
- public partial class TkEndpointCore
- {
- private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
- private static IEnumerable<TkEndpointConfigDTO> _cached;
- // 添加到 TkEndpointCore 类中
- private static readonly ConcurrentDictionary<(int, bool?, string), List<TkEndpointConfigDTO>> _accountEndpointCache = new();
- private static async Task<IEnumerable<TkEndpointConfigDTO>> ListAsync(bool force = false)
- {
- // 内存缓存检查
- if (!force && _cached != null) return _cached;
- string cache_key = "cache:tk_endpoint_config";
- if (!force)
- {
- var cachedList = await RedisHelper.GetAsync<IEnumerable<TkEndpointConfigDTO>>(cache_key);
- if (cachedList != null)
- {
- _cached = cachedList;
- return cachedList;
- }
- }
- // 获取新数据
- await _semaphore.WaitAsync();
- try
- {
- // 双重检查,防止并发情况下重复加载
- if (!force)
- {
- var cachedList = await RedisHelper.GetAsync<IEnumerable<TkEndpointConfigDTO>>(cache_key);
- if (cachedList != null)
- {
- _cached = cachedList;
- return cachedList;
- }
- }
- // 从数据库加载数据
- var list = new DBContext.Table("tk_endpoint_config")
- .Where("status=@status", new { status = 1 })
- .Select<TkEndpointConfigDTO>();
- if (list == null) return default;
- // 更新调用次数
- //foreach (var item in list)
- //{
- // item.current_daily_calls = await RiskControlCore.GetAllNodesTkEndpointCallsAsync(item.id, DateTime.Now.ToString("yyyyMMdd"));
- // item.current_hourly_calls = await RiskControlCore.GetAllNodesTkEndpointCallsAsync(item.id, DateTime.Now.ToString("yyyyMMddHH"));
- //}
- // 更新缓存
- await RedisHelper.SetAsync(cache_key, list, 30 * 86400);
- _cached = list;
- _accountEndpointCache.Clear();
- return list;
- }
- finally
- {
- _semaphore.Release();
- }
- }
- public static Task<List<TkEndpointConfigDTO>> GetEndpointsByAccountAsync(int accountId, bool? isTaobaoUrl = null, string parseEndpoints = null)
- {
- return GetEndpointsByAccountInternalAsync(accountId, isTaobaoUrl, parseEndpoints, cloneResult: true);
- }
- public static Task<List<TkEndpointConfigDTO>> GetEndpointsByAccountReadonlyAsync(int accountId, bool? isTaobaoUrl = null, string parseEndpoints = null)
- {
- return GetEndpointsByAccountInternalAsync(accountId, isTaobaoUrl, parseEndpoints, cloneResult: false);
- }
- private static async Task<List<TkEndpointConfigDTO>> GetEndpointsByAccountInternalAsync(int accountId, bool? isTaobaoUrl, string parseEndpoints, bool cloneResult)
- {
- string normalizedParseEndpoints = NormalizeParseEndpoints(parseEndpoints);
- var cacheKey = (accountId, isTaobaoUrl, normalizedParseEndpoints);
- if (_accountEndpointCache.TryGetValue(cacheKey, out var cached))
- return cloneResult ? cached.Select(x => x.DeepCopy()).ToList() : cached;
- // 2. 获取所有端点(包含全局和专属)
- var allEndpoints = (await ListAsync())?.Where(e => e.status).ToList() ?? [];
- // 3. 合并逻辑:专属配置覆盖全局配置(关键!)
- var mergedEndpoints = allEndpoints
- .GroupBy(e => e.endpoint)
- .Select(g =>
- {
- // 优先取专属配置
- var accountSpecific = g.FirstOrDefault(e => e.tk_pool_id == accountId);
- if (accountSpecific != null)
- return accountSpecific.DeepCopy(); // 深拷贝专属配置
- // 否则取全局配置(tk_pool_id=0)
- var global = g.FirstOrDefault(e => e.tk_pool_id == 0);
- return global?.DeepCopy(); // 深拷贝全局配置
- })
- .Where(e => e != null)
- .ToList();
- // 4. 根据isTaobaoUrl过滤
- if (isTaobaoUrl.HasValue)
- {
- mergedEndpoints = mergedEndpoints.Where(e =>
- {
- if (e.taobao_id_handling == 0) return true;
- if (e.taobao_id_handling == 1 && isTaobaoUrl.Value) return true;
- if (e.taobao_id_handling == 2 && !isTaobaoUrl.Value) return true;
- return false;
- }).ToList();
- }
- // 5. 排除指定的端点
- if (!string.IsNullOrEmpty(normalizedParseEndpoints))
- {
- var parseEndpointIds = normalizedParseEndpoints.Split(',')
- .Select(idStr => int.TryParse(idStr.Trim(), out var id) ? id : (int?)null)
- .Where(id => id.HasValue)
- .Select(id => id.Value)
- .ToHashSet();
- mergedEndpoints = mergedEndpoints.Where(e => parseEndpointIds.Contains(e.ep_id)).ToList();
- }
- // 6. 存入缓存
- var cachedValue = mergedEndpoints.Select(x => x.DeepCopy()).ToList();
- _accountEndpointCache.TryAdd(cacheKey, cachedValue);
- return cloneResult ? cachedValue.Select(x => x.DeepCopy()).ToList() : cachedValue;
- }
- // 添加缓存清理方法
- public static void ClearEndpointCache(int accountId)
- {
- foreach (var key in _accountEndpointCache.Keys.Where(key => key.Item1 == accountId).ToList())
- {
- _accountEndpointCache.TryRemove(key, out _);
- }
- }
- public static void Refresh()
- {
- _ = AllListAsync(true);
- _ = ListAsync(true);
- _accountEndpointCache.Clear();
- }
- private static string NormalizeParseEndpoints(string? parseEndpoints)
- {
- if (string.IsNullOrWhiteSpace(parseEndpoints)) return string.Empty;
- return string.Join(",",
- parseEndpoints.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- .Where(item => !string.IsNullOrWhiteSpace(item))
- .Distinct(StringComparer.Ordinal)
- .OrderBy(item => item, StringComparer.Ordinal));
- }
- }
|