| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- using dodohold.core;
- using System.Globalization;
- namespace molilian.core
- {
- public partial class OverrideRuleCore
- {
- // KEYS: 小时触发、日触发、小时重写、日重写。沿用现有 key,保留历史数据。
- // 同一脚本内检查两项额度并更新计数,避免并发超额或只扣掉其中一项额度。
- private const string RecordRewriteScript = @"
- local hourlyRewrites = tonumber(redis.call('GET', KEYS[3]) or '0')
- local dailyRewrites = tonumber(redis.call('GET', KEYS[4]) or '0')
- local hourlyLimit = tonumber(ARGV[1])
- local dailyLimit = tonumber(ARGV[2])
- redis.call('INCR', KEYS[1])
- redis.call('EXPIRE', KEYS[1], 7200)
- redis.call('INCR', KEYS[2])
- redis.call('EXPIRE', KEYS[2], 259200)
- if (hourlyLimit > 0 and hourlyRewrites >= hourlyLimit)
- or (dailyLimit > 0 and dailyRewrites >= dailyLimit) then
- return 0
- end
- redis.call('INCR', KEYS[3])
- redis.call('EXPIRE', KEYS[3], 15552000)
- redis.call('INCR', KEYS[4])
- redis.call('EXPIRE', KEYS[4], 15552000)
- return 1";
- private static string[] GetCounterKeys(OverrideRuleDTO rule, DateTime now) =>
- [
- $":override_rule_calls:{rule.id}:{now:yyyyMMddHH}",
- $":override_rule_calls:{rule.id}:{now:yyyyMMdd}",
- $":keyword_stats:{rule.platform}:{rule.id}:{now:yyyyMMddHH}",
- $":keyword_stats:{rule.platform}:{rule.id}:{now:yyyyMMdd}"
- ];
- private static async Task<bool> TryRecordRewriteAsync(OverrideRuleDTO rule, DateTime now)
- {
- try
- {
- // RedisUtility 与 RedisKit 均使用 RedisConfig,复用已初始化的连接池。
- // CSRedis 高层 Eval 仅支持一个 key;这里通过原生接口显式传入全部四个 key。
- var pool = RedisHelper.Instance.Nodes.Values.Single();
- var connection = await pool.GetAsync();
- Exception? error = null;
- try
- {
- var keys = GetCounterKeys(rule, now).Select(key => pool.Prefix + key).ToArray();
- var result = await connection.Value.EvalAsync(RecordRewriteScript, keys,
- rule.hourly_calls_limit, rule.daily_calls_limit);
- return Convert.ToInt64(result, CultureInfo.InvariantCulture) == 1;
- }
- catch (Exception ex)
- {
- error = ex;
- throw;
- }
- finally
- {
- pool.Return(connection, error);
- }
- }
- catch (Exception ex)
- {
- _ = new LoggerLibrary("OverrideRule", "Redis")
- .Info($"Rewrite limit check failed: {ex.Message}", ex.StackTrace).SaveAsync();
- // 无法确认额度时跳过受限规则;无限额规则保留统计故障时继续工作的行为。
- return rule.hourly_calls_limit <= 0 && rule.daily_calls_limit <= 0;
- }
- }
- public static async Task LoadStatisticsAsync(OverrideRuleDTO rule, DateTime now)
- {
- var counts = await RedisHelper.MGetAsync<int>(GetCounterKeys(rule, now));
- rule.current_hourly_calls = counts[0];
- rule.current_daily_calls = counts[1];
- rule.current_hourly_rewrites = counts[2];
- rule.current_daily_rewrites = counts[3];
- }
- }
- }
|