HiddenAccountCore.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using CSRedis;
  2. using dodohold.core;
  3. namespace molilian.core
  4. {
  5. /// <summary>
  6. /// 隐藏号判断:隐藏号命中的转链只返回 deeplink,不产生任何日志、统计、上报数据
  7. /// </summary>
  8. public static class HiddenAccountCore
  9. {
  10. // 同一隐藏号当天同 ip / oaid 只转成功一次
  11. private const int OnceDoneExpireSeconds = 86400;
  12. // 转链进行中的占位,防止同一用户并发请求重复转成功
  13. private const int OncePendingExpireSeconds = 120;
  14. public static Task<bool> IsHiddenAsync(TkChannelEnum channel, int accountId)
  15. {
  16. return IsHiddenAsync(channel.ToString(), accountId);
  17. }
  18. public static async Task<bool> IsHiddenAsync(string channel, int accountId)
  19. {
  20. if (accountId <= 0) return false;
  21. switch ((channel ?? string.Empty).ToLowerInvariant())
  22. {
  23. case "tb":
  24. var tbAccount = await TkPoolCore.ALLGetOneAsync(accountId);
  25. return tbAccount != null && tbAccount.is_hide;
  26. case "pdd":
  27. var pddAccounts = await PddPoolCore.AllListAsync();
  28. var pddAccount = pddAccounts?.FirstOrDefault(e => e.id == accountId);
  29. return pddAccount != null && pddAccount.is_hide;
  30. default:
  31. return false;
  32. }
  33. }
  34. /// <summary>
  35. /// 占用隐藏号当天的 ip / oaid 名额。当天已转成功或正在转链时返回 false。
  36. /// </summary>
  37. public static bool TryReserveOnce(TkChannelEnum channel, int accountId, string ip, string oaid)
  38. {
  39. var keys = BuildOnceKeys(channel, accountId, ip, oaid);
  40. var reserved = new List<string>();
  41. foreach (var key in keys)
  42. {
  43. if (!RedisHelper.Set(key, "pending", OncePendingExpireSeconds, RedisExistence.Nx))
  44. {
  45. if (reserved.Count > 0) RedisHelper.Del(reserved.ToArray());
  46. return false;
  47. }
  48. reserved.Add(key);
  49. }
  50. return true;
  51. }
  52. /// <summary>
  53. /// 转链结束:成功则标记当天已转(同步到所有节点),失败则释放占位
  54. /// </summary>
  55. public static async Task CompleteOnceAsync(TkChannelEnum channel, int accountId, string ip, string oaid, bool success)
  56. {
  57. var keys = BuildOnceKeys(channel, accountId, ip, oaid);
  58. if (keys.Count == 0) return;
  59. try
  60. {
  61. if (!success)
  62. {
  63. RedisHelper.Del(keys.ToArray());
  64. return;
  65. }
  66. foreach (var key in keys) RedisHelper.Set(key, "done", OnceDoneExpireSeconds);
  67. await EndPointCore.ProcessEndPointNodesAsync(node =>
  68. {
  69. if (string.IsNullOrEmpty(node.redis_server)) return Task.CompletedTask;
  70. if (!node.is_public_api) return Task.CompletedTask;
  71. try
  72. {
  73. var redis = RedisClientManager.GetRedisClient(node.redis_server);
  74. foreach (var key in keys) redis.Set(key, "done", OnceDoneExpireSeconds);
  75. }
  76. catch (Exception ex)
  77. {
  78. _ = new LoggerLibrary("HiddenAccountCore", "CompleteOnce")
  79. .Info(node.name, ex.Message)
  80. .SaveAsync();
  81. }
  82. return Task.CompletedTask;
  83. });
  84. }
  85. catch (Exception ex)
  86. {
  87. _ = new LoggerLibrary("HiddenAccountCore", "CompleteOnce")
  88. .Info(ex.Message, ex.StackTrace)
  89. .SaveAsync();
  90. }
  91. }
  92. private static List<string> BuildOnceKeys(TkChannelEnum channel, int accountId, string ip, string oaid)
  93. {
  94. string prefix = $":hide_once:{channel}_{accountId}:{DateTime.Now:yyyyMMdd}";
  95. var keys = new List<string>();
  96. if (!string.IsNullOrEmpty(ip)) keys.Add($"{prefix}:ip:{ip}");
  97. if (!string.IsNullOrEmpty(oaid)) keys.Add($"{prefix}:oaid:{oaid}");
  98. return keys;
  99. }
  100. }
  101. }