demo/app/Modules/Tracker/Announce.php
2023-03-23 18:50:47 +01:00

269 lines
7.0 KiB
PHP

<?php
namespace LaraBB\Tracker;
use LaraBB\Profile\Models\Profile;
use PerfectPurple\Models\TorrentPeer;
use PerfectPurple\Models\TorrentFile;
use stdClass;
//use PerfectPurple\Models\TorrentHistory;
class Announce {
/**
* @var
*/
public $config;
/**
* @var stdClass
*/
public $request;
private string $browsers = 'Mozilla|Chrome|Opera|Lynx|Trident|Edge';
/**
* @var
*/
private $currentPeer;
/**
* @var
*/
private $currentTorrent;
/**
* @var UserProfile
*/
private $userProfile;
/**
* @var TorrentPeer
*/
private $torrentPeer;
/**
* @var TorrentFile
*/
private $torrentFile;
//private $torrentHistory;
/**
* TorrentTracker constructor.
* @param UserProfile $userProfile
* @param TorrentPeer $torrentPeer
* @param TorrentFile $torrentFile
*/
public function __construct(
UserProfile $userProfile,
TorrentPeer $torrentPeer,
TorrentFile $torrentFile)
{
$this->config = config('perfectpurple.tracker');
$this->userProfile = $userProfile;
$this->torrentPeer = $torrentPeer;
$this->torrentFile = $torrentFile;
//$this->torrentHistory = $torrentHistory;
$this->request = new stdClass();
}
/**
* @return bool
*/
public function checkAccess(): bool
{
return !preg_match('/' . $this->browsers . '/', $this->request->agent);
}
/**
* @return bool
*/
public function checkClientValues(): bool
{
return !empty($this->request->port);
}
/**
* @return bool
*/
public function checkTorrent(): bool
{
if(empty($this->request->infoHash)) {
return false;
}
$this->currentTorrent = $this->torrentFile->readByInfoHash($this->request->infoHash);
return !is_null($this->currentTorrent);
}
/**
* @return bool
*/
public function checkPid(): bool
{
$userProfile = $this->userProfile->readByPid($this->request->pid);
return !is_null($userProfile);
}
/**
* @return bool
*/
public function checkSamePid(): bool
{
$data = $this->torrentPeer->status($this->request->pid, $this->currentTorrent->id);
if(!$data->isEmpty()) {
foreach($data as $set) {
if($set->status == 'seeder' && $set->status_cnt >= $this->config['max_pid_seed']) return false;
if($set->status == 'leecher' && $set->status_cnt >= $this->config['max_pid_leech']) return false;
}
return true;
}
return true;
}
/**
* @return $this
*/
public function checkFirewalled(): Announce
{
$theError = '';
$fd = fsockopen($this->request->ip, $this->request->port, $errno, $theError, 10);
$this->request->nat = !$fd;
fclose($fd);
return $this;
}
/**
* @return bool|string
*/
public function checkClientEvent(): bool|string
{
$this->currentPeer = $this->torrentPeer->read($this->request->pid, $this->currentTorrent->uuid, ['profile']);
return match ($this->request->event) {
'started' => $this->torrentStarted(),
'stopped' => $this->torrentStopped(),
'finished' => $this->torrentFinished(),
empty($this->currentRequest->event) => $this->torrentNoEvent(),
default => false,
};
}
/**
* @return string
*/
private function torrentStarted(): string
{
if(!is_null($this->currentPeer)) {
$this->torrentPeer->edit($this->currentPeer, $this->request);
} else {
$this->torrentPeer->add($this->request, $this->currentTorrent);
$this->currentPeer = $this->torrentPeer;
}
/*$history = $this->torrentHistory->read($this->currentPeer->user->uid, $this->currentTorrent->id);
if(!is_null($history)) {
$this->torrentHistory->edit($history, $this->currentRequest, true);
} elseif(is_null($history) && $this->currentRequest->left > 0) {
$this->torrentHistory->add($this->currentPeer, $this->currentTorrent, $this->currentRequest, true);
}*/
$this->torrentFile->setSeedersLeechers($this->currentTorrent, $this->request);
return $this->getRandomPeers();
}
/**
* @return string
*/
private function torrentStopped(): string
{
$this->torrentPeer->kill($this->currentPeer, $this->currentTorrent);
$this->userProfile->setTraffic($this->currentPeer->profile, $this->request);
/*$history = $this->torrentHistory->read($this->currentPeer->user->uid, $this->currentTorrent->id);
if(!is_null($history)) {
$this->torrentHistory->edit($history, $this->currentRequest, false);
}*/
return $this->getRandomPeers();
}
/**
* @return string
*/
private function torrentFinished(): string
{
if(is_null($this->currentPeer)) {
$this->torrentPeer->add($this->request, $this->currentTorrent);
$this->currentPeer = $this->torrentPeer;
}
$this->torrentPeer->complete($this->currentPeer, $this->request);
$this->torrentFile->complete($this->currentTorrent);
/*$history = $this->torrentHistory->read($this->currentPeer->user->uid, $this->currentTorrent->id);
if(!is_null($history)) {
$this->torrentHistory->edit($history, $this->currentRequest, true, true);
} else {
$this->torrentHistory->add($this->currentPeer, $this->currentTorrent, $this->currentRequest, true, true);
}*/
return $this->getRandomPeers();
}
/**
* @return string
*/
private function torrentNoEvent(): string
{
if(is_null($this->currentPeer)) {
$this->torrentPeer->add($this->request, $this->currentTorrent);
$this->currentPeer = $this->torrentPeer;
}
if($this->currentPeer->bytes != 0 && $this->request->left == 0) {
$this->torrentPeer->complete($this->currentPeer, $this->request);
$this->torrentFile->complete($this->currentTorrent);
}
$this->collectBytes();
return $this->getRandomPeers();
}
/**
* @return void
*/
private function collectBytes(): void
{
$diff = bcsub($this->currentPeer->bytes, $this->currentPeer->left);
$this->torrentPeer->setBytes($this->currentPeer, $this->request, $diff);
}
/**
* @return string
*/
private function getRandomPeers(): string
{
$data = $this->torrentPeer->random($this->currentTorrent->uuid, $this->request->numWant);
if(!is_null($data) && $this->request->compact) {
$compactStr = '';
$data->map(function($set) use(&$compactStr) {
$compactStr .= str_pad(pack('Nn', ip2long($set->ip), $set->port), 6);
});
return $compactStr;
}
return $data;
}
}