|
@@ -47,69 +47,91 @@ class AutoJob extends Command
|
|
|
|
|
|
private function blockUsers(): void
|
|
|
{
|
|
|
- // 禁用流量超限用户
|
|
|
+ // 封顶禁用:已使用流量 >= 配额
|
|
|
User::activeUser()
|
|
|
->whereRaw('u + d >= transfer_enable')
|
|
|
->chunk(100, function ($users) {
|
|
|
foreach ($users as $user) {
|
|
|
- $user->update(['enable' => 0]);
|
|
|
- Helpers::addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
|
|
|
- \Log::info('用户流量超限被封禁', [
|
|
|
- 'user_id' => $user->id,
|
|
|
- 'email' => $user->email,
|
|
|
- 'used_traffic' => $user->u + $user->d,
|
|
|
- 'transfer_enable' => $user->transfer_enable,
|
|
|
- 'ban_time' => now()
|
|
|
- ]);
|
|
|
+ try {
|
|
|
+ $user->update(['enable' => 0]);
|
|
|
+ Helpers::addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
|
|
|
+ \Log::info('用户流量超限被封禁', [
|
|
|
+ 'user_id' => $user->id,
|
|
|
+ 'email' => $user->email,
|
|
|
+ 'used_traffic' => $user->u + $user->d,
|
|
|
+ 'transfer_enable' => $user->transfer_enable,
|
|
|
+ 'ban_time' => now()
|
|
|
+ ]);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ \Log::error("封禁超限用户失败 [ID: {$user->id}]", [
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- // 封禁最近1小时内流量异常账号(直接用UserDataFlowLog统计)
|
|
|
+ // 加权封禁:1小时内加权流量超限
|
|
|
if (sysConfig('is_traffic_ban')) {
|
|
|
$trafficBanTime = sysConfig('traffic_ban_time');
|
|
|
- $trafficBanValue = sysConfig('traffic_ban_value') * GB;
|
|
|
+ $baseTrafficBanValue = sysConfig('traffic_ban_value') * GB;
|
|
|
$oneHourAgo = time() - 3600;
|
|
|
|
|
|
- // 查询最近1小时内流量超限的用户ID
|
|
|
- $abnormalUserIds = UserDataFlowLog::where('log_time', '>=', $oneHourAgo)
|
|
|
- ->selectRaw('user_id, SUM(u + d) as total_traffic')
|
|
|
- ->groupBy('user_id')
|
|
|
- ->having('total_traffic', '>', $trafficBanValue)
|
|
|
- ->pluck('user_id')
|
|
|
- ->toArray();
|
|
|
+ // 提前加载所有节点到内存,避免 N+1 查询
|
|
|
+ $nodes = Node::all()->keyBy('id');
|
|
|
+
|
|
|
+ // 加权流量累加器
|
|
|
+ $userWeightedTotals = [];
|
|
|
+
|
|
|
+ UserDataFlowLog::where('log_time', '>=', $oneHourAgo)
|
|
|
+ ->chunk(1000, function ($records) use (&$userWeightedTotals, $nodes) {
|
|
|
+ foreach ($records as $record) {
|
|
|
+ $user_id = $record->user_id;
|
|
|
+ $node = $nodes->get($record->node_id);
|
|
|
+ $rate = $node ? ($node->traffic_rate > 0 ? $node->traffic_rate : 1) : 1;
|
|
|
+
|
|
|
+ $weighted = ($record->u + $record->d) / $rate;
|
|
|
+
|
|
|
+ if (!isset($userWeightedTotals[$user_id])) {
|
|
|
+ $userWeightedTotals[$user_id] = 0;
|
|
|
+ }
|
|
|
+ $userWeightedTotals[$user_id] += $weighted;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ $abnormalUserIds = [];
|
|
|
+ foreach ($userWeightedTotals as $user_id => $weightedTotal) {
|
|
|
+ if ($weightedTotal > $baseTrafficBanValue) {
|
|
|
+ $user = User::find($user_id);
|
|
|
+ if (!$user) {
|
|
|
+ \Log::warning("⚠️ 找不到用户 [ID: $user_id],跳过封禁");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ \Log::warning("⚠️ 用户 [ID: $user_id, 邮箱: {$user->email}] 1小时流量为 ".flowAutoShow($weightedTotal).",超出阈值 ".flowAutoShow($baseTrafficBanValue));
|
|
|
+ $abnormalUserIds[] = $user_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (!empty($abnormalUserIds)) {
|
|
|
\Log::info('发现流量异常用户', [
|
|
|
'count' => count($abnormalUserIds),
|
|
|
- 'user_ids' => $abnormalUserIds
|
|
|
+ 'user_ids' => $abnormalUserIds,
|
|
|
]);
|
|
|
|
|
|
User::activeUser()
|
|
|
->whereIn('id', $abnormalUserIds)
|
|
|
->whereBanTime(null)
|
|
|
- ->chunk(100, function ($users) use ($trafficBanTime, $trafficBanValue, $oneHourAgo) {
|
|
|
+ ->chunk(100, function ($users) use ($trafficBanTime) {
|
|
|
foreach ($users as $user) {
|
|
|
try {
|
|
|
- // 重新统计该用户最近1小时的总流量
|
|
|
- $total = UserDataFlowLog::where('user_id', $user->id)
|
|
|
- ->where('log_time', '>=', $oneHourAgo)
|
|
|
- ->sum(\DB::raw('u + d'));
|
|
|
- $banValueStr = flowAutoShow($trafficBanValue);
|
|
|
- $usedStr = flowAutoShow($total);
|
|
|
-
|
|
|
- \Log::warning('⚠️ 用户流量异常封禁 | ID: '.$user->id.' | 邮箱: '.$user->email.' | 1小时内已用流量: '.$usedStr.',阈值: '.$banValueStr.'(已超限)');
|
|
|
-
|
|
|
$user->update([
|
|
|
'enable' => 0,
|
|
|
- 'ban_time' => strtotime("+$trafficBanTime minutes")
|
|
|
+ 'ban_time' => strtotime("+$trafficBanTime minutes"),
|
|
|
]);
|
|
|
$user->refresh();
|
|
|
-
|
|
|
Helpers::addUserBanLog($user->id, $trafficBanTime, '【临时封禁代理】-1小时内流量异常');
|
|
|
- } catch (\Exception $e) {
|
|
|
- \Log::error('封禁流量异常用户失败', [
|
|
|
- 'user_id' => $user->id,
|
|
|
- 'error' => $e->getMessage()
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ \Log::error("封禁加权流量异常用户失败 [ID: {$user->id}]", [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
]);
|
|
|
}
|
|
|
}
|