123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <?php
- namespace App\Console\Commands;
- use App\Models\Node;
- use App\Models\NodeDailyDataFlow;
- use App\Models\Ticket;
- use App\Models\User;
- use App\Notifications\TicketClosed;
- use App\Services\OrderService;
- use App\Utils\Helpers;
- use DB;
- use Illuminate\Console\Command;
- use Illuminate\Database\Eloquent\Builder;
- use Log;
- class TaskDaily extends Command
- {
- protected $signature = 'task:daily';
- protected $description = '每日任务';
- public function handle(): void
- {
- $jobTime = microtime(true);
- $this->expireUser(); // 过期用户处理
- $this->closeTickets(); // 关闭用户超时未处理的工单
- if (sysConfig('reset_traffic')) {
- $this->resetUserTraffic(); // 重置用户流量
- }
- if (sysConfig('auto_release_port')) {
- $this->releaseAccountPort(); // 账号端口回收
- }
- $this->userTrafficStatistics(); // 用户每日流量统计
- $this->nodeTrafficStatistics(); // 节点每日流量统计
- $jobTime = round(microtime(true) - $jobTime, 4);
- Log::info(__('----「:job」Completed, Used :time seconds ----', ['job' => $this->description, 'time' => $jobTime]));
- }
- private function expireUser(): void
- { // 过期用户处理
- $isBanStatus = sysConfig('is_ban_status');
- $dirtyWorks = [
- 'u' => 0,
- 'd' => 0,
- 'transfer_enable' => 0,
- 'enable' => 0,
- 'level' => 0,
- 'reset_time' => null,
- 'ban_time' => null,
- ]; // 清理账号 & 停止服务
- $banMsg = __('[Daily Task] Account Expiration: Stop Service');
- if ($isBanStatus) {
- $dirtyWorks['status'] = -1; // 封禁账号
- $banMsg = __('[Daily Task] Account Expiration: Block Login & Clear Account');
- }
- User::activeUser()->where('expired_at', '<', date('Y-m-d')) // 过期
- ->chunk(config('tasks.chunk'), function ($users) use ($banMsg, $dirtyWorks) {
- $users->each(function ($user) use ($banMsg, $dirtyWorks) {
- $user->update($dirtyWorks);
- Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, $banMsg);
- $user->banedLogs()->create(['description' => $banMsg]);
- });
- });
- }
- private function closeTickets(): void
- { // 关闭用户超时未处理的工单
- $closeTicketsHours = config('tasks.close.tickets');
- Ticket::whereStatus(1)->with('reply')->whereHas('reply', function ($query) {
- $query->where('admin_id', '<>', null);
- })->where('updated_at', '<=', now()->subHours($closeTicketsHours))->chunk(config('tasks.chunk'), function ($tickets) use ($closeTicketsHours) {
- $tickets->each(function ($ticket) use ($closeTicketsHours) {
- if ($ticket->close()) {
- $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('ticket.edit', $ticket),
- __('You have not responded this ticket in :num hours, System has closed your ticket.', ['num' => $closeTicketsHours])));
- }
- });
- });
- }
- private function resetUserTraffic(): void
- { // 重置用户流量
- $today = date('Y-m-d');
- User::where('status', '<>', -1)->where('expired_at', '>', $today)->where('reset_time', '<=', $today)->whereHas('orders', function ($query) {
- $query->activePlan();
- })->with(['orders' => function ($query) {
- $query->activePlan();
- }])->chunk(config('tasks.chunk'), function ($users) {
- $users->each(function ($user) {
- $user->orders()->activePackage()->update(['is_expire' => 1]); // 过期生效中的加油包
- $order = $user->orders->first(); // 取出用户正在使用的套餐
- $oldData = $user->transfer_enable;
- // 重置流量与重置日期
- if ($user->update((new OrderService($order))->resetTimeAndData($user->expired_at))) {
- Helpers::addUserTrafficModifyLog($order->user_id, $oldData, $user->transfer_enable, trans('[Daily Task] Reset Account Traffic, Next Reset Date: :date', ['date' => $user->reset_date]), $order->id);
- } else {
- Log::error(trans('notification.reset_failed', ['uid' => $user->id, 'username' => $user->username]));
- }
- });
- });
- }
- private function releaseAccountPort(): void
- { // 被封禁 / 过期N天 的账号自动释放端口
- User::where('port', '<>', 0)->where(function (Builder $query) {
- $query->whereStatus(-1)->orWhere('expired_at', '<=', date('Y-m-d', strtotime('-'.config('tasks.release_port').' days')));
- })->update(['port' => 0]);
- }
- private function userTrafficStatistics(): void
- {
- $created_at = date('Y-m-d 23:59:59', strtotime('yesterday'));
- $end = strtotime($created_at);
- $start = $end - 86399;
- User::activeUser()->whereHas('dataFlowLogs', function (Builder $query) use ($start, $end) {
- $query->whereBetween('log_time', [$start, $end]);
- })->with([
- 'dataFlowLogs' => function ($query) use ($start, $end) {
- $query->whereBetween('log_time', [$start, $end]);
- },
- ])->chunk(config('tasks.chunk'), function ($users) use ($created_at) {
- foreach ($users as $user) {
- $dataFlowLogs = $user->dataFlowLogs->groupBy('node_id');
- $data = $dataFlowLogs->map(function ($logs, $nodeId) use ($created_at) {
- $totals = $logs->reduce(function ($carry, $log) {
- $carry['u'] += $log['u'];
- $carry['d'] += $log['d'];
- return $carry;
- }, ['u' => 0, 'd' => 0]);
- return [
- 'node_id' => $nodeId,
- 'u' => $totals['u'],
- 'd' => $totals['d'],
- 'created_at' => $created_at,
- ];
- })->values()->all();
- $data[] = [ // 每日节点流量合计
- 'node_id' => null,
- 'u' => array_sum(array_column($data, 'u')),
- 'd' => array_sum(array_column($data, 'd')),
- 'created_at' => $created_at,
- ];
- $user->dailyDataFlows()->createMany($data);
- }
- });
- }
- private function nodeTrafficStatistics(): void
- {
- $created_at = date('Y-m-d 23:59:59', strtotime('yesterday'));
- $end = strtotime($created_at);
- $start = $end - 86399;
- Node::whereHas('userDataFlowLogs', function (Builder $query) use ($start, $end) {
- $query->whereBetween('log_time', [$start, $end]);
- })->withCount([
- 'userDataFlowLogs as u_sum' => function ($query) use ($start, $end) {
- $query->select(DB::raw('SUM(u)'))->whereBetween('log_time', [$start, $end]);
- },
- ])->withCount([
- 'userDataFlowLogs as d_sum' => function ($query) use ($start, $end) {
- $query->select(DB::raw('SUM(d)'))->whereBetween('log_time', [$start, $end]);
- },
- ])->chunk(config('tasks.chunk'), function ($nodes) use ($created_at) {
- foreach ($nodes as $node) {
- $node->dailyDataFlows()->create([
- 'u' => $node->u_sum,
- 'd' => $node->d_sum,
- 'created_at' => $created_at,
- ]);
- }
- });
- $dailyTotal = NodeDailyDataFlow::whereNotNull('node_id')->whereCreatedAt($created_at)->selectRaw('SUM(u) as total_u, SUM(d) as total_d')->first();
- if ($dailyTotal) {
- NodeDailyDataFlow::create([
- 'u' => $dailyTotal->total_u,
- 'd' => $dailyTotal->total_d,
- 'created_at' => $created_at,
- ]);
- }
- }
- }
|