2021-06-21 02:01:26 +08:00
|
|
|
<?php
|
|
|
|
|
namespace App\Repositories;
|
|
|
|
|
|
|
|
|
|
use App\Models\HitAndRun;
|
|
|
|
|
use App\Models\Message;
|
|
|
|
|
use App\Models\Setting;
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use App\Models\UserBanLog;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
|
|
|
class HitAndRunRepository extends BaseRepository
|
|
|
|
|
{
|
|
|
|
|
|
2022-03-28 19:52:10 +08:00
|
|
|
public function cronjobUpdateStatus($uid = null, $torrentId = null, $ignoreTime = false): bool|int
|
2021-06-21 02:01:26 +08:00
|
|
|
{
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("uid: $uid, torrentId: $torrentId, ignoreTime: " . var_export($ignoreTime, true));
|
2021-06-21 02:01:26 +08:00
|
|
|
$size = 1000;
|
|
|
|
|
$page = 1;
|
|
|
|
|
$setting = Setting::get('hr');
|
|
|
|
|
if (empty($setting['mode'])) {
|
|
|
|
|
do_log("H&R not set.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ($setting['mode'] == HitAndRun::MODE_DISABLED) {
|
|
|
|
|
do_log("H&R mode is disabled.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-06-22 12:56:03 +08:00
|
|
|
if (empty($setting['inspect_time'])) {
|
|
|
|
|
do_log("H&R inspect_time is not set.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-06-21 02:01:26 +08:00
|
|
|
$query = HitAndRun::query()
|
|
|
|
|
->where('status', HitAndRun::STATUS_INSPECTING)
|
|
|
|
|
->with([
|
|
|
|
|
'torrent' => function ($query) {$query->select(['id', 'size', 'name']);},
|
|
|
|
|
'snatch',
|
2022-03-28 19:52:10 +08:00
|
|
|
'user' => function ($query) {$query->select(['id', 'username', 'lang', 'class', 'donoruntil']);},
|
2021-06-21 02:01:26 +08:00
|
|
|
'user.language',
|
|
|
|
|
]);
|
|
|
|
|
if (!is_null($uid)) {
|
|
|
|
|
$query->where('uid', $uid);
|
|
|
|
|
}
|
|
|
|
|
if (!is_null($torrentId)) {
|
|
|
|
|
$query->where('torrent_id', $torrentId);
|
|
|
|
|
}
|
2022-03-28 19:52:10 +08:00
|
|
|
if (!$ignoreTime) {
|
|
|
|
|
$query->where('created_at', '<', Carbon::now()->subHours($setting['inspect_time']));
|
|
|
|
|
}
|
2021-06-21 02:01:26 +08:00
|
|
|
$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) {
|
2022-03-28 19:52:10 +08:00
|
|
|
$currentLog = "$logPrefix, [HANDLING] " . $row->toJson();
|
2021-06-21 02:01:26 +08:00
|
|
|
do_log($logPrefix);
|
|
|
|
|
if (!$row->user) {
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("$currentLog, user not exists, skip!", 'error');
|
2021-06-21 02:01:26 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!$row->snatch) {
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("$currentLog, snatch not exists, skip!", 'error');
|
2021-06-21 02:01:26 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!$row->torrent) {
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("$currentLog, torrent not exists, skip!", 'error');
|
2021-06-21 02:01:26 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 19:52:10 +08:00
|
|
|
//If is VIP or above OR donated, pass
|
|
|
|
|
if ($row->user->class >= HitAndRun::MINIMUM_IGNORE_USER_CLASS || $row->user->isDonating()) {
|
2022-02-23 21:17:25 +08:00
|
|
|
$result = $this->reachedBySpecialUserClass($row);
|
|
|
|
|
if ($result) {
|
|
|
|
|
$successCounts++;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 02:01:26 +08:00
|
|
|
//check seed time
|
|
|
|
|
$targetSeedTime = $row->snatch->seedtime;
|
|
|
|
|
$requireSeedTime = bcmul($setting['seed_time_minimum'], 3600);
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("$currentLog, targetSeedTime: $targetSeedTime, requireSeedTime: $requireSeedTime");
|
2021-06-21 02:01:26 +08:00
|
|
|
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'];
|
2022-03-28 19:52:10 +08:00
|
|
|
do_log("$currentLog, targetShareRatio: $targetShareRatio, requireShareRatio: $requireShareRatio");
|
2021-06-21 02:01:26 +08:00
|
|
|
if ($targetShareRatio >= $requireShareRatio) {
|
|
|
|
|
$result = $this->reachedByShareRatio($row);
|
|
|
|
|
if ($result) {
|
|
|
|
|
$successCounts++;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//unreached
|
2022-03-28 21:08:00 +08:00
|
|
|
if ($row->added->addHours($setting['inspect_time'])->lte(Carbon::now())) {
|
|
|
|
|
$result = $this->unreached($row);
|
|
|
|
|
if ($result) {
|
|
|
|
|
$successCounts++;
|
|
|
|
|
}
|
2021-06-21 02:01:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$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
|
|
|
|
|
];
|
2022-02-23 21:17:25 +08:00
|
|
|
return $this->inspectingToReached($hitAndRun, $update, __FUNCTION__);
|
2021-06-21 02:01:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
];
|
2022-02-23 21:17:25 +08:00
|
|
|
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;
|
2021-06-21 02:01:26 +08:00
|
|
|
$affectedRows = DB::table($hitAndRun->getTable())
|
|
|
|
|
->where('id', $hitAndRun->id)
|
|
|
|
|
->where('status', HitAndRun::STATUS_INSPECTING)
|
|
|
|
|
->update($update);
|
2022-02-23 21:17:25 +08:00
|
|
|
do_log("[$logPrefix], " . last_query() . ", affectedRows: $affectedRows");
|
2021-06-21 02:01:26 +08:00
|
|
|
if ($affectedRows != 1) {
|
2022-02-23 21:17:25 +08:00
|
|
|
do_log($hitAndRun->toJson() . ", [$logPrefix], affectedRows != 1, skip!", 'notice');
|
2021-06-21 02:01:26 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2022-02-23 15:19:09 +08:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
}
|
2021-06-21 02:01:26 +08:00
|
|
|
}
|