using dodohold.core; using System.Collections.Generic; using System.Data; using System.Security.Cryptography; using System.Text.RegularExpressions; using YunhuiKit; namespace molilian.core { public partial class OverrideRuleCore { private static IEnumerable _cached; private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public static async Task> ListAsync(bool force = false) { #if DEBUG return new DBContext.Table("tk_override_rules") .Where("status=@status", new { status = 1 }) .Order("sort DESC, id DESC") .Select(); #endif if (!force && _cached != null) return _cached; try { await _semaphore.WaitAsync(); // 如果缓存存在且未强制刷新,直接返回 if (!force && _cached != null) return _cached; string cache_key = $"cache:tk_override_rules"; IEnumerable? list = null; // 尝试从Redis获取数据 try { list = await RedisKit.GetAsync>(cache_key); } catch (Exception ex) { // 记录Redis错误 _ = new LoggerLibrary("OverrideRule", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync(); } // 如果Redis获取失败或需要强制刷新 if (force || list == null) { try { list = new DBContext.Table("tk_override_rules") .Where("status=@status", new { status = 1 }) .Order("sort DESC, id DESC") .Select(); if (list != null && list.Any()) { // 尝试更新Redis缓存 try { await RedisKit.SetAsync(cache_key, list, 30 * 86400); } catch (Exception ex) { // 记录Redis更新错误 _ = new LoggerLibrary("OverrideRule", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync(); } } } catch (Exception ex) { // 记录数据库查询错误 _ = new LoggerLibrary("OverrideRule", "Database").Info(ex.Message, ex.StackTrace).SaveAsync(); // 如果数据库查询失败但缓存还在,继续使用缓存 if (_cached != null) return _cached; throw; // 如果没有任何可用数据,则抛出异常 } } _cached = list; return list ?? []; } finally { _semaphore.Release(); } } public static async Task ProcessAsync(string platform, string content, string ip, string oaid, string riskStrategy, int launchScene, int special_text) { if (string.IsNullOrEmpty(platform)) return null; var list = await ListAsync(); if (list == default) return null; foreach (var item in list) { if (!platform.Equals(item.platform)) continue; if (string.IsNullOrEmpty(item.original_text)) continue; switch (item.rule) { case "regex": Match match = Regex.Match(content, item.original_text); if (!match.Success) continue; break; case "text": if (!content.Equals(item.original_text)) continue; break; default: if (!content.Contains(item.original_text)) continue; break; } if (item.use_risk_control) { bool is_ignore = AlimamaPlus.ShouldIgnoreRequest(ip, oaid, riskStrategy, launchScene, out _); if (is_ignore) continue; } if (item.use_special_text == 1 && special_text != 1) continue; // 每小时调用次数统计(无论是否设置限制都要记录) string hourlyKey = $":override_rule_calls:{item.id}:{DateTime.Now:yyyyMMddHH}"; try { long currentHourlyCalls = await RedisKit.IncrByAsync(hourlyKey); // 如果是第一次调用,设置过期时间为2小时 if (currentHourlyCalls < 10) { await RedisKit.ExpireAsync(hourlyKey, 7200); // 2小时 } // 如果设置了每小时限制且超过限制,跳过该规则 if (item.hourly_calls_limit > 0 && currentHourlyCalls > item.hourly_calls_limit) continue; } catch (Exception ex) { // Redis错误时记录日志但不阻塞业务 _ = new LoggerLibrary("OverrideRule", "Redis").Info($"Hourly limit check failed: {ex.Message}", ex.StackTrace).SaveAsync(); } // 每日调用次数统计(无论是否设置限制都要记录) string dailyKey = $":override_rule_calls:{item.id}:{DateTime.Now:yyyyMMdd}"; try { long currentDailyCalls = await RedisKit.IncrByAsync(dailyKey); if (currentDailyCalls < 10) { await RedisKit.ExpireAsync(dailyKey, 259200); // 3天 } // 如果设置了每日限制且超过限制,跳过该规则 if (item.daily_calls_limit > 0 && currentDailyCalls >= item.daily_calls_limit) continue; } catch (Exception ex) { // Redis错误时记录日志但不阻塞业务 _ = new LoggerLibrary("OverrideRule", "Redis").Info($"Daily limit check failed: {ex.Message}", ex.StackTrace).SaveAsync(); } return item; } return null; } public static void Refresh() { _cached = null; _ = ListAsync(true); } public static int Update(OverrideRuleDTO data, IDbConnection conn) { var result = (int)conn.Update(data, new { data.id }); _ = ListAsync(true); #if DEBUG #else EndPointCore.NotifyReload(); #endif return result; } public static int Create(OverrideRuleDTO data, IDbConnection conn) { var result = (int)conn.Insert(data); _ = ListAsync(true); #if DEBUG #else EndPointCore.NotifyReload(); #endif return result; } } }