|
@@ -29,10 +29,7 @@ namespace molilian.core
|
|
|
private static Dictionary<string, decimal> _incomeAmt = new();
|
|
private static Dictionary<string, decimal> _incomeAmt = new();
|
|
|
private static ConcurrentDictionary<int, DateTime> _suspend = new();
|
|
private static ConcurrentDictionary<int, DateTime> _suspend = new();
|
|
|
|
|
|
|
|
- // 添加本地内存统计 - 线程安全
|
|
|
|
|
- private static readonly ConcurrentDictionary<string, int> _dailyUsage = new();
|
|
|
|
|
- private static volatile string _currentDay = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
- private static readonly object _dayResetLock = new object(); // 专用于日期重置的锁
|
|
|
|
|
|
|
+ // 移除本地内存统计,改用 Redis 存储
|
|
|
|
|
|
|
|
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
|
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
|
|
|
|
|
|
|
@@ -58,73 +55,140 @@ namespace molilian.core
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return list.Where(e => IsMatch(e, mode, accountid))
|
|
return list.Where(e => IsMatch(e, mode, accountid))
|
|
|
- .OrderBy(account => GetCurrentDayUsage(account.id))
|
|
|
|
|
|
|
+ .OrderBy(account => GetCurrentDayUsageFromRedis(account.id))
|
|
|
.ThenBy(account => account.id) // 相同使用次数时按ID排序,确保稳定性
|
|
.ThenBy(account => account.id) // 相同使用次数时按ID排序,确保稳定性
|
|
|
.FirstOrDefault();
|
|
.FirstOrDefault();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private static int GetCurrentDayUsage(int accountId)
|
|
|
|
|
|
|
+ private static int GetCurrentDayUsageFromRedis(int accountId)
|
|
|
{
|
|
{
|
|
|
- CheckAndResetDailyStats();
|
|
|
|
|
- string currentDay = _currentDay; // 获取当前快照,避免在构建key过程中被修改
|
|
|
|
|
- string key = $"{accountId}_{currentDay}";
|
|
|
|
|
- return _dailyUsage.GetOrAdd(key, 0);
|
|
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ string key = $"pdd_daily_usage:{accountId}:{today}";
|
|
|
|
|
+ return RedisHelper.Get<int>(key);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception)
|
|
|
|
|
+ {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private static void CheckAndResetDailyStats()
|
|
|
|
|
|
|
+ internal static void UpdateAccountUsage(int accountId)
|
|
|
{
|
|
{
|
|
|
- var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ string key = $"pdd_daily_usage:{accountId}:{today}";
|
|
|
|
|
|
|
|
- // 使用volatile读取,如果日期相同则直接返回,避免锁开销
|
|
|
|
|
- if (today == _currentDay) return;
|
|
|
|
|
|
|
+ // 递增计数并设置24小时过期时间
|
|
|
|
|
+ RedisHelper.IncrBy(key);
|
|
|
|
|
+ RedisHelper.Expire(key, 86400); // 24小时后自动过期
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 记录错误但不影响主流程
|
|
|
|
|
+ Console.WriteLine($"Failed to update account usage for {accountId}: {ex.Message}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 只有在日期不同时才尝试获取锁
|
|
|
|
|
- lock (_dayResetLock)
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 获取当前所有账号的平均使用次数
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private static int GetAverageUsageCount()
|
|
|
|
|
+ {
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- // 双重检查:再次验证日期是否需要重置
|
|
|
|
|
- if (today != _currentDay)
|
|
|
|
|
- {
|
|
|
|
|
- // 清空所有统计数据
|
|
|
|
|
- _dailyUsage.Clear();
|
|
|
|
|
|
|
+ var activeAccounts = List()?.Where(a => a.enable_parse).ToList();
|
|
|
|
|
+ if (activeAccounts == null || !activeAccounts.Any()) return 0;
|
|
|
|
|
|
|
|
- // 原子性更新当前日期(volatile写入)
|
|
|
|
|
- _currentDay = today;
|
|
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ var totalUsage = 0;
|
|
|
|
|
+ var validCount = 0;
|
|
|
|
|
|
|
|
- // 可选:记录日期切换日志
|
|
|
|
|
- Console.WriteLine($"Daily stats reset for date: {today}");
|
|
|
|
|
|
|
+ foreach (var account in activeAccounts)
|
|
|
|
|
+ {
|
|
|
|
|
+ var usage = GetCurrentDayUsageFromRedis(account.id);
|
|
|
|
|
+ totalUsage += usage;
|
|
|
|
|
+ validCount++;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return validCount > 0 ? totalUsage / validCount : 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.WriteLine($"Failed to get average usage count: {ex.Message}");
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- internal static void UpdateAccountUsage(int accountId)
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 为新上线的账号设置平均使用次数,避免流量集中
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static void InitializeNewAccountUsage(int accountId)
|
|
|
{
|
|
{
|
|
|
- CheckAndResetDailyStats();
|
|
|
|
|
- string currentDay = _currentDay; // 获取当前快照,确保一致性
|
|
|
|
|
- string key = $"{accountId}_{currentDay}";
|
|
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ string key = $"pdd_daily_usage:{accountId}:{today}";
|
|
|
|
|
|
|
|
- // 使用AddOrUpdate确保原子性递增
|
|
|
|
|
- _dailyUsage.AddOrUpdate(key, 1, (k, oldValue) => oldValue + 1);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 检查该账号今天是否已有使用记录
|
|
|
|
|
+ var currentUsage = RedisHelper.Get<int>(key);
|
|
|
|
|
+ if (currentUsage > 0) return; // 已有记录,不需要初始化
|
|
|
|
|
|
|
|
|
|
+ // 获取平均使用次数
|
|
|
|
|
+ var averageUsage = GetAverageUsageCount();
|
|
|
|
|
+ if (averageUsage > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 设置为平均值,避免新账号因为使用次数为0而被优先选择
|
|
|
|
|
+ RedisHelper.Set(key, averageUsage, 86400);
|
|
|
|
|
+ Console.WriteLine($"Initialized account {accountId} with average usage: {averageUsage}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.WriteLine($"Failed to initialize new account usage for {accountId}: {ex.Message}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// 获取当前统计信息(用于监控和调试)
|
|
|
|
|
|
|
+ /// 获取当前统计信息(用于监控和调试)- 改为从Redis获取
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
internal static Dictionary<string, int> GetCurrentUsageSnapshot()
|
|
internal static Dictionary<string, int> GetCurrentUsageSnapshot()
|
|
|
{
|
|
{
|
|
|
- CheckAndResetDailyStats();
|
|
|
|
|
- return new Dictionary<string, int>(_dailyUsage);
|
|
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ var pattern = $"pdd_daily_usage:*:{today}";
|
|
|
|
|
+
|
|
|
|
|
+ // 注意:这里只是示例,实际实现可能需要根据Redis客户端API调整
|
|
|
|
|
+ // 生产环境中应该避免使用KEYS命令,可以考虑其他方案
|
|
|
|
|
+ var result = new Dictionary<string, int>();
|
|
|
|
|
+ // TODO: 实现Redis pattern匹配获取所有相关keys
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception)
|
|
|
|
|
+ {
|
|
|
|
|
+ return new Dictionary<string, int>();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// 强制清理统计数据(仅用于测试或紧急情况)
|
|
|
|
|
|
|
+ /// 强制清理统计数据(仅用于测试或紧急情况)- Redis版本
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
internal static void ForceClearStats()
|
|
internal static void ForceClearStats()
|
|
|
{
|
|
{
|
|
|
- lock (_dayResetLock)
|
|
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- _dailyUsage.Clear();
|
|
|
|
|
- Console.WriteLine("Force cleared daily usage stats");
|
|
|
|
|
|
|
+ var today = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
+ var pattern = $"pdd_daily_usage:*:{today}";
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 实现Redis批量删除相关keys
|
|
|
|
|
+ // 生产环境中需要谨慎使用
|
|
|
|
|
+ Console.WriteLine("Force clear stats - Redis keys will auto-expire in 24h");
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.WriteLine($"Failed to force clear stats: {ex.Message}");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -364,7 +428,12 @@ namespace molilian.core
|
|
|
.Add("login_time", DateTime.Now)
|
|
.Add("login_time", DateTime.Now)
|
|
|
.Where("id=@id", new { exist.id })
|
|
.Where("id=@id", new { exist.id })
|
|
|
.Update();
|
|
.Update();
|
|
|
- if (status) _ = List(true);
|
|
|
|
|
|
|
+ if (status)
|
|
|
|
|
+ {
|
|
|
|
|
+ _ = List(true);
|
|
|
|
|
+ // 为重新上线的账号初始化使用次数
|
|
|
|
|
+ InitializeNewAccountUsage(exist.id);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -382,6 +451,9 @@ namespace molilian.core
|
|
|
.Add("login_time", DateTime.Now)
|
|
.Add("login_time", DateTime.Now)
|
|
|
.Add("status", 0)
|
|
.Add("status", 0)
|
|
|
.Create();
|
|
.Create();
|
|
|
|
|
+
|
|
|
|
|
+ // 为新创建的账号初始化使用次数(如果将来会启用的话)
|
|
|
|
|
+ // InitializeNewAccountUsage(accountId); // 暂不调用,因为新创建的账号status=0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NotifyCore.Notify(new NifyMessage
|
|
NotifyCore.Notify(new NifyMessage
|