| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- using dodohold.core;
- namespace molilian.core
- {
- /// <summary>
- /// 隐藏号判断:隐藏号命中的转链只返回 deeplink,照常写转链日志,但不产生任何统计、上报数据
- /// </summary>
- public static class HiddenAccountCore
- {
- private const int LimitExpireSeconds = 86400;
- public static Task<bool> IsHiddenAsync(TkChannelEnum channel, int accountId)
- {
- return IsHiddenAsync(channel.ToString(), accountId);
- }
- public static async Task<bool> IsHiddenAsync(string channel, int accountId)
- {
- if (accountId <= 0) return false;
- switch ((channel ?? string.Empty).ToLowerInvariant())
- {
- case "tb":
- var tbAccount = await TkPoolCore.ALLGetOneAsync(accountId);
- return tbAccount != null && tbAccount.is_hide;
- case "pdd":
- var pddAccounts = await PddPoolCore.AllListAsync();
- var pddAccount = pddAccounts?.FirstOrDefault(e => e.id == accountId);
- return pddAccount != null && pddAccount.is_hide;
- default:
- return false;
- }
- }
- /// <summary>
- /// 隐藏号专用限制(config 配置,所有隐藏号共用,淘宝/拼多多分开计数):
- /// 城市过滤 + 同 IP / OAID 每天转成功次数。通过时占用名额,转链结束后调用 CompleteLimitAsync。
- /// </summary>
- public static bool TryReserveLimit(TkChannelEnum channel, string ip, string oaid, out HiddenLimitTicket ticket, out string reason)
- {
- ticket = new HiddenLimitTicket();
- reason = string.Empty;
- if (TestParseCore.InWhitelist(ip, oaid)) return true;
- try
- {
- var config = TkConfigCore.Get();
- if (config == null) return true;
- if (!string.IsNullOrEmpty(config.hide_ignore_city))
- {
- string? ipInfo = IP2RegionPlus.Search(ip);
- if (AlimamaPlus.IgnoreRegionIncluded(config.hide_ignore_city, ipInfo, out string regionInfo))
- {
- reason = $"地区控制:{regionInfo}";
- return false;
- }
- }
- string date = DateTime.Now.ToString("yyyyMMdd");
- if (!TryReserveCount(BuildLimitKey(channel, date, "ip", ip), config.hide_limit_per_ip_24h, ticket))
- {
- ReleaseReserved(ticket);
- reason = "IP控制";
- return false;
- }
- if (!TryReserveCount(BuildLimitKey(channel, date, "oaid", oaid), config.hide_limit_per_oaid_24h, ticket))
- {
- ReleaseReserved(ticket);
- reason = "OAID控制";
- return false;
- }
- return true;
- }
- catch (Exception ex)
- {
- // 与全局限制一致:异常时不拦截
- _ = new LoggerLibrary("HiddenAccountCore", "TryReserveLimit")
- .Info(ex.Message, ex.StackTrace)
- .SaveAsync();
- return true;
- }
- }
- /// <summary>
- /// 转链结束:成功则计入当天次数(同步到其他节点),失败则归还占用的名额
- /// </summary>
- public static async Task CompleteLimitAsync(HiddenLimitTicket ticket, bool success)
- {
- if (ticket == null || ticket.Keys.Count == 0) return;
- try
- {
- if (!success)
- {
- ReleaseReserved(ticket);
- return;
- }
- // 本节点在占用时已计数,只同步到其他节点
- await EndPointCore.ProcessEndPointNodesAsync(node =>
- {
- if (string.IsNullOrEmpty(node.redis_server)) return Task.CompletedTask;
- if (!node.is_public_api) return Task.CompletedTask;
- if (string.Equals(node.name, EndPointCore.CurrentEndPoint, StringComparison.OrdinalIgnoreCase)) return Task.CompletedTask;
- try
- {
- var redis = RedisClientManager.GetRedisClient(node.redis_server);
- foreach (var key in ticket.Keys)
- {
- redis.IncrBy(key);
- redis.Expire(key, LimitExpireSeconds);
- }
- }
- catch (Exception ex)
- {
- _ = new LoggerLibrary("HiddenAccountCore", "CompleteLimit")
- .Info(node.name, ex.Message)
- .SaveAsync();
- }
- return Task.CompletedTask;
- });
- }
- catch (Exception ex)
- {
- _ = new LoggerLibrary("HiddenAccountCore", "CompleteLimit")
- .Info(ex.Message, ex.StackTrace)
- .SaveAsync();
- }
- }
- private static bool TryReserveCount(string key, int limit, HiddenLimitTicket ticket)
- {
- if (limit <= 0 || string.IsNullOrEmpty(key)) return true;
- long count = RedisHelper.IncrBy(key);
- RedisHelper.Expire(key, LimitExpireSeconds);
- if (count > limit)
- {
- RedisHelper.IncrBy(key, -1);
- return false;
- }
- ticket.Keys.Add(key);
- return true;
- }
- private static void ReleaseReserved(HiddenLimitTicket ticket)
- {
- foreach (var key in ticket.Keys) RedisHelper.IncrBy(key, -1);
- ticket.Keys.Clear();
- }
- private static string BuildLimitKey(TkChannelEnum channel, string date, string type, string value)
- {
- if (string.IsNullOrEmpty(value)) return string.Empty;
- return $":hide_limit:{channel}:{date}:{type}:{value}";
- }
- }
- /// <summary>
- /// 隐藏号限制占用的名额(Redis 计数 key)
- /// </summary>
- public sealed class HiddenLimitTicket
- {
- public List<string> Keys { get; } = [];
- }
- }
|