using CSRedis;
using dodohold.core;
namespace molilian.core
{
///
/// 隐藏号判断:隐藏号命中的转链只返回 deeplink,不产生任何日志、统计、上报数据
///
public static class HiddenAccountCore
{
// 同一隐藏号当天同 ip / oaid 只转成功一次
private const int OnceDoneExpireSeconds = 86400;
// 转链进行中的占位,防止同一用户并发请求重复转成功
private const int OncePendingExpireSeconds = 120;
public static Task IsHiddenAsync(TkChannelEnum channel, int accountId)
{
return IsHiddenAsync(channel.ToString(), accountId);
}
public static async Task 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;
}
}
///
/// 占用隐藏号当天的 ip / oaid 名额。当天已转成功或正在转链时返回 false。
///
public static bool TryReserveOnce(TkChannelEnum channel, int accountId, string ip, string oaid)
{
var keys = BuildOnceKeys(channel, accountId, ip, oaid);
var reserved = new List();
foreach (var key in keys)
{
if (!RedisHelper.Set(key, "pending", OncePendingExpireSeconds, RedisExistence.Nx))
{
if (reserved.Count > 0) RedisHelper.Del(reserved.ToArray());
return false;
}
reserved.Add(key);
}
return true;
}
///
/// 转链结束:成功则标记当天已转(同步到所有节点),失败则释放占位
///
public static async Task CompleteOnceAsync(TkChannelEnum channel, int accountId, string ip, string oaid, bool success)
{
var keys = BuildOnceKeys(channel, accountId, ip, oaid);
if (keys.Count == 0) return;
try
{
if (!success)
{
RedisHelper.Del(keys.ToArray());
return;
}
foreach (var key in keys) RedisHelper.Set(key, "done", OnceDoneExpireSeconds);
await EndPointCore.ProcessEndPointNodesAsync(node =>
{
if (string.IsNullOrEmpty(node.redis_server)) return Task.CompletedTask;
if (!node.is_public_api) return Task.CompletedTask;
try
{
var redis = RedisClientManager.GetRedisClient(node.redis_server);
foreach (var key in keys) redis.Set(key, "done", OnceDoneExpireSeconds);
}
catch (Exception ex)
{
_ = new LoggerLibrary("HiddenAccountCore", "CompleteOnce")
.Info(node.name, ex.Message)
.SaveAsync();
}
return Task.CompletedTask;
});
}
catch (Exception ex)
{
_ = new LoggerLibrary("HiddenAccountCore", "CompleteOnce")
.Info(ex.Message, ex.StackTrace)
.SaveAsync();
}
}
private static List BuildOnceKeys(TkChannelEnum channel, int accountId, string ip, string oaid)
{
string prefix = $":hide_once:{channel}_{accountId}:{DateTime.Now:yyyyMMdd}";
var keys = new List();
if (!string.IsNullOrEmpty(ip)) keys.Add($"{prefix}:ip:{ip}");
if (!string.IsNullOrEmpty(oaid)) keys.Add($"{prefix}:oaid:{oaid}");
return keys;
}
}
}