diff --git a/.php_cs b/.php_cs index 9c552f9e4..32894c3a3 100644 --- a/.php_cs +++ b/.php_cs @@ -28,9 +28,7 @@ return PhpCsFixer\Config::create() ]) ->setFinder( PhpCsFixer\Finder::create() - ->exclude('public') - ->exclude('resource') - ->exclude('config') + ->exclude('test') ->exclude('runtime') ->exclude('vendor') ->in(__DIR__) diff --git a/script/Command/GenVersion.php b/script/Command/GenVersion.php index f19a4b800..914af934b 100644 --- a/script/Command/GenVersion.php +++ b/script/Command/GenVersion.php @@ -74,7 +74,7 @@ public function __invoke(App $app): void } if ($this->updated > 0 && $app->getBoolOpt('c')) { - self::gitCommit('update: update the version to composer.json'); + self::gitCommit("update: add {$this->version} for all component composer.json"); } echo Color::render("Complete\n", 'cyan'); diff --git a/src/bean/src/Container.php b/src/bean/src/Container.php index ccb67d63c..4464b3462 100644 --- a/src/bean/src/Container.php +++ b/src/bean/src/Container.php @@ -1048,13 +1048,14 @@ private function newProperty( $propertyValue = $this->newPropertyArray($propertyValue, $id); } + // Refer config or bean if ($propertyInject->isRef()) { $propertyValue = $this->getRefValue($propertyValue, $id); - } - // Optimize: Value not exists, skip call setter - if ($propertyValue === null) { - continue; + // Optimize: Value not exists, skip call setter + if ($propertyValue === null) { + continue; + } } // Parser property type diff --git a/src/console/src/Advanced/Formatter/Panel.php b/src/console/src/Advanced/Formatter/Panel.php index 2819a67e3..69fd50c62 100644 --- a/src/console/src/Advanced/Formatter/Panel.php +++ b/src/console/src/Advanced/Formatter/Panel.php @@ -159,7 +159,7 @@ public static function show($data, string $title = 'Information Panel', array $o // output panel top border if ($borderChar) { - $border = str_pad($borderChar, $panelWidth + (3 * 3), $borderChar); + $border = str_pad($borderChar, $panelWidth + (3 * 4), $borderChar); Console::write(' ' . $border); } diff --git a/src/console/src/Application.php b/src/console/src/Application.php index bad43417a..96a044d40 100644 --- a/src/console/src/Application.php +++ b/src/console/src/Application.php @@ -17,7 +17,9 @@ use Swoft\Stdlib\Helper\ObjectHelper; use Throwable; use function array_merge; +use function input; use function implode; +use function output; use function strpos; use function strtr; use function trim; @@ -59,7 +61,7 @@ class Application implements ConsoleInterface /** * @var string */ - private $name = 'My Application'; + private $name = 'Swoft Application'; /** * @var string @@ -69,7 +71,14 @@ class Application implements ConsoleInterface /** * @var string */ - private $description = 'Console application description'; + private $description = 'Swoft 2.0 console application'; + + /** + * Console font logo text + * + * @var string + */ + private $logoText = ''; /** * @var array @@ -94,25 +103,26 @@ public function __construct(array $options = []) */ public function commentsVars(): array { - $script = input()->getScript(); + $script = $this->input->getScriptFile(); + $fullCmd = $this->input->getFullCommand(); return [ 'name' => $this->getName(), 'description' => $this->getDescription(), // 'group' => self::getName(), - 'workDir' => \input()->getPwd(), + 'workDir' => $this->input->getPwd(), 'script' => $script, // bin/app 'binFile' => $script, - 'command' => \input()->getCommand(), // demo OR home:test - 'fullCmd' => \input()->getFullCommand(), - 'fullCommand' => \input()->getFullCommand(), + 'command' => $this->input->getCommand(), // demo OR home:test + 'fullCmd' => $fullCmd, + 'fullCommand' => $fullCmd, ]; } protected function prepare(): void { - $this->input = \input(); - $this->output = \output(); + $this->input = input(); + $this->output = output(); // load builtin comments vars $this->setCommentsVars($this->commentsVars()); @@ -124,15 +134,13 @@ protected function prepare(): void public function run(): void { try { - Swoft::trigger(ConsoleEvent::RUN_BEFORE, $this); - - // Prepare + // Prepare for run $this->prepare(); - // Get input command - $inputCommand = $this->input->getCommand(); + Swoft::trigger(ConsoleEvent::RUN_BEFORE, $this); - if (!$inputCommand) { + // Get input command + if (!$inputCommand = $this->input->getCommand()) { $this->filterSpecialOption(); } else { $this->doRun($inputCommand); @@ -383,4 +391,20 @@ public function setDescription(string $description): void { $this->description = trim($description); } + + /** + * @return string + */ + public function getLogoText(): string + { + return $this->logoText; + } + + /** + * @param string $logoText + */ + public function setLogoText(string $logoText): void + { + $this->logoText = $logoText; + } } diff --git a/src/console/src/AutoLoader.php b/src/console/src/AutoLoader.php index b86fcfb3e..164b09439 100644 --- a/src/console/src/AutoLoader.php +++ b/src/console/src/AutoLoader.php @@ -2,6 +2,7 @@ namespace Swoft\Console; +use Swoft; use Swoft\Console\Router\Router; use Swoft\Helper\ComposerJSON; use Swoft\SwoftComponent; @@ -13,13 +14,10 @@ */ final class AutoLoader extends SwoftComponent { - /** - * @return bool - */ - public function enable(): bool - { - return true; - } + // public function enable(): bool + // { + // return true; + // } /** * Get namespace and dirs @@ -53,7 +51,7 @@ public function beans(): array return [ 'cliApp' => [ 'class' => Application::class, - 'version' => '2.0.0' + 'version' => Swoft::VERSION, ], 'cliRouter' => [ 'class' => Router::class, diff --git a/src/console/src/Concern/RenderHelpInfoTrait.php b/src/console/src/Concern/RenderHelpInfoTrait.php index bd0aa3249..008bc9c89 100644 --- a/src/console/src/Concern/RenderHelpInfoTrait.php +++ b/src/console/src/Concern/RenderHelpInfoTrait.php @@ -4,6 +4,7 @@ use Swoft; use Swoft\Console\Console; +use Swoft\Console\ConsoleEvent; use Swoft\Console\Helper\FormatUtil; use Swoft\Console\Helper\Show; use Swoft\Console\Output\Output; @@ -13,7 +14,6 @@ use function array_shift; use function explode; use function implode; -use function input; use function is_array; use function is_bool; use function is_scalar; @@ -53,7 +53,8 @@ protected function showVersionInfo(): void $swooleVersion = SWOOLE_VERSION; // Display logo - $output->colored(' ' . ltrim(Swoft::FONT_LOGO)); + $logoText = $this->logoText ?: Swoft::FONT_LOGO; + $output->colored(ltrim($logoText, "\n")); // Display some information $output->writef( @@ -69,12 +70,17 @@ protected function showVersionInfo(): void */ protected function showApplicationHelp(bool $showLogo = true): void { + Swoft::trigger(ConsoleEvent::SHOW_HELP_BEFORE, 'app'); + // show logo if ($showLogo) { - Console::colored(Swoft::FONT_LOGO, 'cyan'); + $logoText = $this->logoText ?: Swoft::FONT_LOGO; + Console::colored(ltrim($logoText, "\n"), 'cyan'); } - $script = input()->getScriptName(); + /** @var Swoft\Console\Input\Input $input */ + $input = $this->input; + $script = $input->getScriptFile(); // Global options $globalOptions = self::$globalOptions; // Append expand option @@ -95,7 +101,7 @@ protected function showApplicationHelp(bool $showLogo = true): void /* @var Router $router */ $router = Swoft::getBean('cliRouter'); - $expand = input()->getBoolOpt('expand'); + $expand = $input->getBoolOpt('expand'); $keyWidth = $router->getKeyWidth($expand ? 2 : -4); Console::writeln('Available Commands:'); @@ -134,11 +140,9 @@ protected function showGroupHelp(string $group, array $info = []): void { /* @var Router $router */ $router = Swoft::getBean('cliRouter'); - $script = input()->getScriptName(); + $info = $info ?: $router->getGroupInfo($group); - if (!$info) { - $info = $router->getGroupInfo($group); - } + Swoft::trigger(ConsoleEvent::SHOW_HELP_BEFORE, 'group', $info); // $class = $groupInfo['class']; $names = $info['names']; @@ -146,6 +150,10 @@ protected function showGroupHelp(string $group, array $info = []): void $keyWidth = $router->getKeyWidth(-4); $groupName = sprintf('%s%s', $group, $info['alias'] ? " (alias: {$info['alias']})" : ''); + /** @var Swoft\Console\Input\Input $input */ + $input = $this->input; + $script = $input->getScriptFile(); + Console::startBuffer(); Console::writeln($info['desc'] . PHP_EOL); Console::writeln("Group: $groupName"); @@ -186,7 +194,11 @@ protected function showGroupHelp(string $group, array $info = []): void */ protected function showCommandHelp(array $info): void { - $script = input()->getScriptName(); + Swoft::trigger(ConsoleEvent::SHOW_HELP_BEFORE, 'command', $info); + + /** @var Swoft\Console\Input\Input $input */ + $input = $this->input; + $script = $input->getScriptFile(); $usage = sprintf('%s %s [arg ...] [--opt ...]', $script, $info['cmdId']); // If has been custom usage. diff --git a/src/console/src/ConsoleDispatcher.php b/src/console/src/ConsoleDispatcher.php index 6d758aceb..a669365a3 100644 --- a/src/console/src/ConsoleDispatcher.php +++ b/src/console/src/ConsoleDispatcher.php @@ -2,23 +2,21 @@ namespace Swoft\Console; -use function defined; use ReflectionException; use ReflectionType; -use function srun; use Swoft; use Swoft\Bean\Annotation\Mapping\Bean; -use Swoft\Bean\BeanFactory; use Swoft\Console\Input\Input; use Swoft\Console\Output\Output; use Swoft\Context\Context; -use Swoft\Contract\DispatcherInterface; use Swoft\Stdlib\Helper\PhpHelper; use Swoft\SwoftEvent; use Swoole\Runtime; use Throwable; +use function defined; use function get_class; use function get_parent_class; +use function srun; /** * Class ConsoleDispatcher @@ -26,18 +24,17 @@ * @since 2.0 * @Bean("cliDispatcher") */ -class ConsoleDispatcher implements DispatcherInterface +class ConsoleDispatcher // implements DispatcherInterface { /** - * @param array $params + * @param array $route * * @return void * @throws ReflectionException * @throws Throwable */ - public function dispatch(...$params): void + public function dispatch(array $route): void { - $route = $params[0]; // Handler info [$className, $method] = $route['handler']; @@ -87,7 +84,7 @@ public function executeByCo($beanObject, string $method, array $bindParams): voi $this->after($method); } catch (Throwable $e) { /** @var ConsoleErrorDispatcher $errDispatcher */ - $errDispatcher = BeanFactory::getSingleton(ConsoleErrorDispatcher::class); + $errDispatcher = Swoft::getSingleton(ConsoleErrorDispatcher::class); // Handle request error $errDispatcher->run($e); @@ -130,9 +127,9 @@ private function getBindParams(string $class, string $method): array $type = $paramType->getName(); if ($type === Output::class) { - $bindParams[] = \output(); + $bindParams[] = Swoft::getBean('input'); } elseif ($type === Input::class) { - $bindParams[] = \input(); + $bindParams[] = Swoft::getBean('output'); } else { $bindParams[] = null; } diff --git a/src/console/src/ConsoleEvent.php b/src/console/src/ConsoleEvent.php index 76dd3cec8..dee1311a1 100644 --- a/src/console/src/ConsoleEvent.php +++ b/src/console/src/ConsoleEvent.php @@ -7,11 +7,43 @@ */ final class ConsoleEvent { - public const RUN_BEFORE = 'console.run.before'; + /** + * On run before + */ + public const RUN_BEFORE = 'console.run.before'; + + /** + * On show help before + */ + public const SHOW_HELP_BEFORE = 'console.show.help.before'; + + /** + * On dispatch before + */ public const DISPATCH_BEFORE = 'console.dispatch.before'; - public const EXECUTE_BEFORE = 'console.execute.before'; - public const EXECUTE_AFTER = 'console.execute.after'; - public const DISPATCH_AFTER = 'console.dispatch.after'; - public const RUN_AFTER = 'console.run.after'; - public const RUN_ERROR = 'console.run.error'; + + /** + * On execute before + */ + public const EXECUTE_BEFORE = 'console.execute.before'; + + /** + * On execute after + */ + public const EXECUTE_AFTER = 'console.execute.after'; + + /** + * On dispatch after + */ + public const DISPATCH_AFTER = 'console.dispatch.after'; + + /** + * On run after + */ + public const RUN_AFTER = 'console.run.after'; + + /** + * On run error + */ + public const RUN_ERROR = 'console.run.error'; } diff --git a/src/console/src/Contract/InputInterface.php b/src/console/src/Contract/InputInterface.php index dbb2b1854..a07c3fcea 100644 --- a/src/console/src/Contract/InputInterface.php +++ b/src/console/src/Contract/InputInterface.php @@ -23,7 +23,7 @@ public function read(string $question = '', bool $nl = false): string; * * @return string */ - public function getScript(): string; + public function getScriptFile(): string; /** * 获取执行的命令 diff --git a/src/console/src/Input/AbstractInput.php b/src/console/src/Input/AbstractInput.php index 5a3cfff18..c248c7522 100644 --- a/src/console/src/Input/AbstractInput.php +++ b/src/console/src/Input/AbstractInput.php @@ -23,15 +23,15 @@ abstract class AbstractInput implements InputInterface protected $pwd; /** - * the script name + * The script file * e.g `./bin/app` OR `bin/cli.php` * * @var string */ - protected $script; + protected $scriptFile; /** - * the command name(Is first argument) + * The command name(Is first argument) * e.g `start` OR `start` * * @var string @@ -691,17 +691,17 @@ public function getWorkDir(): string /** * @return string */ - public function getScript(): string + public function getScriptFile(): string { - return $this->script; + return $this->scriptFile; } /** - * @param string $script + * @param string $scriptFile */ - public function setScript(string $script): void + public function setScriptFile(string $scriptFile): void { - $this->script = $script; + $this->scriptFile = $scriptFile; } /** diff --git a/src/console/src/Input/Input.php b/src/console/src/Input/Input.php index b4995a8d9..dc9db9158 100644 --- a/src/console/src/Input/Input.php +++ b/src/console/src/Input/Input.php @@ -6,6 +6,7 @@ use Toolkit\Cli\Flags; use function array_map; use function array_shift; +use function basename; use function fgets; use function fwrite; use function implode; @@ -24,7 +25,7 @@ class Input extends AbstractInput { /** - * the real command ID(group:command) + * The real command ID(group:command) * e.g `http:start` * * @var string @@ -50,7 +51,7 @@ public function __construct(array $args = null, bool $parsing = true) $this->pwd = $this->getPwd(); $this->tokens = $args; - $this->script = array_shift($args); + $this->scriptFile = array_shift($args); $this->fullScript = implode(' ', $args); if ($parsing) { @@ -108,15 +109,15 @@ public function read(string $question = '', bool $nl = false): string */ public function getFullCommand(): string { - return $this->script . ' ' . $this->command; + return $this->scriptFile . ' ' . $this->command; } /** * @return string */ - public function getScriptName(): string + public function getBinFile(): string { - return $this->script; + return $this->scriptFile; } /** @@ -124,7 +125,15 @@ public function getScriptName(): string */ public function getBinName(): string { - return $this->script; + return $this->getScriptName(); + } + + /** + * @return string + */ + public function getScriptName(): string + { + return basename($this->scriptFile); } /** diff --git a/src/framework/src/SwoftApplication.php b/src/framework/src/SwoftApplication.php index 9c93a39c8..42a430794 100644 --- a/src/framework/src/SwoftApplication.php +++ b/src/framework/src/SwoftApplication.php @@ -220,7 +220,7 @@ public function run(): void } /** - * @param string[] $classes + * @param string[] ...$classes */ public function disableAutoLoader(string ...$classes) { diff --git a/src/http-server/src/Command/HttpServerCommand.php b/src/http-server/src/Command/HttpServerCommand.php index 92928a025..3954d31c1 100644 --- a/src/http-server/src/Command/HttpServerCommand.php +++ b/src/http-server/src/Command/HttpServerCommand.php @@ -6,7 +6,6 @@ use Swoft\Console\Annotation\Mapping\Command; use Swoft\Console\Annotation\Mapping\CommandMapping; use Swoft\Console\Annotation\Mapping\CommandOption; -use Swoft\Console\Helper\Show; use Swoft\Http\Server\HttpServer; use Swoft\Server\Command\BaseServerCommand; use Swoft\Server\Exception\ServerException; @@ -42,42 +41,7 @@ public function start(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $masterPid = $server->getPid(); - output()->writeln("The HTTP server have been running!(PID: {$masterPid})"); - return; - } - - // Startup settings - $this->configStartOption($server); - - $settings = $server->getSetting(); - // Setting - $workerNum = $settings['worker_num']; - - // Server startup parameters - $mainHost = $server->getHost(); - $mainPort = $server->getPort(); - $modeName = $server->getModeName(); - $typeName = $server->getTypeName(); - - // Http - $panel = [ - 'HTTP' => [ - 'listen' => $mainHost . ':' . $mainPort, - 'type' => $typeName, - 'mode' => $modeName, - 'worker' => $workerNum, - ], - ]; - - // Port Listeners - $panel = $this->appendPortsToPanel($server, $panel); - - Show::panel($panel); - - output()->writeln('HTTP server start success !'); + $this->showServerInfoPanel($server); // Start the server $server->start(); @@ -92,26 +56,9 @@ public function start(): void public function reload(): void { $server = $this->createServer(); - $script = input()->getScript(); - // Check if it has started - if (!$server->isRunning()) { - output()->writeln('The HTTP server is not running! cannot reload'); - return; - } - - output()->writef('Server %s is reloading', $script); - - if ($reloadTask = input()->hasOpt('t')) { - Show::notice('Will only reload task worker'); - } - - if (!$server->reload($reloadTask)) { - Show::error('The swoole server worker process reload fail!'); - return; - } - - output()->writef('HTTP server %s reload success', $script); + // Reload server + $this->reloadServer($server); } /** @@ -147,18 +94,8 @@ public function restart(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $success = $server->stop(); - - if (!$success) { - output()->error('Stop the old server failed!'); - return; - } - } - - output()->writef('Server HTTP restart success !'); - $server->startWithDaemonize(); + // Restart server + $this->restartServer($server); } /** @@ -166,7 +103,7 @@ public function restart(): void */ private function createServer(): HttpServer { - $script = input()->getScript(); + $script = input()->getScriptFile(); $command = $this->getFullCommand(); /** @var HttpServer $server */ diff --git a/src/http-server/test/testing/MockResponse.php b/src/http-server/test/testing/MockResponse.php index f7d34e002..b8226a6b2 100644 --- a/src/http-server/test/testing/MockResponse.php +++ b/src/http-server/test/testing/MockResponse.php @@ -72,16 +72,17 @@ public function header($key, $value, $ucwords = null) } /** - * @param string $name - * @param string $value - * @param int|string $expires + * @param string $name + * @param string $value + * @param int|string $expires * @param string|null $path - * @param string $domain - * @param bool $secure - * @param bool $httpOnly + * @param string $domain + * @param bool $secure + * @param bool $httpOnly + * @param null $samesite */ public function cookie( - $name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httpOnly = null + $name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httpOnly = null, $samesite = null ) { $result = \urlencode($name) . '=' . \urlencode($value); diff --git a/src/process/src/Command/ProcessCommand.php b/src/process/src/Command/ProcessCommand.php index 6a800df68..ebcab3217 100644 --- a/src/process/src/Command/ProcessCommand.php +++ b/src/process/src/Command/ProcessCommand.php @@ -82,7 +82,7 @@ public function restart(): void public function reload(): void { $server = $this->createServer(); - $script = input()->getScript(); + $script = input()->getScriptFile(); // Check if it has started if (!$server->isRunning()) { @@ -122,7 +122,7 @@ public function stop(): void */ private function createServer(): ProcessPool { - $script = input()->getScript(); + $script = input()->getScriptFile(); $command = $this->getFullCommand(); /** @var ProcessPool $processPool */ diff --git a/src/rpc-server/src/Command/ServiceServerCommand.php b/src/rpc-server/src/Command/ServiceServerCommand.php index 9100d16f0..723246030 100644 --- a/src/rpc-server/src/Command/ServiceServerCommand.php +++ b/src/rpc-server/src/Command/ServiceServerCommand.php @@ -1,23 +1,17 @@ createServer(); - // Check if it has started - if ($server->isRunning()) { - $masterPid = $server->getPid(); - output()->writeln("The RPC server have been running!(PID: {$masterPid})"); - return; - } - - // Startup settings - $this->configStartOption($server); - - $settings = $server->getSetting(); - - // Setting - $workerNum = $settings['worker_num']; - - // Server startup parameters - $mainHost = $server->getHost(); - $mainPort = $server->getPort(); - $modeName = $server->getModeName(); - $typeName = $server->getTypeName(); - - // RPC - $panel = [ - 'RPC' => [ - 'listen' => $mainHost . ':' . $mainPort, - 'type' => $typeName, - 'mode' => $modeName, - 'worker' => $workerNum, - ], - ]; - - // Listener - $listeners = $server->getListener(); - foreach ($listeners as $name => $listener) { - if (!$listener instanceof ServerInterface) { - continue; - } - $panel[$name] = [ - 'listen' => sprintf('%s:%s', $listener->getHost(), $listener->getPort()), - 'type' => $listener->getTypeName() - ]; - } - - Show::panel($panel); - - output()->writef('RPC server start success !'); + $this->showServerInfoPanel($server); // Start the server $server->start(); @@ -104,31 +53,13 @@ public function start(): void * * @CommandMapping(usage="{fullCommand} [-t]") * @CommandOption("t", desc="Only to reload task processes, default to reload worker and task") - * */ public function reload(): void { $server = $this->createServer(); - $script = input()->getScript(); - - // Check if it has started - if (!$server->isRunning()) { - output()->writeln('The RPC server is not running! cannot reload'); - return; - } - - output()->writef('RPC server %s is reloading', $script); - if ($reloadTask = input()->hasOpt('t')) { - Show::notice('Will only reload task worker'); - } - - if (!$server->reload($reloadTask)) { - Show::error('The swoole server worker process reload fail!'); - return; - } - - output()->writef('RPC server %s reload success', $script); + // Reload server + $this->reloadServer($server); } /** @@ -165,18 +96,8 @@ public function restart(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $success = $server->stop(); - - if (!$success) { - output()->error('Stop the old server failed!'); - return; - } - } - - output()->writef('RPC server reload success !'); - $server->startWithDaemonize(); + // Restart server + $this->restartServer($server); } /** @@ -184,7 +105,7 @@ public function restart(): void */ private function createServer(): ServiceServer { - $script = input()->getScript(); + $script = input()->getScriptFile(); $command = $this->getFullCommand(); /** @var ServiceServer $server */ diff --git a/src/rpc-server/src/Swoole/ConnectListener.php b/src/rpc-server/src/Swoole/ConnectListener.php index 52b202496..cb7fa23ad 100644 --- a/src/rpc-server/src/Swoole/ConnectListener.php +++ b/src/rpc-server/src/Swoole/ConnectListener.php @@ -1,12 +1,9 @@ isRunning()) { + $masterPid = $server->getPid(); + output()->writeln("The server have been running!(PID: {$masterPid})"); + return; + } + + // Startup config + $this->configStartOption($server); + + // Server startup parameters + $sType = $server->getServerType(); + + // Main server info + $panel = [ + $sType => $this->buildMainServerInfo($server), + ]; + + // Port listeners + $panel = $this->appendPortsToPanel($server, $panel); + + // Show server info + Show::panel($panel, 'Server Information'); + + $bgMsg = '!'; + if ($server->isDaemonize()) { + $bgMsg = '(Run in background)!'; + } + + output()->writef("$sType Server Start Success{$bgMsg}"); + } + /** * Set startup options to override configuration options * @@ -24,29 +65,32 @@ abstract class BaseServerCommand protected function configStartOption(Server $server): void { $asDaemon = input()->getSameOpt(['d', 'daemon'], false); + if ($asDaemon) { $server->setDaemonize(); } } /** - * @return string + * @param Server $server + * + * @return array */ - protected function getFullCommand(): string + protected function buildMainServerInfo(Server $server): array { - // Script file - $script = input()->getScript(); + // Server setting + $settings = $server->getSetting(); + $workerNum = $settings['worker_num']; - // Full command - $command = input()->getFullScript(); + $mainHost = $server->getHost(); + $mainPort = $server->getPort(); - $phpBin = 'php'; - [$ok, $ret,] = Sys::run('which php'); - if ($ok === 0) { - $phpBin = trim($ret); - } - - return sprintf('%s %s %s', $phpBin, $script, $command); + return [ + 'listen' => $mainHost . ':' . $mainPort, + 'type' => $server->getTypeName(), + 'mode' => $server->getModeName(), + 'worker' => $workerNum, + ]; } /** @@ -67,11 +111,81 @@ protected function appendPortsToPanel(Server $server, array $panel): array $upperName = strtoupper($name); $panel[$upperName] = [ - 'listen' => sprintf('%s:%s', $listener->getHost(), $listener->getPort()), + 'listen' => $listener->getHost() . ':' . $listener->getPort(), 'type' => $listener->getTypeName() ]; } return $panel; } + + /** + * Reload Server - reload worker processes + * + * @param Server $server + */ + protected function reloadServer(Server $server): void + { + $script = input()->getScriptFile(); + + // Check if it has started + if (!$server->isRunning()) { + output()->writeln('The server is not running! cannot reload'); + return; + } + + output()->writef('Server %s is reloading', $script); + + if ($reloadTask = input()->hasOpt('t')) { + Show::notice('Will only reload task worker'); + } + + if (!$server->reload($reloadTask)) { + Show::error('The swoole server worker process reload fail!'); + return; + } + + output()->writef('Server %s reload success', $script); + } + + /** + * @param Server $server + */ + protected function restartServer(Server $server): void + { + // If it's has started, stop old server. + if ($server->isRunning()) { + $success = $server->stop(); + + if (!$success) { + output()->error('Stop the old server failed!'); + return; + } + } + + output()->writef('Swoft Server Restart Success!'); + + // Restart server + $server->startWithDaemonize(); + } + + /** + * @return string + */ + protected function getFullCommand(): string + { + // Script file + $script = input()->getScriptFile(); + + // Full command + $command = input()->getFullScript(); + + $phpBin = 'php'; + [$ok, $ret,] = Sys::run('which php'); + if ($ok === 0) { + $phpBin = trim($ret); + } + + return sprintf('%s %s %s', $phpBin, $script, $command); + } } diff --git a/src/server/src/Server.php b/src/server/src/Server.php index 204de70cc..a856eddf9 100644 --- a/src/server/src/Server.php +++ b/src/server/src/Server.php @@ -359,14 +359,10 @@ public function onWorkerStart(CoServer $server, int $workerId): void $this->pidMap['workerPid'] = $server->worker_pid; $event = new WorkerEvent(SwooleEvent::WORKER_START, $server, $workerId); - // Is task process - $isTaskProcess = $workerId >= $server->setting['worker_num']; - $event->taskProcess = $isTaskProcess; - - Swoft::trigger($event); - // Task process - if ($isTaskProcess) { + // Is task process + $event->taskProcess = $workerId >= $server->setting['worker_num']; + if ($event->taskProcess) { $procRole = 'task'; $eventName = ServerEvent::TASK_PROCESS_START; // Worker process @@ -375,27 +371,29 @@ public function onWorkerStart(CoServer $server, int $workerId): void $eventName = ServerEvent::WORK_PROCESS_START; } - // For special role process + // Trigger worker start event + Swoft::trigger($event); + + // For special role process: worker, task $newEvent = clone $event; $newEvent->setName($eventName); Sys::setProcessTitle(sprintf('%s %s process', $this->pidName, $procRole)); - // In coroutine, sync task is not in coroutine + // In coroutine: `sync task` is not in coroutine env. if (Co::id() > 0) { // Before Swoft::trigger(ServerEvent::BEFORE_WORKER_START_EVENT, $this, $server, $workerId); - // Already in coroutine + // Trigger event Swoft::trigger($newEvent, $this); // After event Swoft::trigger(ServerEvent::AFTER_EVENT, $this); - - return ; + return; } - // Trigger task event + // Trigger event Swoft::trigger($newEvent, $this); } diff --git a/src/stdlib/src/PhpType.php b/src/stdlib/src/PhpType.php new file mode 100644 index 000000000..daf9de286 --- /dev/null +++ b/src/stdlib/src/PhpType.php @@ -0,0 +1,21 @@ +createServer(); - // Check if it has started - if ($server->isRunning()) { - $masterPid = $server->getPid(); - output()->writeln("The server have been running!(PID: {$masterPid})"); - return; - } - - // Startup settings - $this->configStartOption($server); - - $settings = $server->getSetting(); - // Setting - $workerNum = $settings['worker_num']; - - // Server startup parameters - $mainHost = $server->getHost(); - $mainPort = $server->getPort(); - - // Main server - $panel = [ - 'TCP' => [ - 'listen' => $mainHost . ':' . $mainPort, - 'type' => $server->getTypeName(), - 'mode' => $server->getModeName(), - 'worker' => $workerNum, - ], - ]; - - // Port Listeners - $panel = $this->appendPortsToPanel($server, $panel); - - Show::panel($panel); - - output()->writef('Tcp server start success !'); + $this->showServerInfoPanel($server); // Start the server $server->start(); @@ -86,31 +52,13 @@ public function start(): void * * @CommandMapping(usage="{fullCommand} [-t]") * @CommandOption("t", desc="Only to reload task processes, default to reload worker and task") - * */ public function reload(): void { $server = $this->createServer(); - $script = input()->getScript(); - - // Check if it has started - if (!$server->isRunning()) { - output()->writeln('The server is not running! cannot reload'); - return; - } - - output()->writef('Server %s is reloading', $script); - if ($reloadTask = input()->hasOpt('t')) { - Show::notice('Will only reload task worker'); - } - - if (!$server->reload($reloadTask)) { - Show::error('The swoole server worker process reload fail!'); - return; - } - - output()->writef('Tcp Server %s reload success', $script); + // Reload server + $this->reloadServer($server); } /** @@ -146,18 +94,8 @@ public function restart(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $success = $server->stop(); - - if (!$success) { - output()->error('Stop the old server failed!'); - return; - } - } - // Restart server - $server->startWithDaemonize(); + $this->restartServer($server); } /** @@ -165,7 +103,7 @@ public function restart(): void */ private function createServer(): TcpServer { - $script = input()->getScript(); + $script = input()->getScriptFile(); $command = $this->getFullCommand(); /* @var TcpServer $server */ diff --git a/src/tcp-server/src/Connection.php b/src/tcp-server/src/Connection.php index a3e19097f..2eb83cfdb 100644 --- a/src/tcp-server/src/Connection.php +++ b/src/tcp-server/src/Connection.php @@ -18,7 +18,7 @@ class Connection implements SessionInterface { use DataPropertyTrait; - private const METADATA_KEY = 'metadata'; + private const METADATA_KEY = '_metadata'; /** * @var int diff --git a/src/tcp-server/src/Listener/BeforeSettingListener.php b/src/tcp-server/src/Listener/BeforeSettingListener.php index a0ee10ba2..fb8f19765 100644 --- a/src/tcp-server/src/Listener/BeforeSettingListener.php +++ b/src/tcp-server/src/Listener/BeforeSettingListener.php @@ -20,7 +20,6 @@ class BeforeSettingListener implements EventHandlerInterface { /** * @param EventInterface $event - * */ public function handle(EventInterface $event): void { diff --git a/src/tcp-server/src/MiddlewareChain.php b/src/tcp-server/src/MiddlewareChain.php index 7cfb7c294..4ac755362 100644 --- a/src/tcp-server/src/MiddlewareChain.php +++ b/src/tcp-server/src/MiddlewareChain.php @@ -3,7 +3,7 @@ namespace Swoft\Tcp\Server; /** - * Class MiddlewareChain + * Class MiddlewareChain TODO ... * * @since 2.0.4 */ diff --git a/src/tcp-server/src/Response.php b/src/tcp-server/src/Response.php index bb0029246..d1d1e002c 100644 --- a/src/tcp-server/src/Response.php +++ b/src/tcp-server/src/Response.php @@ -72,6 +72,11 @@ public function send(Server $server = null): int return 0; } + // Fix: No response data + if ($this->isEmpty()) { + return 0; + } + /** @var Protocol $protocol */ $protocol = Swoft::getBean('tcpServerProtocol'); diff --git a/src/tcp-server/src/Swoole/ConnectListener.php b/src/tcp-server/src/Swoole/ConnectListener.php index 88969f5ed..0f84c37fb 100644 --- a/src/tcp-server/src/Swoole/ConnectListener.php +++ b/src/tcp-server/src/Swoole/ConnectListener.php @@ -44,7 +44,7 @@ public function onConnect(Server $server, int $fd, int $reactorId): void try { // Trigger connect event - Swoft::trigger(TcpServerEvent::CONNECT, $server, $fd, $reactorId); + Swoft::trigger(TcpServerEvent::CONNECT, $fd, $server, $reactorId); /** @var TcpDispatcher $dispatcher */ // $dispatcher = Swoft::getSingleton('tcpDispatcher'); diff --git a/src/tcp-server/test/unit/ResponseTest.php b/src/tcp-server/test/unit/ResponseTest.php new file mode 100644 index 000000000..80ea405b0 --- /dev/null +++ b/src/tcp-server/test/unit/ResponseTest.php @@ -0,0 +1,21 @@ +assertTrue($w->isEmpty()); + $w->setContent('hi'); + $this->assertFalse($w->isEmpty()); + } +} diff --git a/src/tcp/src/Response.php b/src/tcp/src/Response.php index c0570fdde..a19c605d5 100644 --- a/src/tcp/src/Response.php +++ b/src/tcp/src/Response.php @@ -91,6 +91,14 @@ public function isFail(): bool return $this->code !== self::OK; } + /** + * @return bool + */ + public function isEmpty(): bool + { + return $this->content === '' && $this->data === null; + } + /** * @return int */ diff --git a/src/websocket-server/src/Command/WsServerCommand.php b/src/websocket-server/src/Command/WsServerCommand.php index 7b368fe0f..415adc2a2 100644 --- a/src/websocket-server/src/Command/WsServerCommand.php +++ b/src/websocket-server/src/Command/WsServerCommand.php @@ -5,9 +5,9 @@ use Swoft\Console\Annotation\Mapping\Command; use Swoft\Console\Annotation\Mapping\CommandMapping; use Swoft\Console\Annotation\Mapping\CommandOption; -use Swoft\Console\Helper\Show; use Swoft\Server\Command\BaseServerCommand; use Swoft\Server\Exception\ServerException; +use Swoft\Server\Server; use Swoft\Server\SwooleEvent; use Swoft\WebSocket\Server\WebSocketServer; use Throwable; @@ -43,50 +43,26 @@ public function start(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $masterPid = $server->getPid(); - output()->writeln("The server have been running!(PID: {$masterPid})"); - return; - } - - // Startup settings - $this->configStartOption($server); - - $settings = $server->getSetting(); - // Setting - $workerNum = $settings['worker_num']; - - // Server startup parameters - $mainHost = $server->getHost(); - $mainPort = $server->getPort(); - - $allowHttp = $server->hasListener(SwooleEvent::REQUEST); - $httpText = $allowHttp ? 'enabled' : 'disabled'; - - // Main server - $panel = [ - 'WebSocket' => [ - 'listen' => $mainHost . ':' . $mainPort, - 'type' => $server->getTypeName(), - 'mode' => $server->getModeName(), - 'worker' => $workerNum . " (HTTP:$httpText)", - ], - // 'ExtraInfo' => [ - // 'HttpHandle' => $server->hasListener(SwooleEvent::REQUEST), - // 'pidFile' => $server->getPidFile(), - // ], - ]; + $this->showServerInfoPanel($server); - // Port Listeners - $panel = $this->appendPortsToPanel($server, $panel); + // Start the server + $server->start(); + } - Show::panel($panel); + /** + * @param Server $server + * + * @return array + */ + protected function buildMainServerInfo(Server $server): array + { + $info = parent::buildMainServerInfo($server); - output()->writef('WebSocket Server start success !'); + $openHttp = $server->hasListener(SwooleEvent::REQUEST); + $httpText = $openHttp ? 'enabled' : 'disabled'; - // Start the server - $server->start(); + $info['worker'] .= " (HTTP:$httpText)"; + return $info; } /** @@ -98,26 +74,9 @@ public function start(): void public function reload(): void { $server = $this->createServer(); - $script = input()->getScript(); - - // Check if it has started - if (!$server->isRunning()) { - output()->writeln('The server is not running! cannot reload'); - return; - } - - output()->writef('Server %s is reloading', $script); - - if ($reloadTask = input()->hasOpt('t')) { - Show::notice('Will only reload task worker'); - } - - if (!$server->reload($reloadTask)) { - Show::error('The swoole server worker process reload fail!'); - return; - } - output()->writef('Server %s reload success', $script); + // Reload server + $this->reloadServer($server); } /** @@ -153,18 +112,8 @@ public function restart(): void { $server = $this->createServer(); - // Check if it has started - if ($server->isRunning()) { - $success = $server->stop(); - - if (!$success) { - output()->error('Stop the old server failed!'); - return; - } - } - // Restart server - $server->startWithDaemonize(); + $this->restartServer($server); } /** @@ -172,7 +121,7 @@ public function restart(): void */ private function createServer(): WebSocketServer { - $script = input()->getScript(); + $script = input()->getScriptFile(); $command = $this->getFullCommand(); /* @var WebSocketServer $server */ diff --git a/src/websocket-server/src/Listener/ConnStorageSubscriber.php b/src/websocket-server/src/Listener/ConnStorageSubscriber.php index 4d0a4b9eb..b09e4def8 100644 --- a/src/websocket-server/src/Listener/ConnStorageSubscriber.php +++ b/src/websocket-server/src/Listener/ConnStorageSubscriber.php @@ -9,6 +9,7 @@ use Swoft\Session\Session; use Swoft\WebSocket\Server\ConnectionStorage; use Swoft\WebSocket\Server\WsServerEvent; +use Swoft\Config\Annotation\Mapping\Config; /** * Class ConnStorageSubscriber @@ -18,6 +19,12 @@ */ class ConnStorageSubscriber implements EventSubscriberInterface { + /** + * @Config("websocket.autoRestoreConn") + * @var bool + */ + private $autoRestoreConn = false; + /** * Configure events and corresponding processing methods (you can configure the priority) * @@ -32,7 +39,7 @@ public static function getSubscribedEvents(): array return [ WsServerEvent::HANDSHAKE_SUCCESS => 'handshakeOk', WsServerEvent::MESSAGE_RECEIVE => 'messageReceive', - WsServerEvent::CLOSE_BEFORE => 'messageReceive', + WsServerEvent::CLOSE_BEFORE => 'connClose', ]; } @@ -49,6 +56,10 @@ protected function getStorage(): ConnectionStorage */ public function handshakeOk(EventInterface $event): void { + if (!$this->autoRestoreConn) { + return; + } + [$request, $response] = $event->getParams(); $this->getStorage()->storage($request, $response); @@ -59,6 +70,10 @@ public function handshakeOk(EventInterface $event): void */ public function messageReceive(EventInterface $event): void { + if (!$this->autoRestoreConn) { + return; + } + $fd = (int)$event->getTarget(); if (!Session::has((string)$fd)) { @@ -71,6 +86,10 @@ public function messageReceive(EventInterface $event): void */ public function connClose(EventInterface $event): void { + if (!$this->autoRestoreConn) { + return; + } + $fd = (int)$event->getTarget(); $this->getStorage()->remove($fd); diff --git a/src/websocket-server/src/Message/MiddlewareChain.php b/src/websocket-server/src/Message/MiddlewareChain.php index 5af232c72..9829ece71 100644 --- a/src/websocket-server/src/Message/MiddlewareChain.php +++ b/src/websocket-server/src/Message/MiddlewareChain.php @@ -71,16 +71,16 @@ public function use(...$middleware): self * Add middleware * This method prepends new middleware to the application middleware stack. * - * @param MiddlewareInterface[] ...$middlewareList Any callable that accepts two arguments: - * 1. A Request object - * 2. A Handler object + * @param MiddlewareInterface[] ...$middles Any callable that accepts two arguments: + * 1. A Request object + * 2. A Handler object * * @return $this * @throws RuntimeException */ - public function add(...$middlewareList): self + public function add(...$middles): self { - foreach ($middlewareList as $middleware) { + foreach ($middles as $middleware) { $this->middle($middleware); } diff --git a/src/websocket-server/src/Message/Response.php b/src/websocket-server/src/Message/Response.php index f2780962b..1035d2cfd 100644 --- a/src/websocket-server/src/Message/Response.php +++ b/src/websocket-server/src/Message/Response.php @@ -183,6 +183,11 @@ public function send(Connection $conn = null): int return 0; } + // Fix: No response data + if ($this->isEmpty()) { + return 0; + } + /** @noinspection CallableParameterUseCaseInTypeContextInspection */ $conn = $conn ?: Session::mustGet(); $server = $conn->getServer(); @@ -264,6 +269,14 @@ protected function formatContent(Connection $conn): string return $content; } + /** + * @return bool + */ + public function isEmpty(): bool + { + return $this->content === '' && $this->data === null; + } + /** * @return int */ diff --git a/src/websocket-server/src/Storage/AbstractStorage.php b/src/websocket-server/src/Storage/AbstractStorage.php index 3c2580b17..ba538f971 100644 --- a/src/websocket-server/src/Storage/AbstractStorage.php +++ b/src/websocket-server/src/Storage/AbstractStorage.php @@ -4,8 +4,6 @@ /** * Class AbstractStorage - * - * @package Swoft\WebSocket\Server\Storage */ abstract class AbstractStorage { @@ -25,7 +23,6 @@ abstract class AbstractStorage '/' => 'rooms' ]; - /***************************************************************************** * some methods for rooms(of an namespace) ****************************************************************************/ diff --git a/src/websocket-server/src/Storage/SwooleStorage.php b/src/websocket-server/src/Storage/SwooleStorage.php index b97df5b0f..889235866 100644 --- a/src/websocket-server/src/Storage/SwooleStorage.php +++ b/src/websocket-server/src/Storage/SwooleStorage.php @@ -22,11 +22,6 @@ class SwooleStorage implements StorageInterface */ private $size = 20480; - // public function __construct() - // { - // $this->create(); - // } - public function create(): void { $this->db = new Table($this->size); diff --git a/src/websocket-server/src/Swoole/CloseListener.php b/src/websocket-server/src/Swoole/CloseListener.php index cfbd26109..48f8ca887 100644 --- a/src/websocket-server/src/Swoole/CloseListener.php +++ b/src/websocket-server/src/Swoole/CloseListener.php @@ -4,6 +4,7 @@ use Swoft; use Swoft\Bean\Annotation\Mapping\Bean; +use Swoft\Bean\Annotation\Mapping\Inject; use Swoft\Context\Context; use Swoft\Server\Contract\CloseInterface; use Swoft\Session\Session; @@ -27,6 +28,12 @@ */ class CloseListener implements CloseInterface { + /** + * @Inject("wsDispatcher") + * @var WsDispatcher + */ + private $wsDispatcher; + /** * Close event * @@ -85,9 +92,7 @@ public function onClose(Server $server, int $fd, int $reactorId): void // Handshake successful callback close handle if ($conn->isHandshake()) { - /** @var WsDispatcher $dispatcher */ - $dispatcher = Swoft::getSingleton('wsDispatcher'); - $dispatcher->close($server, $fd); + $this->wsDispatcher->close($server, $fd); } // Call on close callback @@ -103,7 +108,7 @@ public function onClose(Server $server, int $fd, int $reactorId): void // Defer Swoft::trigger(SwoftEvent::COROUTINE_DEFER); - // Destroy + // Destroy context Swoft::trigger(SwoftEvent::COROUTINE_COMPLETE); // Remove connection diff --git a/src/websocket-server/src/WsMessageDispatcher.php b/src/websocket-server/src/WsMessageDispatcher.php index b166174ea..638caefe8 100644 --- a/src/websocket-server/src/WsMessageDispatcher.php +++ b/src/websocket-server/src/WsMessageDispatcher.php @@ -6,6 +6,7 @@ use ReflectionType; use Swoft; use Swoft\Bean\Annotation\Mapping\Bean; +use Swoft\Bean\Annotation\Mapping\Inject; use Swoft\Session\Session; use Swoft\WebSocket\Server\Contract\WsModuleInterface; use Swoft\WebSocket\Server\Exception\WsMessageParseException; @@ -26,8 +27,14 @@ * * @Bean("wsMsgDispatcher") */ -class WsMessageDispatcher // extends \Swoft\Concern\AbstractDispatcher +class WsMessageDispatcher { + /** + * @Inject("wsRouter") + * @var Router + */ + private $router; + /** * Dispatch ws message handle * @@ -72,20 +79,16 @@ public function dispatch(Server $server, Request $request, Response $response): $request->setMessage($message); /** @var Router $router */ - $cmdId = $message->getCmd() ?: $info['defaultCommand']; - $router = Swoft::getSingleton('wsRouter'); + $cmdId = $message->getCmd() ?: $info['defaultCommand']; - [$status, $route] = $router->matchCommand($info['path'], $cmdId); + [$status, $route] = $this->router->matchCommand($info['path'], $cmdId); if ($status === Router::NOT_FOUND) { throw new WsMessageRouteException("message command '$cmdId' is not found, in module {$info['path']}"); } [$ctlClass, $ctlMethod] = $route['handler']; - server()->log( - "Message: conn#{$fd} call message command handler '{$ctlClass}::{$ctlMethod}'", - $message->toArray(), - 'debug' - ); + server()->log("Message: conn#{$fd} call message command handler '{$ctlClass}::{$ctlMethod}'", + $message->toArray(), 'debug'); $object = Swoft::getBean($ctlClass); $params = $this->getBindParams($ctlClass, $ctlMethod, $request, $response); diff --git a/src/websocket-server/test/testing/MockHttpResponse.php b/src/websocket-server/test/testing/MockHttpResponse.php index a5377c60c..e2f38aae7 100644 --- a/src/websocket-server/test/testing/MockHttpResponse.php +++ b/src/websocket-server/test/testing/MockHttpResponse.php @@ -74,6 +74,7 @@ public function header($key, $value, $ucwords = null) * @param string $domain * @param bool $secure * @param bool $httpOnly + * @param null $samesite */ public function cookie( $name, @@ -82,7 +83,8 @@ public function cookie( $path = null, $domain = null, $secure = null, - $httpOnly = null + $httpOnly = null, + $samesite = null ) { $result = \urlencode($name) . '=' . \urlencode($value); diff --git a/src/websocket-server/test/unit/Message/ResponseTest.php b/src/websocket-server/test/unit/Message/ResponseTest.php index b0a3c0518..1481353c5 100644 --- a/src/websocket-server/test/unit/Message/ResponseTest.php +++ b/src/websocket-server/test/unit/Message/ResponseTest.php @@ -5,6 +5,9 @@ use PHPUnit\Framework\TestCase; use Swoft\WebSocket\Server\Message\Response; +/** + * Class ResponseTest + */ class ResponseTest extends TestCase { public function testBasic(): void @@ -38,5 +41,9 @@ public function testBasic(): void $this->assertEmpty($w->getFds()); $w->toMore([33, 34]); $this->assertSame([33, 34], $w->getFds()); + + $this->assertTrue($w->isEmpty()); + $w->setContent('hi'); + $this->assertFalse($w->isEmpty()); } }