Merge pull request #562 from limingxinleo/1.0-merge

Merge 1.0 to master.
This commit is contained in:
李铭昕 2019-09-11 12:11:33 +08:00 committed by GitHub
commit 9cae4cdfbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 169 additions and 77 deletions

View File

@ -45,7 +45,31 @@ return ApplicationContext::setContainer($container);
- [#448](https://github.com/hyperf-cloud/hyperf/pull/448) Fixed TCP Server does not works when HTTP Server or WebSocket Server exists.
# v1.0.15 - TBD
# v1.0.16 - TBD
# v1.0.15 - 2019-09-11
## Fixed
- [#534](https://github.com/hyperf-cloud/hyperf/pull/534) Fixed Guzzle HTTP Client does not handle the response status is equal to `-3`;
- [#541](https://github.com/hyperf-cloud/hyperf/pull/541) Fixed bug grpc client cannot be set correctly.
- [#542](https://github.com/hyperf-cloud/hyperf/pull/542) Fixed `Hyperf\Grpc\Parser::parseResponse` returns a non-standard error code for grpc.
- [#551](https://github.com/hyperf-cloud/hyperf/pull/551) Fixed infinite loop in grpc client when the server closed the connection.
- [#558](https://github.com/hyperf-cloud/hyperf/pull/558) Fixed UDP Server does not works.
## Deleted
- [#545](https://github.com/hyperf-cloud/hyperf/pull/545) Deleted useless static methods `restoring` and `restored` of trait SoftDeletes.
## Optimized
- [#549](https://github.com/hyperf-cloud/hyperf/pull/549) Optimized `read` and `write` of `Hyperf\Amqp\Connection\SwooleIO`.
- [#559](https://github.com/hyperf-cloud/hyperf/pull/559) Optimized `redirect ` of `Hyperf\HttpServer\Response`.
- [#560](https://github.com/hyperf-cloud/hyperf/pull/560) Optimized class `Hyperf\WebSocketServer\CoreMiddleware`.
## Deprecated
- [#558](https://github.com/hyperf-cloud/hyperf/pull/558) Marked `Hyperf\Server\ServerInterface::SERVER_TCP` as deprecated, will be removed in `v1.1`.
# v1.0.14 - 2019-09-05

View File

@ -101,7 +101,7 @@ return [
'servers' => [
[
'name' => 'jsonrpc',
'type' => Server::SERVER_TCP,
'type' => Server::SERVER_BASE,
'host' => '0.0.0.0',
'port' => 9503,
'sock_type' => SWOOLE_SOCK_TCP,

View File

@ -158,7 +158,6 @@ class SwooleIO extends AbstractIO
public function read($len)
{
$this->check_heartbeat();
$count = 0;
do {
if ($len <= strlen($this->buffer)) {
$data = substr($this->buffer, 0, $len);
@ -178,10 +177,7 @@ class SwooleIO extends AbstractIO
}
if ($read_buffer === '') {
if (5 < $count++) {
throw new AMQPRuntimeException('The receiving data is empty, errno=' . $this->sock->errCode);
}
continue;
throw new AMQPRuntimeException('Connection is closed.');
}
$this->buffer .= $read_buffer;
@ -192,8 +188,8 @@ class SwooleIO extends AbstractIO
/**
* @param string $data
* @throws AMQPRuntimeException
* @throws \PhpAmqpLib\Exception\AMQPTimeoutException
* @throws AMQPRuntimeException
* @return mixed|void
*/
public function write($data)
@ -204,10 +200,6 @@ class SwooleIO extends AbstractIO
throw new AMQPRuntimeException('Error sending data');
}
if ($buffer === 0 && ! $this->sock->connected) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}
$this->lastWrite = microtime(true);
}

View File

@ -89,26 +89,6 @@ trait SoftDeletes
return ! is_null($this->{$this->getDeletedAtColumn()});
}
/**
* Register a restoring model event with the dispatcher.
*
* @param \Closure|string $callback
*/
public static function restoring($callback)
{
static::registerModelEvent('restoring', $callback);
}
/**
* Register a restored model event with the dispatcher.
*
* @param \Closure|string $callback
*/
public static function restored($callback)
{
static::registerModelEvent('restored', $callback);
}
/**
* Determine if the model is currently force deleting.
*

View File

@ -14,6 +14,8 @@ namespace Hyperf\GrpcClient;
use Google\Protobuf\Internal\Message;
use Hyperf\Grpc\Parser;
use Hyperf\Grpc\StatusCode;
use Hyperf\GrpcClient\Exception\GrpcClientException;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\ChannelPool;
use InvalidArgumentException;
@ -36,7 +38,7 @@ class BaseClient
if (! ($options['client'] instanceof GrpcClient)) {
throw new InvalidArgumentException('Parameter client have to instanceof Hyperf\GrpcClient\GrpcClient');
}
$this->setClient($options['client']);
$this->grpcClient = $options['client'];
} else {
$this->grpcClient = new GrpcClient(ApplicationContext::getContainer()->get(ChannelPool::class));
$this->grpcClient->set($hostname, $options);
@ -75,6 +77,7 @@ class BaseClient
* @param array $metadata A metadata map to send to the server
* (optional)
* @param array $options An array of options (optional)
* @throws GrpcClientException The client should not be used after this exception
* @return []
*/
protected function simpleRequest(
@ -83,6 +86,10 @@ class BaseClient
$deserialize
) {
$streamId = $this->send($this->buildRequest($method, $argument));
if ($streamId === 0) {
// The client should not be used after this exception
throw new GrpcClientException('Failed to send the request to server', StatusCode::INTERNAL);
}
return Parser::parseResponse($this->recv($streamId), $deserialize);
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
*/
namespace Hyperf\GrpcClient\Exception;
class GrpcClientException extends \RuntimeException
{
}

View File

@ -168,6 +168,10 @@ class GrpcClient
$shouldKill = true;
} else {
$shouldKill = ! $this->getHttpClient()->connect();
if ($shouldKill) {
// Set `connected` of http client to `false`
$this->getHttpClient()->close();
}
}
// Clear the receive channel map
if (! empty($this->recvChannelMap)) {
@ -325,7 +329,7 @@ class GrpcClient
}
} else {
// If no response, then close all the connection.
if (! $this->isConnected() && $this->closeRecv()) {
if ($this->closeRecv()) {
break;
}
}

View File

@ -78,7 +78,9 @@ class Parser
return ['No response', self::GRPC_ERROR_NO_RESPONSE, $response];
}
if ($response->statusCode !== 200) {
return ['Http status Error', $response->errCode ?: $response->statusCode, $response];
$message = $response->headers['grpc-message'] ?? 'Http status Error';
$code = $response->headers['grpc-status'] ?? ($response->errCode ?: $response->statusCode);
return [$message, (int) $code, $response];
}
$grpc_status = (int) ($response->headers['grpc-status'] ?? 0);
if ($grpc_status !== 0) {

View File

@ -190,13 +190,18 @@ class CoroutineHandler
'errCode' => $errCode,
];
if ($statusCode === -1) {
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_CONNECT_FAILED) {
return new ConnectException(sprintf('Connection failed, errCode=%s', $errCode), $request, null, $ctx);
}
if ($statusCode === -2) {
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_REQUEST_TIMEOUT) {
return new RequestException(sprintf('Request timed out, errCode=%s', $errCode), $request, null, null, $ctx);
}
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_SERVER_RESET) {
return new RequestException('Server reset', $request, null, null, $ctx);
}
return true;
}
}

View File

@ -147,13 +147,18 @@ class CoroutineHandler
$statusCode = $client->statusCode;
$errCode = $client->errCode;
if ($statusCode === -1) {
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_CONNECT_FAILED) {
return new RingException(sprintf('Connection timed out errCode=%s', $errCode));
}
if ($statusCode === -2) {
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_REQUEST_TIMEOUT) {
return new RingException('Request timed out');
}
if ($statusCode === SWOOLE_HTTP_CLIENT_ESTATUS_SERVER_RESET) {
return new RingException('Server reset');
}
return true;
}

View File

@ -14,12 +14,15 @@ namespace HyperfTest\Guzzle\Cases;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\Request;
use Hyperf\Guzzle\CoroutineHandler;
use HyperfTest\Guzzle\Stub\CoroutineHandlerStub;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestInterface;
use Swoole\Coroutine\Http\Client as SwooleHttpClient;
/**
* @internal
@ -252,6 +255,31 @@ class CoroutineHandlerTest extends TestCase
$this->assertEquals('Basic ' . base64_encode('username:password'), $json['headers']['Authorization']);
}
public function testStatusCode()
{
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -1;
$request = \Mockery::mock(RequestInterface::class);
$handler = new CoroutineHandlerStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(ConnectException::class, $ex);
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -2;
$request = \Mockery::mock(RequestInterface::class);
$handler = new CoroutineHandlerStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(RequestException::class, $ex);
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -3;
$request = \Mockery::mock(RequestInterface::class);
$handler = new CoroutineHandlerStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(RequestException::class, $ex);
$this->assertSame('Server reset', $ex->getMessage());
}
protected function getHandler($options = [])
{
return new CoroutineHandler($options);

View File

@ -12,9 +12,12 @@ declare(strict_types=1);
namespace HyerfTest\Guzzle\Cases;
use GuzzleHttp\Ring\Exception\RingException;
use Hyperf\Guzzle\RingPHP\CoroutineHandler;
use HyperfTest\Guzzle\Stub\RingPHPCoroutineHanderStub;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\RequestInterface;
use Swoole\Coroutine\Http\Client as SwooleHttpClient;
/**
* @internal
@ -80,4 +83,30 @@ class RingPHPCoroutineHandlerTest extends TestCase
$this->assertEquals('/echo?a=1&b=2', $json['uri']);
}
public function testStatusCode()
{
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -1;
$request = \Mockery::mock(RequestInterface::class);
$handler = new RingPHPCoroutineHanderStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(RingException::class, $ex);
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -2;
$request = \Mockery::mock(RequestInterface::class);
$handler = new RingPHPCoroutineHanderStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(RingException::class, $ex);
$this->assertSame('Request timed out', $ex->getMessage());
$client = new SwooleHttpClient('127.0.0.1', 80);
$client->statusCode = -3;
$request = \Mockery::mock(RequestInterface::class);
$handler = new RingPHPCoroutineHanderStub();
$ex = $handler->checkStatusCode($client, $request);
$this->assertInstanceOf(RingException::class, $ex);
$this->assertSame('Server reset', $ex->getMessage());
}
}

View File

@ -17,6 +17,11 @@ use Swoole\Coroutine\Http\Client;
class CoroutineHandlerStub extends CoroutineHandler
{
public function checkStatusCode(Client $client, $request)
{
return parent::checkStatusCode($client, $request);
}
protected function execute(Client $client, $path)
{
$client->body = json_encode([

View File

@ -17,6 +17,11 @@ use Swoole\Coroutine\Http\Client;
class RingPHPCoroutineHanderStub extends CoroutineHandler
{
public function checkStatusCode($client, $request)
{
return parent::checkStatusCode($client, $request);
}
protected function execute(Client $client, $path)
{
$client->body = json_encode([

View File

@ -122,7 +122,7 @@ class Response implements PsrResponseInterface, ResponseInterface
$uri = $request->getUri();
$host = $uri->getAuthority();
// Build the url by $schema and host.
return $schema . '://' . $host . '/' . $toUrl;
return $schema . '://' . $host . (Str::startsWith($toUrl, '/') ? $toUrl : '/' . $toUrl);
});
return $this->getResponse()->withStatus($status)->withAddedHeader('Location', $toUrl);
}

View File

@ -14,6 +14,8 @@ namespace HyperfTest\HttpServer;
use Hyperf\HttpMessage\Cookie\Cookie;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpMessage\Uri\Uri;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\HttpServer\Response;
use Hyperf\Utils\ApplicationContext;
@ -41,6 +43,9 @@ class ResponseTest extends TestCase
public function testRedirect()
{
$container = Mockery::mock(ContainerInterface::class);
$request = Mockery::mock(RequestInterface::class);
$request->shouldReceive('getUri')->andReturn(new Uri('http://127.0.0.1:9501'));
$container->shouldReceive('get')->with(RequestInterface::class)->andReturn($request);
ApplicationContext::setContainer($container);
$psrResponse = new \Hyperf\HttpMessage\Base\Response();
@ -57,6 +62,16 @@ class ResponseTest extends TestCase
$this->assertSame(302, $res->getStatusCode());
$this->assertSame('http://www.baidu.com', $res->getHeaderLine('Location'));
$response = new Response();
$res = $response->redirect('/index');
$this->assertSame(302, $res->getStatusCode());
$this->assertSame('http://127.0.0.1:9501/index', $res->getHeaderLine('Location'));
$response = new Response();
$res = $response->redirect('index');
$this->assertSame(302, $res->getStatusCode());
$this->assertSame('http://127.0.0.1:9501/index', $res->getHeaderLine('Location'));
}
public function testToXml()

View File

@ -18,6 +18,7 @@ use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Framework\Event\AfterWorkerStart;
use Hyperf\Server\Server;
use Hyperf\Server\ServerManager;
use Swoole\Server\Port;
/**
* @Listener
@ -52,11 +53,12 @@ class AfterWorkerStartListener implements ListenerInterface
{
/** @var AfterWorkerStart $event */
if ($event->workerId === 0) {
/** @var Port $server */
foreach (ServerManager::list() as $name => [$type, $server]) {
$listen = $server->host . ':' . $server->port;
$type = value(function () use ($type) {
switch ($type) {
case Server::SERVER_TCP:
case Server::SERVER_BASE:
return 'TCP';
break;
case Server::SERVER_WEBSOCKET:

View File

@ -58,6 +58,7 @@ class Port
isset($config['type']) && $port->setType($config['type']);
isset($config['host']) && $port->setHost($config['host']);
isset($config['port']) && $port->setPort($config['port']);
isset($config['sock_type']) && $port->setSockType($config['sock_type']);
isset($config['callbacks']) && $port->setCallbacks($config['callbacks']);
isset($config['settings']) && $port->setSettings($config['settings']);

View File

@ -172,7 +172,7 @@ class Server implements ServerInterface
return new SwooleHttpServer($host, $port, $mode, $sockType);
case ServerInterface::SERVER_WEBSOCKET:
return new SwooleWebSocketServer($host, $port, $mode, $sockType);
case ServerInterface::SERVER_TCP:
case ServerInterface::SERVER_BASE:
return new SwooleServer($host, $port, $mode, $sockType);
}

View File

@ -22,7 +22,12 @@ interface ServerInterface
const SERVER_WEBSOCKET = 2;
const SERVER_TCP = 3;
const SERVER_BASE = 3;
/**
* @deprecated v1.1
*/
const SERVER_TCP = self::SERVER_BASE;
public function __construct(ContainerInterface $container, LoggerInterface $logger, EventDispatcherInterface $dispatcher);

View File

@ -12,50 +12,16 @@ declare(strict_types=1);
namespace Hyperf\WebSocketServer;
use FastRoute\Dispatcher;
use Hyperf\HttpServer\CoreMiddleware as HttpCoreMiddleware;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Server\Exception\ServerException;
use Hyperf\Utils\Context;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\WebSocketServer\Exception\WebSocketHandeShakeException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CoreMiddleware extends HttpCoreMiddleware
{
/**
* Process an incoming server request and return a response, optionally delegating
* response creation to a handler.
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
/** @var Dispatched $dispatched */
$dispatched = $request->getAttribute(Dispatched::class);
if (! $dispatched instanceof Dispatched) {
throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class));
}
switch ($dispatched->status) {
case Dispatcher::NOT_FOUND:
$response = $this->handleNotFound($request);
break;
case Dispatcher::METHOD_NOT_ALLOWED:
$response = $this->handleMethodNotAllowed($dispatched->params, $request);
break;
case Dispatcher::FOUND:
$response = $this->handleFound($dispatched, $request);
break;
}
if (! $response instanceof ResponseInterface) {
$response = $this->transferToResponse($response, $request);
}
return $response->withAddedHeader('Server', 'Hyperf');
}
/**
* Handle the response when found.
*