feat: ws notify nodes when user traffic is exhausted

This commit is contained in:
xboard
2026-03-25 01:44:55 +08:00
parent 7dacb69275
commit 73a37a07dd
5 changed files with 74 additions and 8 deletions

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Console\Commands;
use App\Models\Server;
use App\Models\User;
use App\Services\NodeSyncService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class CheckTrafficExceeded extends Command
{
protected $signature = 'check:traffic-exceeded';
protected $description = '检查流量超标用户并通知节点';
public function handle()
{
$count = Redis::scard('traffic:pending_check');
if ($count <= 0) {
return;
}
$pendingUserIds = array_map('intval', Redis::spop('traffic:pending_check', $count));
$exceededUsers = User::toBase()
->whereIn('id', $pendingUserIds)
->whereRaw('u + d >= transfer_enable')
->where('transfer_enable', '>', 0)
->where('banned', 0)
->select(['id', 'group_id'])
->get();
if ($exceededUsers->isEmpty()) {
return;
}
$groupedUsers = $exceededUsers->groupBy('group_id');
$notifiedCount = 0;
foreach ($groupedUsers as $groupId => $users) {
if (!$groupId) {
continue;
}
$userIdsInGroup = $users->pluck('id')->toArray();
$servers = Server::whereJsonContains('group_ids', (string) $groupId)->get();
foreach ($servers as $server) {
if (!NodeSyncService::isNodeOnline($server->id)) {
continue;
}
NodeSyncService::push($server->id, 'sync.user.delta', [
'action' => 'remove',
'users' => array_map(fn($id) => ['id' => $id], $userIdsInGroup),
]);
$notifiedCount++;
}
}
$this->info("Checked " . count($pendingUserIds) . " users, notified {$notifiedCount} nodes for " . $exceededUsers->count() . " exceeded users.");
}
}

View File

@@ -35,6 +35,7 @@ class Kernel extends ConsoleKernel
$schedule->command('check:order')->everyMinute()->onOneServer()->withoutOverlapping(5);
$schedule->command('check:commission')->everyMinute()->onOneServer()->withoutOverlapping(5);
$schedule->command('check:ticket')->everyMinute()->onOneServer()->withoutOverlapping(5);
$schedule->command('check:traffic-exceeded')->everyMinute()->onOneServer()->withoutOverlapping(10);
// reset
$schedule->command('reset:traffic')->everyMinute()->onOneServer()->withoutOverlapping(10);
$schedule->command('reset:log')->daily()->onOneServer();