where('status', HitAndRun::STATUS_INSPECTING) ->with([ 'torrent' => function ($query) {$query->select(['id', 'size', 'name']);}, 'snatch', 'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil']);}, 'user.language', ]); if (!is_null($uid)) { $query->where('uid', $uid); } if (!is_null($torrentId)) { $query->where('torrent_id', $torrentId); } if (!$ignoreTime) { $query->where('created_at', '<', Carbon::now()->subHours($setting['inspect_time'])); } $successCounts = 0; while (true) { $logPrefix = "page: $page, size: $size"; $rows = $query->forPage($page, $size)->get(); do_log("$logPrefix, counts: " . $rows->count()); if ($rows->isEmpty()) { do_log("$logPrefix, no more data..." . last_query()); break; } foreach ($rows as $row) { $currentLog = "$logPrefix, [HANDLING] " . $row->toJson(); do_log($logPrefix); if (!$row->user) { do_log("$currentLog, user not exists, skip!", 'error'); continue; } if (!$row->snatch) { do_log("$currentLog, snatch not exists, skip!", 'error'); continue; } if (!$row->torrent) { do_log("$currentLog, torrent not exists, skip!", 'error'); continue; } //If is VIP or above OR donated, pass if ($row->user->class >= HitAndRun::MINIMUM_IGNORE_USER_CLASS || $row->user->isDonating()) { $result = $this->reachedBySpecialUserClass($row); if ($result) { $successCounts++; } continue; } //check seed time $targetSeedTime = $row->snatch->seedtime; $requireSeedTime = bcmul($setting['seed_time_minimum'], 3600); do_log("$currentLog, targetSeedTime: $targetSeedTime, requireSeedTime: $requireSeedTime"); if ($targetSeedTime >= $requireSeedTime) { $result = $this->reachedBySeedTime($row); if ($result) { $successCounts++; } continue; } //check share ratio $targetShareRatio = bcdiv($row->snatch->uploaded, $row->torrent->size, 4); $requireShareRatio = $setting['ignore_when_ratio_reach']; do_log("$currentLog, targetShareRatio: $targetShareRatio, requireShareRatio: $requireShareRatio"); if ($targetShareRatio >= $requireShareRatio) { $result = $this->reachedByShareRatio($row); if ($result) { $successCounts++; } continue; } //unreached if ($row->created_at->addHours($setting['inspect_time'])->lte(Carbon::now())) { $result = $this->unreached($row); if ($result) { $successCounts++; } } } $page++; } do_log("[CRONJOB_UPDATE_HR_DONE]"); return $successCounts; } private function geReachedMessage(HitAndRun $hitAndRun): array { return [ 'receiver' => $hitAndRun->uid, 'added' => Carbon::now()->toDateTimeString(), 'subject' => nexus_trans('hr.reached_message_subject', ['hit_and_run_id' => $hitAndRun->id], $hitAndRun->user->locale), 'msg' => nexus_trans('hr.reached_message_content', [ 'completed_at' => $hitAndRun->snatch->completedat->toDateTimeString(), 'torrent_id' => $hitAndRun->torrent_id, 'torrent_name' => $hitAndRun->torrent->name, ], $hitAndRun->user->locale), ]; } private function reachedByShareRatio(HitAndRun $hitAndRun): bool { do_log(__METHOD__); $comment = nexus_trans('hr.reached_by_share_ratio_comment', [ 'now' => Carbon::now()->toDateTimeString(), 'seed_time_minimum' => Setting::get('hr.seed_time_minimum'), 'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1), 'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded), 'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach'), ], $hitAndRun->user->locale); $update = [ 'comment' => $comment ]; return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__); } private function reachedBySeedTime(HitAndRun $hitAndRun): bool { do_log(__METHOD__); $comment = nexus_trans('hr.reached_by_seed_time_comment', [ 'now' => Carbon::now()->toDateTimeString(), 'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1), 'seed_time_minimum' => Setting::get('hr.seed_time_minimum') ], $hitAndRun->user->locale); $update = [ 'comment' => $comment ]; return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__); } private function reachedBySpecialUserClass(HitAndRun $hitAndRun): bool { do_log(__METHOD__); $comment = nexus_trans('hr.reached_by_special_user_class_comment', [ 'user_class_text' => $hitAndRun->user->class_text, ], $hitAndRun->user->locale); $update = [ 'comment' => $comment ]; return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__); } private function inspectingToReached(HitAndRun $hitAndRun, array $update, string $logPrefix = ''): bool { $update['status'] = HitAndRun::STATUS_REACHED; $affectedRows = DB::table($hitAndRun->getTable()) ->where('id', $hitAndRun->id) ->where('status', HitAndRun::STATUS_INSPECTING) ->update($update); do_log("[$logPrefix], " . last_query() . ", affectedRows: $affectedRows"); if ($affectedRows != 1) { do_log($hitAndRun->toJson() . ", [$logPrefix], affectedRows != 1, skip!", 'notice'); return false; } $message = $this->geReachedMessage($hitAndRun); Message::query()->insert($message); return true; } private function unreached(HitAndRun $hitAndRun): bool { do_log(__METHOD__); $comment = nexus_trans('hr.unreached_comment', [ 'now' => Carbon::now()->toDateTimeString(), 'seed_time' => bcdiv($hitAndRun->snatch->seedtime, 3600, 1), 'seed_time_minimum' => Setting::get('hr.seed_time_minimum'), 'share_ratio' => get_hr_ratio($hitAndRun->snatch->uploaded, $hitAndRun->snatch->downloaded), 'torrent_size' => mksize($hitAndRun->torrent->size), 'ignore_when_ratio_reach' => Setting::get('hr.ignore_when_ratio_reach') ], $hitAndRun->user->locale); $update = [ 'status' => HitAndRun::STATUS_UNREACHED, 'comment' => $comment ]; $affectedRows = DB::table($hitAndRun->getTable()) ->where('id', $hitAndRun->id) ->where('status', HitAndRun::STATUS_INSPECTING) ->update($update); do_log("[H&R_UNREACHED], " . last_query() . ", affectedRows: $affectedRows"); if ($affectedRows != 1) { do_log($hitAndRun->toJson() . ", [H&R_UNREACHED], affectedRows != 1, skip!", 'notice'); return false; } $message = [ 'receiver' => $hitAndRun->uid, 'added' => Carbon::now()->toDateTimeString(), 'subject' => nexus_trans('hr.unreached_message_subject', ['hit_and_run_id' => $hitAndRun->id], $hitAndRun->user->locale), 'msg' => nexus_trans('hr.unreached_message_content', [ 'completed_at' => $hitAndRun->snatch->completedat->toDateTimeString(), 'torrent_id' => $hitAndRun->torrent_id, 'torrent_name' => $hitAndRun->torrent->name, ], $hitAndRun->user->locale), ]; Message::query()->insert($message); //disable user /** @var User $user */ $user = $hitAndRun->user; $counts = $user->hitAndRuns()->where('status', HitAndRun::STATUS_UNREACHED)->count(); $disableCounts = Setting::get('hr.ban_user_when_counts_reach'); do_log("user: {$user->id}, H&R counts: $counts, disableCounts: $disableCounts", 'notice'); if ($counts >= $disableCounts) { do_log("[DISABLE_USER_DUE_TO_H&R_UNREACHED]", 'notice'); $comment = nexus_trans('hr.unreached_disable_comment', [], $user->locale); $user->updateWithModComment(['enabled' => User::ENABLED_NO], $comment); $message = [ 'receiver' => $hitAndRun->uid, 'added' => Carbon::now()->toDateTimeString(), 'subject' => $comment, 'msg' => nexus_trans('hr.unreached_disable_message_content', [ 'ban_user_when_counts_reach' => Setting::get('hr.ban_user_when_counts_reach'), ], $hitAndRun->user->locale), ]; Message::query()->insert($message); $userBanLog = [ 'uid' => $user->id, 'username' => $user->username, 'reason' => $comment ]; UserBanLog::query()->insert($userBanLog); } return true; } public function getStatusStats($uid, $formatted = true) { $results = HitAndRun::query()->where('uid', $uid) ->selectRaw('status, count(*) as counts') ->groupBy('status') ->get() ->pluck('counts', 'status'); if ($formatted) { return sprintf( '%s/%s/%s', $results->get(HitAndRun::STATUS_INSPECTING, 0), $results->get(HitAndRun::STATUS_UNREACHED, 0), Setting::get('hr.ban_user_when_counts_reach') ); } return $results; } }