mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-03 14:10:57 +08:00
improve announce for paid torrents and H&R
This commit is contained in:
@@ -41,10 +41,17 @@ use Firebase\JWT\Key;
|
||||
|
||||
class TorrentRepository extends BaseRepository
|
||||
{
|
||||
const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers:";
|
||||
const BOUGHT_USER_CACHE_KEY_PREFIX = "torrent_purchasers";
|
||||
|
||||
const BUY_FAIL_CACHE_KEY_PREFIX = "torrent_purchase_fails";
|
||||
|
||||
const PIECES_HASH_CACHE_KEY = "torrent_pieces_hash";
|
||||
|
||||
const BUY_STATUS_SUCCESS = 0;
|
||||
const BUY_STATUS_NOT_YET = -1;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* fetch torrent list
|
||||
*
|
||||
@@ -764,15 +771,102 @@ HTML;
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function addBoughtUserToCache($torrentId, $uid)
|
||||
/**
|
||||
* 购买成功缓存,保存为 hash,一个种子一个 hash,永久有效
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return void
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function addBuySuccessCache($uid, $torrentId): void
|
||||
{
|
||||
NexusDB::redis()->hSet($this->getBoughtUserCacheKey($torrentId), $uid, 1);
|
||||
}
|
||||
|
||||
|
||||
private function getBoughtUserCacheKey($torrentId): string
|
||||
public function hasBuySuccessCache($uid, $torrentId): bool
|
||||
{
|
||||
return self::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentId;
|
||||
return NexusDB::redis()->hGet($this->getBoughtUserCacheKey($torrentId), $uid) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取购买种子的缓存状态
|
||||
*
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return int
|
||||
*/
|
||||
public function getBuyStatus($uid, $torrentId): int
|
||||
{
|
||||
//查询是否已经购买
|
||||
if ($this->hasBuySuccessCache($uid, $torrentId)) {
|
||||
return self::BUY_STATUS_SUCCESS;
|
||||
}
|
||||
//是否购买失败过
|
||||
$buyFailCount = $this->getBuyFailCache($uid, $torrentId);
|
||||
if ($buyFailCount > 0) {
|
||||
//根据失败次数,禁用下载权限并做提示等
|
||||
return $buyFailCount;
|
||||
}
|
||||
//购买失败缓存失效后,再重新查询数据库确定最终状态
|
||||
$hasBuyFromDB = TorrentBuyLog::query()->where("uid", $uid)->where("torrent_id", $torrentId)->exists();
|
||||
if ($hasBuyFromDB) {
|
||||
//标记购买成功, 返回已购买
|
||||
$this->addBuySuccessCache($uid, $torrentId);
|
||||
return self::BUY_STATUS_SUCCESS;
|
||||
} else {
|
||||
//返回未购买,前端可执行购买逻辑
|
||||
return self::BUY_STATUS_NOT_YET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加购买失败缓存, 结果累加
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return void
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function addBuyFailCache($uid, $torrentId): void
|
||||
{
|
||||
$key = $this->getBuyFailCacheKey($uid, $torrentId);
|
||||
$result = NexusDB::redis()->incr($key);
|
||||
if ($result == 1) {
|
||||
NexusDB::redis()->expire($key, 3600);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取失败缓存 ,结果是失败的次数
|
||||
*
|
||||
* @param $uid
|
||||
* @param $torrentId
|
||||
* @return int
|
||||
* @throws \RedisException
|
||||
*/
|
||||
public function getBuyFailCache($uid, $torrentId): int
|
||||
{
|
||||
return intval(NexusDB::redis()->get($this->getBuyFailCacheKey($uid, $torrentId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买成功缓存 key
|
||||
* @param $torrentId
|
||||
* @return string
|
||||
*/
|
||||
public function getBoughtUserCacheKey($torrentId): string
|
||||
{
|
||||
return sprintf("%s:%s", self::BOUGHT_USER_CACHE_KEY_PREFIX, $torrentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 购买失败缓存 key
|
||||
* @param int $userId
|
||||
* @param int $torrentId
|
||||
* @return string
|
||||
*/
|
||||
public function getBuyFailCacheKey(int $userId, int $torrentId): string
|
||||
{
|
||||
return sprintf("%s:%s:%s", self::BUY_FAIL_CACHE_KEY_PREFIX, $userId, $torrentId);
|
||||
}
|
||||
|
||||
public function addPiecesHashCache(int $torrentId, string $piecesHash): bool|int|\Redis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.8.14');
|
||||
defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-10-07');
|
||||
defined('RELEASE_DATE') || define('RELEASE_DATE', '2024-10-31');
|
||||
defined('IN_TRACKER') || define('IN_TRACKER', false);
|
||||
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
|
||||
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
|
||||
|
||||
@@ -2798,6 +2798,8 @@ if ($msgalert)
|
||||
$text = $lang_functions['text_you_have'].$unread.$lang_functions['text_new_message'] . add_s($unread) . $lang_functions['text_click_here_to_read'];
|
||||
msgalert("messages.php",$text, "red");
|
||||
}
|
||||
\App\Utils\MsgAlert::getInstance()->render();
|
||||
|
||||
/*
|
||||
$pending_invitee = $Cache->get_value('user_'.$CURUSER["id"].'_pending_invitee_count');
|
||||
if ($pending_invitee == ""){
|
||||
@@ -5907,7 +5909,11 @@ function get_ip_location_from_geoip($ip): bool|array
|
||||
function msgalert($url, $text, $bgcolor = "red")
|
||||
{
|
||||
print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"10\"><tr><td style='border: none; padding: 10px; background: ".$bgcolor."'>\n");
|
||||
print("<b><a href=\"".$url."\" target='_blank'><font color=\"white\">".$text."</font></a></b>");
|
||||
if (!empty($url)) {
|
||||
print("<b><a href=\"".$url."\" target='_blank'><font color=\"white\">".$text."</font></a></b>");
|
||||
} else {
|
||||
print("<b><font color=\"white\">".$text."</font></b>");
|
||||
}
|
||||
print("</td></tr></table><br />");
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,13 @@ if (!$az) {
|
||||
$redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]);
|
||||
warn("Invalid passkey! Re-download the .torrent from $BASEURL");
|
||||
}
|
||||
if ($az["enabled"] == "no")
|
||||
warn("Your account is disabled!", 300);
|
||||
elseif ($az["parked"] == "yes")
|
||||
warn("Your account is parked! (Read the FAQ)", 300);
|
||||
elseif ($az["downloadpos"] == "no")
|
||||
warn("Your downloading privileges have been disabled! (Read the rules)", 300);
|
||||
|
||||
$userid = intval($az['id'] ?? 0);
|
||||
unset($GLOBALS['CURUSER']);
|
||||
$CURUSER = $GLOBALS["CURUSER"] = $az;
|
||||
@@ -401,13 +408,6 @@ if (!isset($self))
|
||||
if ($valid[0] >= 1 && $seeder == 'no') err("You already are downloading the same torrent. You may only leech from one location at a time.", 300);
|
||||
if ($valid[0] >= 3 && $seeder == 'yes') err("You cannot seed the same torrent from more than 3 locations.", 300);
|
||||
|
||||
if ($az["enabled"] == "no")
|
||||
warn("Your account is disabled!", 300);
|
||||
elseif ($az["parked"] == "yes")
|
||||
warn("Your account is parked! (Read the FAQ)", 300);
|
||||
elseif ($az["downloadpos"] == "no")
|
||||
warn("Your downloading privileges have been disabled! (Read the rules)", 300);
|
||||
|
||||
if ($az["class"] < UC_VIP)
|
||||
{
|
||||
$ratio = (($az["downloaded"] > 0) ? ($az["uploaded"] / $az["downloaded"]) : 1);
|
||||
@@ -451,43 +451,48 @@ if (!isset($self))
|
||||
&& $torrent['owner'] != $userid
|
||||
&& get_setting("torrent.paid_torrent_enabled") == "yes"
|
||||
) {
|
||||
$hasBuyCacheKey = \App\Repositories\TorrentRepository::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentid;
|
||||
$hasBuy = $redis->hGet($hasBuyCacheKey, $userid);
|
||||
if ($hasBuy === false) {
|
||||
//no cache
|
||||
$lockName = "load_torrent_bought_user:$torrentid";
|
||||
$loadBoughtLock = new \Nexus\Database\NexusLock($lockName, 300);
|
||||
if ($loadBoughtLock->get()) {
|
||||
//get lock, do load
|
||||
executeCommand("torrent:load_bought_user $torrentid", "string", true, false);
|
||||
} else {
|
||||
do_log("can not get loadBoughtLock: $lockName", 'debug');
|
||||
$torrentRep = new \App\Repositories\TorrentRepository();
|
||||
$buyStatus = $torrentRep->getBuyStatus($userid, $torrentid);
|
||||
if ($buyStatus > 0) {
|
||||
do_log(sprintf("user: %v buy torrent: %v fail count: %v", $userid, $torrentid, $buyStatus), "error");
|
||||
if ($buyStatus > 3) {
|
||||
//warn
|
||||
\App\Utils\MsgAlert::getInstance()->add(
|
||||
"announce_paid_torrent_too_many_times",
|
||||
time() + 86400,
|
||||
"announce to paid torrent and fail too many times, please make sure you have enough bonus!",
|
||||
"",
|
||||
"black"
|
||||
);
|
||||
}
|
||||
//simple cache the hasBuy result
|
||||
$hasBuy = \Nexus\Database\NexusDB::remember(sprintf("user_has_buy_torrent:%s:%s", $userid, $torrentid), 86400*10, function () use($userid, $torrentid) {
|
||||
$exists = \App\Models\TorrentBuyLog::query()->where('uid', $userid)->where('torrent_id', $torrentid)->exists();
|
||||
return intval($exists);
|
||||
});
|
||||
if ($buyStatus > 10) {
|
||||
//disable download
|
||||
(new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $userid, 'no', 'announce_paid_torrent_too_many_times');
|
||||
}
|
||||
warn("purchase fail, please try again later, please make sure you have enough bonus", 300);
|
||||
}
|
||||
if (!$hasBuy) {
|
||||
$lock = new \Nexus\Database\NexusLock("buying_torrent:$userid", 5);
|
||||
if ($buyStatus == \App\Repositories\TorrentRepository::BUY_STATUS_NOT_YET) {
|
||||
//one by one
|
||||
$lock = new \Nexus\Database\NexusLock("buying_torrent", 5);
|
||||
if (!$lock->get()) {
|
||||
$msg = "buying torrent, wait!";
|
||||
do_log("[ANNOUNCE] user: $userid, torrent: $torrentid, $msg", 'error');
|
||||
err($msg);
|
||||
warn($msg, 300);
|
||||
}
|
||||
$bonusRep = new \App\Repositories\BonusRepository();
|
||||
try {
|
||||
$bonusRep->consumeToBuyTorrent($az['id'], $torrent['id'], 'Web');
|
||||
$redis->hSet($hasBuyCacheKey, $userid, 1);
|
||||
$torrentRep->addBuySuccessCache($userid, $torrentid);
|
||||
$lock->release();
|
||||
} catch (\Exception $exception) {
|
||||
$msg = $exception->getMessage();
|
||||
do_log("[ANNOUNCE] user: $userid, torrent: $torrentid, $msg " . $exception->getTraceAsString(), 'error');
|
||||
$torrentRep->addBuyFailCache($userid, $torrentid);
|
||||
$lock->release();
|
||||
err($msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else // continue an existing session
|
||||
@@ -570,19 +575,7 @@ else
|
||||
if ($event != 'stopped') {
|
||||
$isPeerExistResultSet = sql_query("select id from peers where $selfwhere limit 1");
|
||||
if (mysql_num_rows($isPeerExistResultSet) == 0) {
|
||||
$cacheKey = 'peers:connectable:'.$ip.'-'.$port.'-'.$agent;
|
||||
$connectable = \Nexus\Database\NexusDB::remember($cacheKey, 3600, function () use ($ip, $port) {
|
||||
if (isIPV6($ip)) {
|
||||
$sockres = @fsockopen("tcp://[".$ip."]",$port,$errno,$errstr,1);
|
||||
} else {
|
||||
$sockres = @fsockopen($ip, $port, $errno, $errstr, 1);
|
||||
}
|
||||
if (is_resource($sockres)) {
|
||||
fclose($sockres);
|
||||
return 'yes';
|
||||
}
|
||||
return 'no';
|
||||
});
|
||||
$connectable = "yes";
|
||||
$insertPeerSql = "INSERT INTO peers (torrent, userid, peer_id, ip, port, connectable, uploaded, downloaded, to_go, started, last_action, seeder, agent, downloadoffset, uploadoffset, passkey, ipv4, ipv6, is_seed_box) VALUES ($torrentid, $userid, ".sqlesc($peer_id).", ".sqlesc($ip).", $port, '$connectable', $uploaded, $downloaded, $left, $dt, $dt, '$seeder', ".sqlesc($agent).", $downloaded, $uploaded, ".sqlesc($passkey).", ".sqlesc($ipv4).", ".sqlesc($ipv6).", ".intval($isIPSeedBox).")";
|
||||
do_log("[INSERT PEER] peer not exists for $selfwhere, do insert with $insertPeerSql");
|
||||
|
||||
@@ -617,7 +610,7 @@ if (($left > 0 || $event == "completed") && $az['class'] < \App\Models\HitAndRun
|
||||
$hrLog = sprintf("[HR_LOG] user: %d, torrent: %d, hrMode: %s", $userid, $torrentid, $hrMode);
|
||||
if ($hrMode == \App\Models\HitAndRun::MODE_GLOBAL || ($hrMode == \App\Models\HitAndRun::MODE_MANUAL && $torrent['hr'] == \App\Models\Torrent::HR_YES)) {
|
||||
$hrCacheKey = sprintf("hit_and_run:%d:%d", $userid, $torrentid);
|
||||
$hrExists = \Nexus\Database\NexusDB::remember($hrCacheKey, 24*3600, function () use ($torrentid, $userid) {
|
||||
$hrExists = \Nexus\Database\NexusDB::remember($hrCacheKey, mt_rand(86400*365*5, 86400*365*10), function () use ($torrentid, $userid) {
|
||||
return \App\Models\HitAndRun::query()->where("uid", $userid)->where("torrent_id", $torrentid)->exists();
|
||||
});
|
||||
$hrLog .= ", hrExists: $hrExists";
|
||||
|
||||
@@ -6,7 +6,7 @@ require_once(get_langfile_path());
|
||||
loggedinorreturn();
|
||||
$id = intval($_GET["id"] ?? 0);
|
||||
$customField = new \Nexus\Field\Field();
|
||||
int_check($id);
|
||||
int_check($id, true);
|
||||
if (!isset($id) || !$id)
|
||||
die();
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ return [
|
||||
'subject' => 'Download permission canceled',
|
||||
'body' => 'Your download permission has been cancelled due to excessive upload speed, please file if you are a seed box user.' ,
|
||||
],
|
||||
'download_disable_announce_paid_torrent_too_many_times' => [
|
||||
'subject' => 'Download permission canceled',
|
||||
'body' => 'Your download permission has been cancelled due to announce to paid torrent too many times, please make sure you have enough bonus.' ,
|
||||
],
|
||||
'download_enable' => [
|
||||
'subject' => 'Download permission restored',
|
||||
'body' => 'Your download privileges restored, you can now download torrents. By: :operator',
|
||||
|
||||
@@ -19,6 +19,10 @@ return [
|
||||
'subject' => '下载权限取消',
|
||||
'body' => '你因上传速度过快下载权限被取消,若是盒子用户请备案。',
|
||||
],
|
||||
'download_disable_announce_paid_torrent_too_many_times' => [
|
||||
'subject' => '下载权限取消',
|
||||
'body' => '你因向付费种子汇报失败次数过多下载权限被取消,请确保你有足够的魔力。',
|
||||
],
|
||||
'download_enable' => [
|
||||
'subject' => '下载权限恢复',
|
||||
'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator',
|
||||
|
||||
@@ -18,6 +18,10 @@ return [
|
||||
'subject' => '下載權限取消',
|
||||
'body' => '你因上傳速度過快下載權限被取消,若是盒子用戶請備案。',
|
||||
],
|
||||
'download_disable_announce_paid_torrent_too_many_times' => [
|
||||
'subject' => '下载权限取消',
|
||||
'body' => '你因向付費種子匯報失敗次數過多下載權限被取消,請確保你有足夠的魔力。',
|
||||
],
|
||||
'download_enable' => [
|
||||
'subject' => '下載權限恢復',
|
||||
'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator',
|
||||
|
||||
Reference in New Issue
Block a user