diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ab6ec6..f0cc541 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@
- **Email:** Fix Email Can't Send
- **Error:** Fix Error Handler
- **Invite:** Add Fine-grained control of recycle pending
+- **Links:** Remove extra meta section
- **Register:** Add captcha checker
- **TorrentUpload:** Fix length 0 file cause ParseErrorException
- **Tracker:** Add miss port check for field ipv6_port
@@ -59,6 +60,7 @@
- **Redis:** Add more Redis arguments in debug output
- **Session:** Add Session Format Docs
- **SiteConfig:** change namespace `authority.route_` to `route.`
+- **Tracker:** Separate announce data update function
- **Validator:** Add function buildDefaultValue()
- **ext2Icon:** Add more File format
diff --git a/README.md b/README.md
index cbc6ca7..62aa8c3 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,9 @@ So that tracker can record the peer's ip address.
7. Use the default `php bin/rid-httpd service start -d` to let *RidPT* RUN in the background. Or you can use other daemon work like:
- Systemctl: [ridpt.service](migration/ridpt.service)
-## Basie Environment in `.env`
+## Basie Environment Setting in `.env`
+
+> Notice: Any change in file `.env` require the restart of Application to Make it effective
### Section `APP`
diff --git a/apps/config/http_base.php b/apps/config/http_base.php
index 7212859..fa4bbed 100644
--- a/apps/config/http_base.php
+++ b/apps/config/http_base.php
@@ -215,6 +215,12 @@
'type' => \Rid\Base\Timer::TICK,
'msec' => 5 * 60 * 1000, // TODO 单位为毫秒,应该为所有contab worker的最小公倍数(应该在面板有所提醒)
'callback' => 'init'
+ ],
+ 'tracker' => [
+ 'class' => \apps\task\TrackerAnnounceTimer::class,
+ 'type' => \Rid\Base\Timer::AFTER,
+ 'msec' => 10 * 1000,
+ 'callback' => 'init'
]
],
diff --git a/apps/config/httpd.php b/apps/config/httpd.php
index b003406..17cc6df 100644
--- a/apps/config/httpd.php
+++ b/apps/config/httpd.php
@@ -63,7 +63,6 @@
'enable_coroutine' => false, // 开启协程
'reactor_num' => 1, // 连接处理线程数
'worker_num' => 5, // 工作进程数
- 'task_worker_num' => 10, // Task进程数
'pid_file' => '/var/run/rid-httpd.pid', // PID 文件
'log_file' => '/tmp/rid-httpd.log', // 日志文件路径
'max_request' => 3000, // 进程的最大任务数
diff --git a/apps/controllers/TrackerController.php b/apps/controllers/TrackerController.php
index 71ecb77..2668012 100644
--- a/apps/controllers/TrackerController.php
+++ b/apps/controllers/TrackerController.php
@@ -775,9 +775,13 @@ private function checkSession($queries, $seeder, $userInfo, $torrentInfo)
private function sendToTaskWorker($queries, $role, $userInfo, $torrentInfo)
{
- // Push to Redis Queue and quick response
- app()->redis->lPush('Tracker:to_deal_queue', json_encode([
- 'worker' => \apps\task\TrackerAnnounceTask::class,
+ /**
+ * Push to Redis Queue and quick response
+ *
+ * Don't use json_{encode,decode} for the value of info_hash and peer_id will make
+ * those function return FALSE
+ */
+ return app()->redis->lPush('Tracker:to_deal_queue', serialize([
'timestamp' => time(),
'queries' => $queries,
'role' => $role,
diff --git a/apps/public/static/css/main.css b/apps/public/static/css/main.css
index 84f7729..d5adbde 100644
--- a/apps/public/static/css/main.css
+++ b/apps/public/static/css/main.css
@@ -61,7 +61,7 @@ body{background-color:#f6f6f6}
.color-rss{color:#5c7cfa}
/* Main Container */
-.main-container{background-color:#eaeaea;padding:10px}
+.main-container{background-color:#eaeaea;padding:20px 10px}
/* Footer Menu */
#footer_menu{background-color:#383838;color:#C3C0B9;font-size:12px;margin-top:30px;padding-bottom:10px;padding-top:15px}
diff --git a/apps/task/CronTabTimer.php b/apps/task/CronTabTimer.php
index 309b081..8c2a5d4 100644
--- a/apps/task/CronTabTimer.php
+++ b/apps/task/CronTabTimer.php
@@ -12,9 +12,9 @@
class CronTabTimer extends Timer
{
-
+
private $_print_flag = 1; // FIXME debug model on
-
+
private function print_log($log)
{
$this->_print_flag = $this->_print_flag ?? config('debug.print_crontab_log');
@@ -41,7 +41,7 @@ public function init()
$job_start_time = time();
$this->{$job['job']}($job);
$job_end_time = time();
- $hit ++;
+ $hit++;
// Update the run information
app()->pdo->createCommand('UPDATE `site_crontab` set last_run_at= NOW() , next_run_at= DATE_ADD(NOW(), interval job_interval second) WHERE id=:id')->bindParams([
@@ -66,7 +66,7 @@ public function init()
}
}
$end_time = time();
- $this->print_log('This Cron Work period Start At ' . $start_time.', Cost Time: ' . number_format($start_time - $end_time, 10) . 's, With ' . $hit . 'Jobs hits.');
+ $this->print_log('This Cron Work period Start At ' . $start_time . ', Cost Time: ' . number_format($start_time - $end_time, 10) . 's, With ' . $hit . ' Jobs hits.');
}
protected function clean_dead_peer()
@@ -79,7 +79,8 @@ protected function clean_dead_peer()
$this->print_log('Success clean ' . $affect_peer_count . ' peers from our peer list');
}
- protected function clean_expired_session() {
+ protected function clean_expired_session()
+ {
$timenow = time();
$expired_sessions = app()->redis->zRangeByScore('Site:Sessions:to_expire', 0, $timenow);
@@ -90,16 +91,14 @@ protected function clean_expired_session() {
}
$clean_record_count = app()->redis->zRemRangeByScore('Site:Sessions:to_expire', 0, $timenow);
- $this->print_log('Success clean expired Sessions: Database(' . count($expired_sessions) .'), Redis(' . $clean_record_count .').');
+ $this->print_log('Success clean expired Sessions: Database(' . count($expired_sessions) . '), Redis(' . $clean_record_count . ').');
}
// TODO sync sessions from database to redis to avoid lost (Maybe)...
-
- protected function expired_invitee () {
+ protected function expired_invitee()
+ {
app()->pdo->createCommand('UPDATE `invite` SET `used` = -1 WHERE `expire_at` < NOW() AND `used` = 0')->execute();
-
-
$count = app()->pdo->getRowCount();
$this->print_log('Success Expired ' . $count . ' invites');
}
diff --git a/apps/task/TrackerAnnounceTask.php b/apps/task/TrackerAnnounceTimer.php
similarity index 92%
rename from apps/task/TrackerAnnounceTask.php
rename to apps/task/TrackerAnnounceTimer.php
index aff48e6..2318c0a 100644
--- a/apps/task/TrackerAnnounceTask.php
+++ b/apps/task/TrackerAnnounceTimer.php
@@ -2,40 +2,44 @@
/**
* Created by PhpStorm.
* User: Rhilip
- * Date: 2019/3/17
- * Time: 13:52
+ * Date: 2019/6/28
+ * Time: 9:46
*/
namespace apps\task;
-use Rid\Base\TaskInterface;
-use apps\exceptions\TrackerException;
+use Rid\Base\Timer;
-
-class TrackerAnnounceTask implements TaskInterface
+class TrackerAnnounceTimer extends Timer
{
-
- public function run($data)
+ public function init()
{
- app()->pdo->beginTransaction();
- try {
- $this->processAnnounceRequest($data['queries'], $data['role'], $data['userInfo'], $data['torrentInfo']);
- app()->pdo->commit();
- } catch (TrackerException $e) {
- app()->pdo->rollback();
- // TODO throw $e;
- } catch (\Exception $e) {
- app()->pdo->rollback();
- // TODO throw new TrackerException(998, [":msg" => $e->getMessage()]);
+ while (true) {
+ $data_raw = app()->redis->rpoplpush('Tracker:to_deal_queue', 'Tracker:backup_queue');
+ if ($data_raw !== false) {
+ $data = unserialize($data_raw);
+ app()->pdo->beginTransaction();
+ try {
+ $this->processAnnounceRequest($data['queries'], $data['role'], $data['userInfo'], $data['torrentInfo']);
+ app()->pdo->commit();
+ app()->redis->lRem('Tracker:backup_queue', $data_raw, 0);
+ } catch (\Exception $e) {
+ println($e->getMessage());
+ app()->pdo->rollback();
+ // TODO deal with the items in backup_queue
+ }
+ } else {
+ sleep(1);
+ }
}
}
+
/** TODO 2018.12.12 Check Muti-Tracker behaviour when a Transaction begin
* @param $queries
* @param $seeder
* @param $userInfo
* @param $torrentInfo
- * @throws TrackerException
*/
private function processAnnounceRequest($queries, $seeder, $userInfo, $torrentInfo)
{
@@ -64,8 +68,8 @@ private function processAnnounceRequest($queries, $seeder, $userInfo, $torrentIn
$trueUploaded = max(0, $queries['uploaded']);
$trueDownloaded = max(0, $queries['downloaded']);
- app()->pdo->createCommand("INSERT INTO `peers` SET `user_id` =:uid, `torrent_id`= :tid, `peer_id`= :pid, `started_at`= CURRENT_TIMESTAMP
- `agent`=:agent, `seeder` = :seeder, {$ipField} ,
+ app()->pdo->createCommand("INSERT INTO `peers` SET `user_id` =:uid, `torrent_id`= :tid, `peer_id`= :pid, `started_at`= CURRENT_TIMESTAMP , `last_action_at` = CURRENT_TIMESTAMP ,
+ `agent`= :agent, `seeder` = :seeder, {$ipField} ,
`uploaded` = :upload , `downloaded` = :download, `to_go` = :to_go,
`corrupt` = :corrupt , `key` = :key ;
")->bindParams([
@@ -122,7 +126,7 @@ private function processAnnounceRequest($queries, $seeder, $userInfo, $torrentIn
} else {
// if session is exist but event!=stopped , we should continue the old session
app()->pdo->createCommand("UPDATE `peers` SET `agent`=:agent, {$ipField}," .
- "`seeder`=:seeder,
+ "`seeder`=:seeder,
`uploaded`=`uploaded` + :uploaded, `downloaded`= `downloaded` + :download, `to_go` = :left,
`last_action_at`=NOW(), `corrupt`=:corrupt, `key`=:key
WHERE `user_id` = :uid AND `torrent_id` = :tid AND `peer_id`=:pid")->bindParams([
@@ -173,7 +177,6 @@ private function processAnnounceRequest($queries, $seeder, $userInfo, $torrentIn
* @param $trueUploaded
* @param $trueDownloaded
* @param $duration
- * @throws TrackerException
*/
private function checkUpspeed($userInfo, $torrentInfo, $trueUploaded, $trueDownloaded, $duration)
{
@@ -200,7 +203,6 @@ private function checkUpspeed($userInfo, $torrentInfo, $trueUploaded, $trueDownl
])->execute();
app()->redis->del("TRACKER:user_passkey_" . $userInfo["passkey"] . "_content");
- throw new TrackerException(170);
}
// Uploaded more than 1 GB with uploading rate higher than 25 MByte/S (For Consertive level). This is likely cheating.
diff --git a/apps/views/admin/redis_key.php b/apps/views/admin/redis_key.php
index 3995bd2..1d8dd67 100644
--- a/apps/views/admin/redis_key.php
+++ b/apps/views/admin/redis_key.php
@@ -50,7 +50,7 @@
= json_encode($value, JSON_PRETTY_PRINT) ?>
- Values
+ List Values
= $item ?>
diff --git a/bin/rid-httpd b/bin/rid-httpd
index 5d7cb29..c95aef2 100644
--- a/bin/rid-httpd
+++ b/bin/rid-httpd
@@ -1,11 +1,13 @@
#!/usr/bin/env php
run();
diff --git a/framework/Base/TaskInterface.php b/framework/Base/TaskInterface.php
deleted file mode 100644
index 0eb6451..0000000
--- a/framework/Base/TaskInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-clear();
// 设置定时器
- $timerId = swoole_timer_after($msec, function () use ($callback) {
+ $timerId = \Swoole\Timer::after($msec, function () use ($callback) {
// 执行闭包
try {
call_user_func($callback);
@@ -74,7 +74,7 @@ public function tick(int $msec, callable $callback)
// 清除旧定时器
$this->clear();
// 设置定时器
- $timerId = swoole_timer_tick($msec, function () use ($callback) {
+ $timerId = \Swoole\Timer::tick($msec, function () use ($callback) {
// 执行闭包
try {
call_user_func($callback);
@@ -95,7 +95,8 @@ public function tick(int $msec, callable $callback)
public function clear()
{
if (isset($this->_timerId)) {
- return swoole_timer_clear($this->_timerId);
+ \Swoole\Timer::clear($this->_timerId);
+ return true;
}
return false;
}
diff --git a/framework/Component/Config.php b/framework/Component/Config.php
index 9fb0fbb..40b43ae 100644
--- a/framework/Component/Config.php
+++ b/framework/Component/Config.php
@@ -13,8 +13,9 @@
class Config extends Component
{
- /** @var \swoole_table */
+ /** @var \Swoole\Table */
private $cacheTable;
+
private $valueField = 'data';
public function onInitialize(array $config = [])
diff --git a/framework/Exceptions/TaskException.php b/framework/Exceptions/TaskException.php
deleted file mode 100644
index fe45169..0000000
--- a/framework/Exceptions/TaskException.php
+++ /dev/null
@@ -1,10 +0,0 @@
- false, // 开启协程
'reactor_num' => 8, // 主进程事件处理线程数
'worker_num' => 8, // 工作进程数
- 'task_worker_num' => 8, // 任务进程数
'max_request' => 10000, // 进程的最大任务数
'reload_async' => true, // 异步安全重启
'max_wait_time' => 60, // 退出等待时间
@@ -45,132 +44,170 @@ class HttpServer extends BaseObject
// 端口
protected $_port;
- // 初始化
- protected function initialize()
+ // 启动服务
+ public function start()
{
// 初始化参数
$this->_host = $this->virtualHost['host'];
$this->_port = $this->virtualHost['port'];
+
+ // 实例化服务器
+ $this->_server = new \Swoole\Http\Server($this->_host, $this->_port);
$this->settings += $this->_settings;
- $this->createSever();
+ $this->_server->set($this->settings);
+ // 覆盖参数
+ $this->_server->set([
+ 'enable_coroutine' => false, // 关闭默认协程,回调中有手动开启支持上下文的协程
+ ]);
+
+ // 绑定事件
+ $this->_server->on('start', [$this, 'onStart']);
+ $this->_server->on('shutdown', [$this, 'onShutdown']);
+ $this->_server->on('managerStart', [$this, 'onManagerStart']);
+ $this->_server->on('managerStop', [$this, 'onManagerStop']);
+ $this->_server->on('workerStart', [$this, 'onWorkerStart']);
+ $this->_server->on('workerStop', [$this, 'onWorkerStop']);
+ $this->_server->on('workerError', [$this, 'onWorkerError']);
+ $this->_server->on('workerExit', [$this, 'onWorkerExit']);
+ $this->_server->on('request', [$this, 'onRequest']);
+
+ // 欢迎信息
+ $this->welcome();
+
+ // rid-httpd 模式下,在此处创建全局的 \Swoole\Table
+ $configTable = new \Swoole\Table(2048);
+ $configTable->column('data', \Swoole\Table::TYPE_STRING, 256);
+ $configTable->create();
+ $this->_server->configTable = $configTable;
+
+ return $this->_server->start();
}
- // 启动服务
- public function start()
+ /**
+ * 主进程启动事件
+ * 仅允许echo、打印Log、修改进程名称,不得执行其他操作
+ * @param \Swoole\Server $server
+ */
+ public function onStart(\Swoole\Server $server)
{
- $this->initialize();
- $this->welcome();
- $this->onStart();
- $this->onManagerStart();
- $this->onWorkerStart();
- $this->onTask();
- $this->onFinish();
- $this->onRequest();
- $this->_server->set($this->settings);
- $this->_server->start();
+ ProcessHelper::setTitle("{$this->name}: master {$this->_host}:{$this->_port}");
}
- // 主进程启动事件
- protected function onStart()
+ /**
+ * 主进程停止事件
+ * 请勿在onShutdown中调用任何异步或协程相关API,触发onShutdown时底层已销毁了所有事件循环设施
+ * @param \Swoole\Server $server
+ */
+ public function onShutdown(\Swoole\Server $server)
{
- $this->_server->on('Start', function (\swoole_server $server) {
- ProcessHelper::setTitle("rid-httpd: master {$this->_host}:{$this->_port}");
- });
+
}
- // 管理进程启动事件
- protected function onManagerStart()
+ /**
+ * 管理进程启动事件
+ * 可以使用基于信号实现的同步模式定时器swoole_timer_tick,不能使用task、async、coroutine等功能
+ * @param \Swoole\Server $server
+ */
+ public function onManagerStart(\Swoole\Server $server)
{
- $this->_server->on('ManagerStart', function (\swoole_server $server) {
- // 进程命名
- ProcessHelper::setTitle("rid-httpd: manager");
- });
+ ProcessHelper::setTitle("{$this->name}: manager"); // 进程命名
}
- // 工作进程启动事件
- protected function onWorkerStart()
+ /**
+ * 管理进程停止事件
+ * @param \Swoole\Server $server
+ */
+ public function onManagerStop(\Swoole\Server $server)
{
- $this->_server->on('WorkerStart', function (\swoole_server $server,int $workerId) {
- // 刷新OpCode缓存,防止reload重载入时受到影响
- foreach (['apc_clear_cache', 'opcache_reset'] as $func) {
- if (function_exists($func)) $func();
- }
- // 进程命名
- if ($workerId < $server->setting['worker_num']) {
- ProcessHelper::setTitle("rid-httpd: worker #{$workerId}");
- } else {
- ProcessHelper::setTitle("rid-httpd: task #{$workerId}");
- }
-
- // 实例化App
- $config = require $this->virtualHost['configFile'];
- $app = new Application($config);
- $app->setServ($this->_server);
- $app->setWorker($workerId);
- $app->loadAllComponents();
-
- if ($workerId == 0) { // 将系统设置中的 Timer 添加到 worker #0 中
- foreach (app()->env('timer') as $timer_name => $timer_config) {
- $timer_class = $timer_config['class'];
- $timer = new $timer_class();
- if ($timer instanceof Timer) {
- $timer->run($timer_config);
- }
- }
- }
- });
}
- protected function onTask()
+ /**
+ * 工作进程启动事件
+ * @param \Swoole\Http\Server $server
+ * @param int $workerId
+ */
+ public function onWorkerStart(\Swoole\Http\Server $server, int $workerId)
{
- $this->_server->on('Task', function (\swoole_server $serv, int $task_id, int $src_worker_id, $data) {
- $error_msg = "This Task {$task_id} from Worker {$src_worker_id}.\n";
- $data = unserialize($data);
- $task_worker_name = $data['worker'];
- if (class_exists($task_worker_name)) {
- /** @var TaskInterface $task_worker */
- $task_worker = new $task_worker_name();
- if ($task_worker instanceof TaskInterface) {
- return $task_worker->run($data);
+ // 刷新OpCode缓存,防止reload重载入时受到影响
+ foreach (['apc_clear_cache', 'opcache_reset'] as $func) {
+ if (function_exists($func)) $func();
+ }
+
+ // 进程命名
+ if ($workerId < $server->setting['worker_num']) {
+ ProcessHelper::setTitle("rid-httpd: worker #{$workerId}");
+ } else {
+ ProcessHelper::setTitle("rid-httpd: task #{$workerId}");
+ }
+
+ // 实例化App
+ $config = require $this->virtualHost['configFile'];
+ $app = new Application($config);
+ $app->setServ($this->_server);
+ $app->setWorker($workerId);
+ $app->loadAllComponents();
+
+ if ($workerId == 0) { // 将系统设置中的 Timer 添加到 worker #0 中
+ foreach (app()->env('timer') as $timer_name => $timer_config) {
+ $timer_class = $timer_config['class'];
+ $timer = new $timer_class();
+ if ($timer instanceof Timer) {
+ $timer->run($timer_config);
}
- $error_msg .= "Error: The task worker is not instanceof TaskInterface,\nData: " . json_encode($data);
- throw new TaskException($error_msg);
}
- $error_msg .= "No Task Worker model found,\nData: " . json_encode($data);
- throw new TaskException($error_msg);
- });
+ }
}
- protected function onFinish() {
- $this->_server->on('Finish', function (\swoole_server $serv, $task_id, $data) {
- //echo "Task#$task_id finished, data_len=".strlen($data).PHP_EOL;
- });
+ /**
+ * 工作进程停止事件
+ * @param \Swoole\Server $server
+ * @param int $workerId
+ */
+ public function onWorkerStop(\Swoole\Server $server, int $workerId)
+ {
+
}
- // 请求事件
- protected function onRequest()
+ /**
+ * 工作进程错误事件
+ * 当Worker/Task进程发生异常后会在Manager进程内回调此函数。
+ * @param \Swoole\Server $server
+ * @param int $workerId
+ * @param int $workerPid
+ * @param int $exitCode
+ * @param int $signal
+ */
+ public function onWorkerError(\Swoole\Server $server, int $workerId, int $workerPid, int $exitCode, int $signal)
{
- $this->_server->on('request', function (\swoole_http_request $request,\swoole_http_response $response) {
- try {
- app()->request->setRequester($request);
- app()->response->setResponder($response);
- app()->run(); // 执行请求
- } catch (\Throwable $e) {
- app()->error->handleException($e);
- }
- });
+
}
- protected function createSever() {
- // 实例化服务器
- $this->_server = new \Swoole\Http\Server($this->_host, $this->_port);
+ /**
+ * 工作进程退出事件
+ * 仅在开启reload_async特性后有效。异步重启特性,会先创建新的Worker进程处理新请求,旧的Worker进程自行退出
+ * @param \Swoole\Server $server
+ * @param int $workerId
+ */
+ public function onWorkerExit(\Swoole\Server $server, int $workerId)
+ {
- // rid-httpd 模式下,在此处创建全局的 \Swoole\Table
- $configTable = new \Swoole\Table(2048);
- $configTable->column('data', \Swoole\Table::TYPE_STRING, 256);
- $configTable->create();
- $this->_server->configTable = $configTable;
+ }
+
+ /**
+ * 请求事件
+ * @param \Swoole\Http\Request $request
+ * @param \Swoole\Http\Response $response
+ */
+ public function onRequest(\Swoole\Http\Request $request, \Swoole\Http\Response $response)
+ {
+ try {
+ app()->request->setRequester($request);
+ app()->response->setResponder($response);
+ app()->run(); // 执行请求
+ } catch (\Throwable $e) {
+ app()->error->handleException($e);
+ }
}
// 欢迎信息
@@ -184,14 +221,15 @@ protected function welcome()
\ \ \\ \\ \ \/\ \L\ \ \ \/ \ \ \
\ \_\ \_\ \_\ \___,_\ \_\ \ \_\
\/_/\/ /\/_/\/__,_ /\/_/ \/_/
+
EOL
);
println('───────────────────────────────────────');
- println('Server Name: rid-httpd');
- println('System Name: ' . strtolower(PHP_OS));
+ println('Server Name: ' . $this->name);
+ println('System Name: ' . PHP_OS);
println('Framework Version: ' . \Rid::VERSION);
println('PHP Version: ' . PHP_VERSION);
- println('Swoole Version: ' . swoole_version());
+ println('Swoole Version: ' . SWOOLE_VERSION);
println('Listen Addr: ' . $this->_host);
println('Listen Port: ' . $this->_port);
println('Reactor Num: ' . $this->settings['reactor_num']);