diff --git a/src/server/src/Concern/CommonProtocolDataTrait.php b/src/server/src/Concern/CommonProtocolDataTrait.php index 6db20d592..16a18af99 100644 --- a/src/server/src/Concern/CommonProtocolDataTrait.php +++ b/src/server/src/Concern/CommonProtocolDataTrait.php @@ -50,10 +50,13 @@ public function getExt(): array /** * @param array $ext + * + * @return $this */ - public function setExt(array $ext): void + public function setExt(array $ext): self { $this->ext = $ext; + return $this; } /** diff --git a/src/tcp-server/phpunit.xml b/src/tcp-server/phpunit.xml index 823b92f28..d88ee67cd 100644 --- a/src/tcp-server/phpunit.xml +++ b/src/tcp-server/phpunit.xml @@ -1,16 +1,16 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd" + bootstrap="test/bootstrap.php" + backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false"> ./test/unit diff --git a/src/tcp-server/src/Annotation/Parser/TcpControllerParser.php b/src/tcp-server/src/Annotation/Parser/TcpControllerParser.php index f7398fe45..8062815e8 100644 --- a/src/tcp-server/src/Annotation/Parser/TcpControllerParser.php +++ b/src/tcp-server/src/Annotation/Parser/TcpControllerParser.php @@ -20,7 +20,7 @@ final class TcpControllerParser extends Parser /** * Parse object * - * @param int $type Class or Method or Property + * @param int $type Class or Method or Property * @param TcpController $annotation Annotation object * * @return array diff --git a/src/tcp-server/src/Context/TcpConnectContext.php b/src/tcp-server/src/Context/TcpConnectContext.php index 45a4bbef6..8ae6343e7 100644 --- a/src/tcp-server/src/Context/TcpConnectContext.php +++ b/src/tcp-server/src/Context/TcpConnectContext.php @@ -25,8 +25,8 @@ class TcpConnectContext extends AbstractContext protected $reactorId; /** - * @param int $fd - * @param int $reactorId + * @param int $fd + * @param int $reactorId * * @return self */ diff --git a/src/tcp-server/src/Context/TcpReceiveContext.php b/src/tcp-server/src/Context/TcpReceiveContext.php index 9f2039aa5..46badba7d 100644 --- a/src/tcp-server/src/Context/TcpReceiveContext.php +++ b/src/tcp-server/src/Context/TcpReceiveContext.php @@ -56,7 +56,7 @@ public function clear(): void { parent::clear(); - $this->request = null; + $this->request = null; $this->response = null; } diff --git a/src/tcp-server/src/Contract/MiddlewareInterface.php b/src/tcp-server/src/Contract/MiddlewareInterface.php index 9340a8bd5..07772cacb 100644 --- a/src/tcp-server/src/Contract/MiddlewareInterface.php +++ b/src/tcp-server/src/Contract/MiddlewareInterface.php @@ -13,8 +13,8 @@ interface MiddlewareInterface { /** - * @param RequestInterface|Request $request - * @param RequestHandlerInterface $handler + * @param RequestInterface|Request $request + * @param RequestHandlerInterface $handler * * @return ResponseInterface|Response */ diff --git a/src/tcp-server/src/MiddlewareChain.php b/src/tcp-server/src/MiddlewareChain.php index c3276830f..09a58058c 100644 --- a/src/tcp-server/src/MiddlewareChain.php +++ b/src/tcp-server/src/MiddlewareChain.php @@ -103,9 +103,7 @@ public function handle(RequestInterface $request): ResponseInterface } if (!$response instanceof ResponseInterface) { - throw new TcpMiddlewareException( - 'Middleware must return object and instance of ' . ResponseInterface::class - ); + throw new TcpMiddlewareException('Middleware must return object and instance of ' . ResponseInterface::class); } return $response; diff --git a/src/tcp-server/src/Request.php b/src/tcp-server/src/Request.php index 1ab26dfdb..243bc12e1 100644 --- a/src/tcp-server/src/Request.php +++ b/src/tcp-server/src/Request.php @@ -20,9 +20,16 @@ class Request implements RequestInterface /** * The request data key for storage matched route info. + * eg: + * [ + * status, + * [ + * command => string, + * handler => [class, method], + * ] + * ] */ public const ROUTE_INFO = '__route'; - public const COMMAND = '__cmd'; /** * Receiver fd diff --git a/src/tcp-server/src/Response.php b/src/tcp-server/src/Response.php index 45a5f4c14..eaac9461d 100644 --- a/src/tcp-server/src/Response.php +++ b/src/tcp-server/src/Response.php @@ -6,9 +6,9 @@ use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Log\Helper\CLog; use Swoft\Tcp\Protocol; +use Swoft\Tcp\Response as TcpResponse; use Swoft\Tcp\Server\Contract\ResponseInterface; use Swoft\Tcp\Server\Exception\TcpResponseException; -use Swoft\Tcp\Response as TcpResponse; use Swoole\Server; /** @@ -72,17 +72,13 @@ 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'); + $protocol = Swoft::getBean('tcpServerProtocol'); + $this->sent = true; // Content is empty, skip send - if (!$content = $protocol->packResponse($this)) { - $this->sent = true; + $content = $protocol->packResponse($this); + if ('' === $content) { CLog::warning('cannot send empty content to tcp client'); return 0; } @@ -92,12 +88,12 @@ public function send(Server $server = null): int // Trigger event before push message content to client Swoft::trigger(TcpServerEvent::CONTENT_SEND, $server, $content, $this); + // Do send content if ($server->send($this->fd, $content) === false) { $code = $server->getLastError(); throw new TcpResponseException("Error on send data to client #{$this->fd}", $code); } - $this->sent = true; return 1; } diff --git a/src/tcp-server/src/Router/RouteRegister.php b/src/tcp-server/src/Router/RouteRegister.php index f21af15e0..2a5c5ff00 100644 --- a/src/tcp-server/src/Router/RouteRegister.php +++ b/src/tcp-server/src/Router/RouteRegister.php @@ -28,6 +28,7 @@ final class RouteRegister * middles => [middleware0], * ] * ] + * * @var array */ private static $controllers = []; diff --git a/src/tcp-server/src/Router/Router.php b/src/tcp-server/src/Router/Router.php index 01e8c6efb..aea9fdd0e 100644 --- a/src/tcp-server/src/Router/Router.php +++ b/src/tcp-server/src/Router/Router.php @@ -22,6 +22,7 @@ class Router implements RouterInterface * 'handler' => [class, method], * ] * ] + * * @var array */ private $routes = []; @@ -30,6 +31,7 @@ class Router implements RouterInterface * [ * 'command name' => [middle1, middle2], * ] + * * @var array */ private $middlewares = []; @@ -112,7 +114,7 @@ public function addMiddlewares(string $cmd, array $middlewares): void * * @return array */ - public function getMiddlewaresByCmd(string $cmd): array + public function getCmdMiddlewares(string $cmd): array { return $this->middlewares[$cmd] ?? []; } diff --git a/src/tcp-server/src/Swoole/ReceiveListener.php b/src/tcp-server/src/Swoole/ReceiveListener.php index 92c656cc0..3cc870ed4 100644 --- a/src/tcp-server/src/Swoole/ReceiveListener.php +++ b/src/tcp-server/src/Swoole/ReceiveListener.php @@ -74,9 +74,8 @@ public function onReceive(Server $server, int $fd, int $reactorId, string $data) /** @var TcpErrorDispatcher $errDispatcher */ $errDispatcher = Swoft::getSingleton(TcpErrorDispatcher::class); + $errDispatcher->receiveError($e, $response); - // Dispatching error handle - $response = $errDispatcher->receiveError($e, $response); $response->send($server); } finally { // Defer diff --git a/src/tcp-server/src/TcpDispatcher.php b/src/tcp-server/src/TcpDispatcher.php index 611610d17..fbf813d2a 100644 --- a/src/tcp-server/src/TcpDispatcher.php +++ b/src/tcp-server/src/TcpDispatcher.php @@ -41,6 +41,8 @@ class TcpDispatcher implements MiddlewareInterface /** * Pre-check whether the route matches successfully. + * True - Check if the status matches successfully after matching. + * False - check the status after the middleware process * * @var bool */ @@ -51,21 +53,21 @@ class TcpDispatcher implements MiddlewareInterface * * @var array */ - protected $middlewares = []; + private $middlewares = []; /** * User defined global pre-middlewares * * @var array */ - protected $preMiddlewares = []; + private $preMiddlewares = []; /** * User defined global after-middlewares * * @var array */ - protected $afterMiddlewares = []; + private $afterMiddlewares = []; /** * @param Request $request @@ -100,15 +102,17 @@ public function dispatch(Request $request, Response $response): ResponseInterfac $status = $result[0]; // Storage route info - $request->set(Request::COMMAND, $command); $request->set(Request::ROUTE_INFO, $result); // Found, get command middlewares + $middlewares = []; if ($status === Router::FOUND) { - $cmdMiddles = $router->getMiddlewaresByCmd($command); + $middlewares = $router->getCmdMiddlewares($command); - // append middlewares - $this->addMiddlewares($cmdMiddles); + // Append command middlewares + if ($middlewares) { + $middlewares = array_merge($this->middlewares, $middlewares); + } // If this->preCheckRoute is True, pre-check route match status } elseif ($this->preCheckRoute) { @@ -117,10 +121,12 @@ public function dispatch(Request $request, Response $response): ResponseInterfac } // Has middlewares - if ($middlewares = $this->mergeMiddlewares()) { + if ($middlewares = $this->mergeMiddlewares($middlewares)) { $chain = MiddlewareChain::new($this); $chain->addMiddles($middlewares); + server()->log('request will use middleware process, middleware count: ' . $chain->count(), [], 'debug'); + return $chain->run($request); } @@ -238,11 +244,11 @@ public function getMiddlewares(): array } /** - * @param array $middlewares + * @param string $middleware */ - public function setMiddlewares(array $middlewares): void + public function addMiddleware(string $middleware): void { - $this->middlewares = $middlewares; + $this->middlewares[] = $middleware; } /** @@ -255,6 +261,14 @@ public function addMiddlewares(array $middlewares): void } } + /** + * @param array $middlewares + */ + public function setMiddlewares(array $middlewares): void + { + $this->middlewares = $middlewares; + } + /** * @return array */ @@ -290,12 +304,14 @@ public function setAfterMiddlewares(array $afterMiddlewares): void /** * merge all middlewares * + * @param array $middlewares + * * @return array */ - protected function mergeMiddlewares(): array + protected function mergeMiddlewares(array $middlewares): array { - if ($this->middlewares) { - return array_merge($this->preMiddlewares, $this->middlewares, $this->afterMiddlewares); + if ($middlewares) { + return array_merge($this->preMiddlewares, $middlewares, $this->afterMiddlewares); } return array_merge($this->preMiddlewares, $this->afterMiddlewares); diff --git a/src/tcp-server/src/TcpErrorDispatcher.php b/src/tcp-server/src/TcpErrorDispatcher.php index 0e034b196..95f29f917 100644 --- a/src/tcp-server/src/TcpErrorDispatcher.php +++ b/src/tcp-server/src/TcpErrorDispatcher.php @@ -4,6 +4,7 @@ use Swoft; use Swoft\Bean\Annotation\Mapping\Bean; +use Swoft\Bean\Annotation\Mapping\Inject; use Swoft\Error\ErrorManager; use Swoft\Error\ErrorType; use Swoft\Log\Helper\CLog; @@ -20,18 +21,23 @@ */ class TcpErrorDispatcher { + /** + * @Inject() + * @var ErrorManager + */ + private $errorManager; + /** * @param Throwable $e * @param int $fd */ public function connectError(Throwable $e, int $fd): void { - /** @var ErrorManager $handlers */ - $handlers = Swoft::getSingleton(ErrorManager::class); + /** @var TcpConnectErrorHandlerInterface $errorHandler */ + $errorHandler = $this->errorManager->matchHandler($e, ErrorType::TCP_CNT); - /** @var TcpConnectErrorHandlerInterface $handler */ - if ($handler = $handlers->matchHandler($e, ErrorType::TCP_CNT)) { - $handler->handle($e, $fd); + if ($errorHandler) { + $errorHandler->handle($e, $fd); return; } @@ -46,12 +52,10 @@ public function connectError(Throwable $e, int $fd): void */ public function receiveError(Throwable $e, Response $response): Response { - /** @var ErrorManager $handlers */ - $handlers = Swoft::getSingleton(ErrorManager::class); - - /** @var TcpReceiveErrorHandlerInterface $handler */ - if ($handler = $handlers->matchHandler($e, ErrorType::TCP_RCV)) { - return $handler->handle($e, $response); + /** @var TcpReceiveErrorHandlerInterface $errorHandler */ + $errorHandler = $this->errorManager->matchHandler($e, ErrorType::TCP_RCV); + if ($errorHandler) { + return $errorHandler->handle($e, $response); } $this->logError('Receive', $e); @@ -68,12 +72,10 @@ public function receiveError(Throwable $e, Response $response): Response */ public function closeError(Throwable $e, int $fd): void { - /** @var ErrorManager $handlers */ - $handlers = Swoft::getSingleton(ErrorManager::class); - - /** @var Swoft\Tcp\Server\Contract\TcpCloseErrorHandlerInterface $handler */ - if ($handler = $handlers->matchHandler($e, ErrorType::TCP_CLS)) { - $handler->handle($e, $fd); + /** @var Swoft\Tcp\Server\Contract\TcpCloseErrorHandlerInterface $errorHandler */ + $errorHandler = $this->errorManager->matchHandler($e, ErrorType::TCP_CLS); + if ($errorHandler) { + $errorHandler->handle($e, $fd); return; } @@ -88,13 +90,7 @@ public function closeError(Throwable $e, int $fd): void private function logError(string $typeName, Throwable $e): void { Log::error($e->getMessage()); - CLog::error("Tcp %s Error(no handler, %s): %s\nAt File %s line %d\nTrace:\n%s", - $typeName, - get_class($e), - $e->getMessage(), - $e->getFile(), - $e->getLine(), - $e->getTraceAsString() - ); + CLog::error("Tcp %s Error(no handler, %s): %s\nAt File %s line %d\nTrace:\n%s", $typeName, get_class($e), + $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString()); } } diff --git a/src/tcp-server/src/TcpServer.php b/src/tcp-server/src/TcpServer.php index 575a55e55..f33ee62ad 100644 --- a/src/tcp-server/src/TcpServer.php +++ b/src/tcp-server/src/TcpServer.php @@ -5,8 +5,6 @@ use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Server\Exception\ServerException; use Swoft\Server\Server; -use Swoft\Session\Session; -use Swoft\Stdlib\Helper\JsonHelper; use Swoole\Server as SwServer; /** diff --git a/src/tcp-server/src/TcpServerEvent.php b/src/tcp-server/src/TcpServerEvent.php index f7317bad6..cb8f587a7 100644 --- a/src/tcp-server/src/TcpServerEvent.php +++ b/src/tcp-server/src/TcpServerEvent.php @@ -21,6 +21,7 @@ final class TcpServerEvent /** * On receive before + * * @deprecated please use RECEIVE_BEFORE */ public const RECEIVE = 'swoft.tcp.server.receive'; @@ -33,6 +34,7 @@ final class TcpServerEvent /** * On package send * - before call response->send() + * * @deprecated please use PACKAGE_RESPONSE instead */ public const PACKAGE_SEND = 'swoft.tcp.server.package.response'; diff --git a/src/tcp-server/test/bootstrap.php b/src/tcp-server/test/bootstrap.php index 75378126e..a3b73f86d 100644 --- a/src/tcp-server/test/bootstrap.php +++ b/src/tcp-server/test/bootstrap.php @@ -1,4 +1,5 @@ $dir) { $loader->addPsr4($prefix, $componentDir . '/' . $dir); } @@ -25,7 +26,7 @@ $loader = require dirname(__DIR__, 5) . '/autoload.php'; // need load testing psr4 config map - $composerData = json_decode(file_get_contents($componentJson), true); + $composerData = json_decode(file_get_contents($componentJson), true); foreach ($composerData['autoload-dev']['psr-4'] as $prefix => $dir) { $loader->addPsr4($prefix, $componentDir . '/' . $dir); @@ -35,7 +36,7 @@ } $application = new TestApplication([ - 'basePath' => __DIR__ + 'basePath' => __DIR__ ]); $application->setBeanFile(__DIR__ . '/testing/bean.php'); $application->run(); diff --git a/src/tcp-server/test/testing/AutoLoader.php b/src/tcp-server/test/testing/AutoLoader.php index 9b1b7245f..47212f202 100644 --- a/src/tcp-server/test/testing/AutoLoader.php +++ b/src/tcp-server/test/testing/AutoLoader.php @@ -30,7 +30,7 @@ public function metadata(): array { return [ 'tcpServer' => [ - 'debug' => 0, + 'debug' => 0, 'setting' => [ 'log_file' => '', ] diff --git a/src/tcp-server/test/testing/Middleware/CoreMiddleware.php b/src/tcp-server/test/testing/Middleware/CoreMiddleware.php index 802b9c1f1..26266533a 100644 --- a/src/tcp-server/test/testing/Middleware/CoreMiddleware.php +++ b/src/tcp-server/test/testing/Middleware/CoreMiddleware.php @@ -3,8 +3,8 @@ namespace SwoftTest\Tcp\Server\Testing\Middleware; use Swoft\Bean\Annotation\Mapping\Bean; -use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\MiddlewareInterface; +use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\RequestInterface; use Swoft\Tcp\Server\Contract\ResponseInterface; use Swoft\Tcp\Server\Response; diff --git a/src/tcp-server/test/testing/Middleware/User1Middleware.php b/src/tcp-server/test/testing/Middleware/User1Middleware.php index 56aef6f00..e65dc09e7 100644 --- a/src/tcp-server/test/testing/Middleware/User1Middleware.php +++ b/src/tcp-server/test/testing/Middleware/User1Middleware.php @@ -3,8 +3,8 @@ namespace SwoftTest\Tcp\Server\Testing\Middleware; use Swoft\Bean\Annotation\Mapping\Bean; -use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\MiddlewareInterface; +use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\RequestInterface; use Swoft\Tcp\Server\Contract\ResponseInterface; @@ -24,7 +24,7 @@ class User1Middleware implements MiddlewareInterface public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $start = '>user1 '; - $resp = $handler->handle($request); + $resp = $handler->handle($request); $resp->setData($start . $resp->getData() . ' user1>'); diff --git a/src/tcp-server/test/testing/Middleware/User2Middleware.php b/src/tcp-server/test/testing/Middleware/User2Middleware.php index 80559e671..26f1b12c1 100644 --- a/src/tcp-server/test/testing/Middleware/User2Middleware.php +++ b/src/tcp-server/test/testing/Middleware/User2Middleware.php @@ -3,8 +3,8 @@ namespace SwoftTest\Tcp\Server\Testing\Middleware; use Swoft\Bean\Annotation\Mapping\Bean; -use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\MiddlewareInterface; +use Swoft\Tcp\Server\Contract\RequestHandlerInterface; use Swoft\Tcp\Server\Contract\RequestInterface; use Swoft\Tcp\Server\Contract\ResponseInterface; @@ -24,7 +24,7 @@ class User2Middleware implements MiddlewareInterface public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $start = '>user2 '; - $resp = $handler->handle($request); + $resp = $handler->handle($request); $resp->setData($start . $resp->getData() . ' user2>'); diff --git a/src/tcp-server/test/unit/ResponseTest.php b/src/tcp-server/test/unit/ResponseTest.php index 80ea405b0..b8c361b60 100644 --- a/src/tcp-server/test/unit/ResponseTest.php +++ b/src/tcp-server/test/unit/ResponseTest.php @@ -14,8 +14,21 @@ public function testBasic(): void { $w = Response::new(22); + $this->assertFalse($w->isSent()); + $this->assertSame(22, $w->getFd()); + $this->assertSame(22, $w->getReqFd()); + + $w->setFd(12); + $this->assertSame(12, $w->getFd()); + + $w->setSent(true); + $this->assertTrue($w->isSent()); + $this->assertTrue($w->isEmpty()); $w->setContent('hi'); $this->assertFalse($w->isEmpty()); + $w->setCode(23); + $w->setContent(''); + $this->assertFalse($w->isEmpty()); } } diff --git a/src/tcp-server/test/unit/Router/RouterTest.php b/src/tcp-server/test/unit/Router/RouterTest.php index 7c150123f..ab0ef431c 100644 --- a/src/tcp-server/test/unit/Router/RouterTest.php +++ b/src/tcp-server/test/unit/Router/RouterTest.php @@ -2,14 +2,14 @@ namespace SwoftTest\Tcp\Server\Unit\Router; -use SwoftTest\Tcp\Server\Testing\Middleware\User1Middleware; -use SwoftTest\Tcp\Server\Testing\Middleware\User2Middleware; -use function bean; -use function get_class; use PHPUnit\Framework\TestCase; use Swoft\Tcp\Server\Exception\TcpServerRouteException; use Swoft\Tcp\Server\Router\Router; +use SwoftTest\Tcp\Server\Testing\Middleware\User1Middleware; +use SwoftTest\Tcp\Server\Testing\Middleware\User2Middleware; use Throwable; +use function bean; +use function get_class; /** * Class RouterTest @@ -67,18 +67,19 @@ public function testAddError(): void $r->add('test', []); } catch (Throwable $e) { $this->assertSame(TcpServerRouteException::class, get_class($e)); - $this->assertSame('The tcp server command(test) handler cannot be empty', $e->getMessage()); + $this->assertSame('The tcp server command(test) handler cannot be empty', $e->getMessage()); } } - public function testMiddlewares():void + public function testMiddlewares(): void { + /** @var Router $router */ $router = bean('tcpRouter'); $this->assertNotEmpty($ms = $router->getMiddlewares()); $this->assertArrayHasKey('tcpTest.test', $ms); - $this->assertNotEmpty($ms = $router->getMiddlewaresByCmd('tcpTest.test')); + $this->assertNotEmpty($ms = $router->getCmdMiddlewares('tcpTest.test')); $this->assertSame(User1Middleware::class, $ms[0]); $this->assertSame(User2Middleware::class, $ms[1]); } diff --git a/src/tcp-server/test/unit/TcpDispatcherTest.php b/src/tcp-server/test/unit/TcpDispatcherTest.php index df20bc390..cf7152ea0 100644 --- a/src/tcp-server/test/unit/TcpDispatcherTest.php +++ b/src/tcp-server/test/unit/TcpDispatcherTest.php @@ -2,12 +2,15 @@ namespace SwoftTest\Tcp\Server\Unit; +use ReflectionException; use Swoft\Tcp\Server\Exception\CommandNotFoundException; use Swoft\Tcp\Server\Exception\TcpMiddlewareException; use Swoft\Tcp\Server\Exception\TcpUnpackingException; use Swoft\Tcp\Server\Request; use SwoftTest\Tcp\Server\Testing\MockTcpResponse; +use Throwable; use function bean; +use function get_class; /** * Class TcpDispatcherTest @@ -15,7 +18,7 @@ class TcpDispatcherTest extends TcpServerTestCase { /** - * @throws \ReflectionException + * @throws ReflectionException * @throws CommandNotFoundException * @throws TcpMiddlewareException * @throws TcpUnpackingException @@ -24,10 +27,14 @@ public function testDispatch(): void { $td = bean('tcpDispatcher'); - $req = Request::new(1, 'data', 2); - $res = new MockTcpResponse(); + try { + $req = Request::new(1, 'not-exist', 2); + $res = new MockTcpResponse(); - $this->assertNotEmpty($td); - $td->dispatch($req, $res); + $td->dispatch($req, $res); + } catch (Throwable $e) { + $this->assertSame(CommandNotFoundException::class, get_class($e)); + $this->assertSame("request command 'not-exist' is not found of the tcp server", $e->getMessage()); + } } } diff --git a/src/tcp/src/Packer/SimpleTokenPacker.php b/src/tcp/src/Packer/SimpleTokenPacker.php index fffa0c35e..59d334bea 100644 --- a/src/tcp/src/Packer/SimpleTokenPacker.php +++ b/src/tcp/src/Packer/SimpleTokenPacker.php @@ -89,7 +89,7 @@ public function encodeResponse(Response $response): string return $content; } - // Error, output error message + // Has error, output error message if ($response->isFail()) { return $response->getMsg(); } diff --git a/src/tcp/src/Response.php b/src/tcp/src/Response.php index a19c605d5..252ccc0d3 100644 --- a/src/tcp/src/Response.php +++ b/src/tcp/src/Response.php @@ -96,6 +96,11 @@ public function isFail(): bool */ public function isEmpty(): bool { + // Has code and error message + if ($this->isFail()) { + return false; + } + return $this->content === '' && $this->data === null; } diff --git a/src/tcp/test/unit/ResponseTest.php b/src/tcp/test/unit/ResponseTest.php index b529f2e8c..269d02403 100644 --- a/src/tcp/test/unit/ResponseTest.php +++ b/src/tcp/test/unit/ResponseTest.php @@ -40,4 +40,17 @@ public function testBasic(): void $this->assertSame(['array data'], $resp->getData()); $this->assertSame('["array data"]', $resp->getDataString()); } + + public function testEmpty(): void + { + $w = new Response(); + + $this->assertTrue($w->isEmpty()); + + $w->setContent('hi'); + $this->assertFalse($w->isEmpty()); + $w->setCode(23); + $w->setContent(''); + $this->assertFalse($w->isEmpty()); + } } diff --git a/src/websocket-server/src/Message/Response.php b/src/websocket-server/src/Message/Response.php index 1035d2cfd..f7a2645f9 100644 --- a/src/websocket-server/src/Message/Response.php +++ b/src/websocket-server/src/Message/Response.php @@ -183,23 +183,28 @@ public function send(Connection $conn = null): int return 0; } - // Fix: No response data + // Mark has sent + $this->sent = true; + + // Fix: empty response data if ($this->isEmpty()) { + CLog::warning('cannot send empty response to websocket client'); return 0; } /** @noinspection CallableParameterUseCaseInTypeContextInspection */ - $conn = $conn ?: Session::mustGet(); - $server = $conn->getServer(); - $sender = $this->sender === $this->fd ? 0 : $this->sender; + $conn = $conn ?: Session::current(); - $pageSize = $this->pageSize; - $content = $this->formatContent($conn); + // Build response content + $content = $this->formatContent($conn); + $server = $conn->getServer(); + $sender = $this->sender === $this->fd ? 0 : $this->sender; // Trigger event before push message content to client Swoft::trigger(WsServerEvent::MESSAGE_PUSH, $server, $content, $this); // To all users + $pageSize = $this->pageSize; if ($this->sendToAll) { return $server->sendToAll($content, $sender, $pageSize, $this->opcode); } @@ -242,7 +247,6 @@ protected function formatContent(Connection $conn): string /** @var WsMessageContext $context */ $context = Context::get(true); - $parser = $conn->getParser(); $message = null; $cmdId = $context->getMessage()->getCmd(); @@ -262,7 +266,9 @@ protected function formatContent(Connection $conn): string $message = Message::new($cmdId, $this->data, $this->ext); } + // Encode message if ($message) { + $parser = $conn->getParser(); $content = $parser->encode($message); } @@ -274,7 +280,7 @@ protected function formatContent(Connection $conn): string */ public function isEmpty(): bool { - return $this->content === '' && $this->data === null; + return $this->content === '' && $this->data === null && !$this->ext; } /** @@ -299,6 +305,19 @@ public function setFd(int $fd): self return $this; } + /** + * Set data. override raw method. + * + * @param mixed $data + * + * @return $this|ResponseInterface + */ + public function setData($data): ResponseInterface + { + $this->data = $data; + return $this; + } + /** * @return int */ @@ -387,17 +406,6 @@ public function setContent(string $content): ResponseInterface return $this; } - /** - * @param mixed $data - * - * @return ResponseInterface|self - */ - public function setData($data): ResponseInterface - { - $this->data = $data; - return $this; - } - /** * @return int */ diff --git a/src/websocket-server/test/unit/Message/ResponseTest.php b/src/websocket-server/test/unit/Message/ResponseTest.php index 1481353c5..895aa7d60 100644 --- a/src/websocket-server/test/unit/Message/ResponseTest.php +++ b/src/websocket-server/test/unit/Message/ResponseTest.php @@ -45,5 +45,9 @@ public function testBasic(): void $this->assertTrue($w->isEmpty()); $w->setContent('hi'); $this->assertFalse($w->isEmpty()); + $w->setContent('')->setExt(['a']); + $this->assertFalse($w->isEmpty()); + $w->setContent('')->setExt([])->setData(['a']); + $this->assertFalse($w->isEmpty()); } }