2022-03-15 18:05:33 +08:00
|
|
|
|
<?php
|
2020-08-31 10:11:06 +08:00
|
|
|
|
|
2022-03-15 18:05:33 +08:00
|
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2020-08-31 10:11:06 +08:00
|
|
|
|
|
|
|
|
|
|
namespace ZM\Utils;
|
|
|
|
|
|
|
2021-03-29 15:34:24 +08:00
|
|
|
|
use Doctrine\Common\Annotations\AnnotationReader;
|
2020-08-31 10:11:06 +08:00
|
|
|
|
use Exception;
|
2021-03-29 15:34:24 +08:00
|
|
|
|
use ReflectionClass;
|
|
|
|
|
|
use Swoole\Process;
|
2021-03-24 23:34:46 +08:00
|
|
|
|
use ZM\Annotation\Command\TerminalCommand;
|
|
|
|
|
|
use ZM\ConnectionManager\ManagerGM;
|
2020-08-31 10:11:06 +08:00
|
|
|
|
use ZM\Console\Console;
|
2021-03-24 23:34:46 +08:00
|
|
|
|
use ZM\Event\EventDispatcher;
|
|
|
|
|
|
use ZM\Event\EventManager;
|
2020-08-31 10:11:06 +08:00
|
|
|
|
|
|
|
|
|
|
class Terminal
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
public static $default_commands = false;
|
|
|
|
|
|
|
2020-08-31 10:11:06 +08:00
|
|
|
|
/**
|
2022-03-15 18:05:33 +08:00
|
|
|
|
* @throws Exception
|
2020-08-31 10:11:06 +08:00
|
|
|
|
* @return bool
|
2021-03-18 14:56:35 +08:00
|
|
|
|
* @noinspection PhpMissingReturnTypeInspection
|
|
|
|
|
|
* @noinspection PhpUnused
|
2020-08-31 10:11:06 +08:00
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public static function executeCommand(string $cmd)
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
if (self::$default_commands === false) {
|
|
|
|
|
|
self::init();
|
|
|
|
|
|
}
|
2020-08-31 10:11:06 +08:00
|
|
|
|
$it = explodeMsg($cmd);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(TerminalCommand::class);
|
|
|
|
|
|
$dispatcher->setRuleFunction(function ($v) use ($it) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
/* @var TerminalCommand $v */
|
2021-06-16 00:17:30 +08:00
|
|
|
|
return !empty($it) && ($v->command == $it[0] || $v->alias == $it[0]);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$dispatcher->setReturnFunction(function () {
|
|
|
|
|
|
EventDispatcher::interrupt('none');
|
|
|
|
|
|
});
|
|
|
|
|
|
$dispatcher->dispatchEvents($it);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($dispatcher->store !== 'none' && $cmd !== '') {
|
|
|
|
|
|
Console::info('Command not found: ' . $cmd);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
return true;
|
2021-03-24 23:34:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public static function log($type, $log_msg)
|
|
|
|
|
|
{
|
2021-03-24 23:34:46 +08:00
|
|
|
|
ob_start();
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (!in_array($type, ['log', 'info', 'debug', 'success', 'warning', 'error', 'verbose'])) {
|
2021-03-24 23:34:46 +08:00
|
|
|
|
ob_get_clean();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
Console::$type($log_msg);
|
|
|
|
|
|
$r = ob_get_clean();
|
2022-03-15 18:05:33 +08:00
|
|
|
|
$all = ManagerGM::getAllByName('terminal');
|
2021-06-16 00:17:30 +08:00
|
|
|
|
foreach ($all as $v) {
|
2021-03-24 23:34:46 +08:00
|
|
|
|
server()->send($v->getFd(), "\r" . $r);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
server()->send($v->getFd(), '>>> ');
|
2020-08-31 10:11:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-03-29 15:34:24 +08:00
|
|
|
|
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public static function init()
|
|
|
|
|
|
{
|
|
|
|
|
|
Console::debug('Initializing Terminal...');
|
2021-03-29 15:34:24 +08:00
|
|
|
|
foreach ((EventManager::$events[TerminalCommand::class] ?? []) as $v) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($v->command == 'help') {
|
2021-03-29 15:34:24 +08:00
|
|
|
|
self::$default_commands = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$class = new Terminal();
|
|
|
|
|
|
$reader = new AnnotationReader();
|
|
|
|
|
|
$reflection = new ReflectionClass($class);
|
2021-06-16 00:17:30 +08:00
|
|
|
|
foreach ($reflection->getMethods() as $v) {
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$r = $reader->getMethodAnnotation($v, TerminalCommand::class);
|
|
|
|
|
|
if ($r !== null) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
Console::debug('adding command ' . $r->command);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$r->class = Terminal::class;
|
|
|
|
|
|
$r->method = $v->getName();
|
|
|
|
|
|
EventManager::addEvent(TerminalCommand::class, $r);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
self::$default_commands = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="help",alias="h",description="显示帮助菜单")
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function help()
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$help = [];
|
|
|
|
|
|
foreach ((EventManager::$events[TerminalCommand::class] ?? []) as $v) {
|
|
|
|
|
|
/** @var TerminalCommand $v */
|
2022-03-15 18:05:33 +08:00
|
|
|
|
$cmd = $v->command . ($v->alias !== '' ? (' | ' . $v->alias) : '');
|
|
|
|
|
|
$painted = Console::setColor($v->command, 'green') . ($v->alias !== '' ? (' | ' . Console::setColor($v->alias, 'green')) : '');
|
|
|
|
|
|
$help[] = $painted . ':' . str_pad('', 16 - strlen($cmd) - 1) . ($v->description === '' ? '<无描述>' : $v->description);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
echo implode("\n", $help) . PHP_EOL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="status",description="显示Swoole Server运行状态(需要安装league/climate组件)")
|
|
|
|
|
|
* @noinspection PhpFullyQualifiedNameUsageInspection
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function status()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!class_exists('\\League\\CLImate\\CLImate')) {
|
|
|
|
|
|
Console::warning('你还没有安装 league/climate 组件,无法使用此功能!');
|
2021-03-29 15:34:24 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-03-15 18:05:33 +08:00
|
|
|
|
$climate = new \League\CLImate\CLImate();
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$climate->output->addDefault('buffer');
|
|
|
|
|
|
|
|
|
|
|
|
$objs = server()->stats();
|
|
|
|
|
|
$climate->columns($objs);
|
|
|
|
|
|
$obj = $climate->output->get('buffer')->get();
|
2022-03-15 18:05:33 +08:00
|
|
|
|
$climate->output->get('buffer')->clean();
|
2021-03-29 15:34:24 +08:00
|
|
|
|
echo $obj;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="logtest",description="测试log的显示等级")
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function testlog()
|
|
|
|
|
|
{
|
|
|
|
|
|
Console::log(date('[H:i:s]') . ' [L] This is normal msg. (0)');
|
|
|
|
|
|
Console::error('This is error msg. (0)');
|
|
|
|
|
|
Console::warning('This is warning msg. (1)');
|
|
|
|
|
|
Console::info('This is info msg. (2)');
|
|
|
|
|
|
Console::success('This is success msg. (2)');
|
|
|
|
|
|
Console::verbose('This is verbose msg. (3)');
|
|
|
|
|
|
Console::debug('This is debug msg. (4)');
|
2021-03-29 15:34:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="call",description="用于执行不需要参数的动态函数,比如 `call \Module\Example\Hello hitokoto`")
|
|
|
|
|
|
* @param $it
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function call($it)
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$class_name = $it[1];
|
|
|
|
|
|
$function_name = $it[2];
|
|
|
|
|
|
$class = new $class_name([]);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
$r = $class->{$function_name}();
|
|
|
|
|
|
if (is_string($r)) {
|
|
|
|
|
|
Console::success($r);
|
|
|
|
|
|
}
|
2021-03-29 15:34:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="level",description="设置log等级,例如 `level 0|1|2|3|4`")
|
|
|
|
|
|
* @param $it
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function level($it)
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$level = intval(is_numeric($it[1] ?? 99) ? ($it[1] ?? 99) : 99);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($level > 4 || $level < 0) {
|
|
|
|
|
|
Console::warning("Usage: 'level 0|1|2|3|4'");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Console::setLevel($level) || Console::success('Success!!');
|
|
|
|
|
|
}
|
2021-03-29 15:34:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="bc",description="eval执行代码,但输入必须是将代码base64之后的,如 `bc em1faW5mbygn5L2g5aW9Jyk7`")
|
|
|
|
|
|
* @param $it
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function bc($it)
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
$code = base64_decode($it[1] ?? '', true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
eval($code);
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="echo",description="输出内容,用法:`echo hello`")
|
|
|
|
|
|
* @param $it
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function echoI($it)
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
Console::info($it[1]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="stop",description="停止框架")
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function stop()
|
|
|
|
|
|
{
|
2021-06-16 00:17:30 +08:00
|
|
|
|
posix_kill(server()->master_pid, SIGTERM);
|
2021-03-29 15:34:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @TerminalCommand(command="reload",alias="r",description="重启框架(重载用户代码)")
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function reload()
|
|
|
|
|
|
{
|
2021-03-29 15:34:24 +08:00
|
|
|
|
Process::kill(server()->master_pid, SIGUSR1);
|
|
|
|
|
|
}
|
2020-08-31 10:11:06 +08:00
|
|
|
|
}
|