Skip to content

Commit

Permalink
improve announce for paid torrents and H&R
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaomlove committed Oct 30, 2024
1 parent 653a92a commit 42cda65
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 48 deletions.
102 changes: 98 additions & 4 deletions app/Repositories/TorrentRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,17 @@

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
*
Expand Down Expand Up @@ -764,15 +771,102 @@ public function loadBoughtUser($torrentId): int
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);
}

public function hasBuySuccessCache($uid, $torrentId): bool
{
return NexusDB::redis()->hGet($this->getBoughtUserCacheKey($torrentId), $uid) == 1;
}

private function getBoughtUserCacheKey($torrentId): string
/**
* 获取购买种子的缓存状态
*
* @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 self::BOUGHT_USER_CACHE_KEY_PREFIX . $torrentId;
return sprintf("%s:%s:%s", self::BUY_FAIL_CACHE_KEY_PREFIX, $userId, $torrentId);
}

public function addPiecesHashCache(int $torrentId, string $piecesHash): bool|int|\Redis
Expand Down
2 changes: 1 addition & 1 deletion include/constants.php
Original file line number Diff line number Diff line change
@@ -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");
Expand Down
8 changes: 7 additions & 1 deletion include/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2798,6 +2798,8 @@ function stdhead($title = "", $msgalert = true, $script = "", $place = "")
$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 == ""){
Expand Down Expand Up @@ -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 />");
}

Expand Down
75 changes: 34 additions & 41 deletions public/announce.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@
$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;
Expand Down Expand Up @@ -401,13 +408,6 @@
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);
Expand Down Expand Up @@ -451,43 +451,48 @@
&& $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"
);
}
if ($buyStatus > 10) {
//disable download
(new \App\Repositories\UserRepository())->updateDownloadPrivileges(null, $userid, 'no', 'announce_paid_torrent_too_many_times');
}
//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);
});
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
Expand Down Expand Up @@ -570,19 +575,7 @@
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");

Expand Down Expand Up @@ -617,7 +610,7 @@
$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";
Expand Down
2 changes: 1 addition & 1 deletion public/details.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
loggedinorreturn();
$id = intval($_GET["id"] ?? 0);
$customField = new \Nexus\Field\Field();
int_check($id);
int_check($id, true);
if (!isset($id) || !$id)
die();

Expand Down
4 changes: 4 additions & 0 deletions resources/lang/en/message.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
'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',
Expand Down
4 changes: 4 additions & 0 deletions resources/lang/zh_CN/message.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
'subject' => '下载权限取消',
'body' => '你因上传速度过快下载权限被取消,若是盒子用户请备案。',
],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付费种子汇报失败次数过多下载权限被取消,请确保你有足够的魔力。',
],
'download_enable' => [
'subject' => '下载权限恢复',
'body' => '你的下载权限恢复,你现在可以下载种子。By: :operator',
Expand Down
4 changes: 4 additions & 0 deletions resources/lang/zh_TW/message.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
'subject' => '下載權限取消',
'body' => '你因上傳速度過快下載權限被取消,若是盒子用戶請備案。',
],
'download_disable_announce_paid_torrent_too_many_times' => [
'subject' => '下载权限取消',
'body' => '你因向付費種子匯報失敗次數過多下載權限被取消,請確保你有足夠的魔力。',
],
'download_enable' => [
'subject' => '下載權限恢復',
'body' => '你的下載權限恢復,你現在可以下載種子。By: :operator',
Expand Down

0 comments on commit 42cda65

Please sign in to comment.