2020-09-11 19:37:32 +08:00
|
|
|
<?php
|
2020-10-29 18:17:25 +08:00
|
|
|
declare(strict_types=1);
|
2020-09-11 19:37:32 +08:00
|
|
|
|
|
|
|
|
namespace HttpServer\Client;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Exception;
|
2020-11-01 05:10:38 +08:00
|
|
|
use HttpServer\Http\Context;
|
2020-09-11 19:37:32 +08:00
|
|
|
use Snowflake\Abstracts\Component;
|
2020-12-24 11:12:23 +08:00
|
|
|
use Snowflake\Core\Json;
|
2021-03-31 11:05:21 +08:00
|
|
|
use Snowflake\Core\Xml;
|
2021-03-31 01:33:41 +08:00
|
|
|
use Snowflake\Snowflake;
|
2020-09-11 19:37:32 +08:00
|
|
|
use Swoole\Http2\Request;
|
2020-11-14 04:46:52 +08:00
|
|
|
use Swoole\Coroutine\Http2\Client as H2Client;
|
2021-03-31 11:03:30 +08:00
|
|
|
use Swoole\Http2\Response;
|
2020-09-11 19:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class Http2
|
|
|
|
|
* @package HttpServer\Client
|
|
|
|
|
*/
|
|
|
|
|
class Http2 extends Component
|
|
|
|
|
{
|
|
|
|
|
|
2021-03-31 01:33:41 +08:00
|
|
|
|
2021-04-01 11:34:47 +08:00
|
|
|
/**
|
|
|
|
|
* @param bool $isRecv
|
|
|
|
|
* @return Http2
|
|
|
|
|
*/
|
|
|
|
|
public function setIsRecv(bool $isRecv): static
|
|
|
|
|
{
|
|
|
|
|
Context::setContext('http2isRecv', $isRecv);
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-03-31 01:33:41 +08:00
|
|
|
/**
|
|
|
|
|
* @param array $headers
|
2021-04-01 11:34:47 +08:00
|
|
|
* @return Http2
|
2021-03-31 01:33:41 +08:00
|
|
|
*/
|
2021-04-01 11:34:47 +08:00
|
|
|
public function setHeader(array $headers): static
|
2021-03-31 01:33:41 +08:00
|
|
|
{
|
|
|
|
|
Context::setContext('http2Headers', $headers);
|
2021-04-01 11:34:47 +08:00
|
|
|
return $this;
|
2021-03-31 01:33:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-11 19:37:32 +08:00
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
2020-12-17 14:09:14 +08:00
|
|
|
* @return Result
|
2020-09-11 19:37:32 +08:00
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2020-12-17 14:09:14 +08:00
|
|
|
public function get($domain, $path, $params = [], $timeout = -1): Result
|
2020-09-11 19:37:32 +08:00
|
|
|
{
|
2021-03-31 01:33:41 +08:00
|
|
|
$request = $this->dispatch($domain, $path, 'GET', $params, $timeout);
|
|
|
|
|
|
|
|
|
|
return new Result(['code' => 0, 'data' => $request]);
|
2020-09-11 19:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
2020-12-17 14:09:14 +08:00
|
|
|
* @return Result
|
2020-09-11 19:37:32 +08:00
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2020-12-17 14:09:14 +08:00
|
|
|
public function post($domain, $path, $params = [], $timeout = -1): Result
|
2020-09-11 19:37:32 +08:00
|
|
|
{
|
2021-03-31 01:33:41 +08:00
|
|
|
$request = $this->dispatch($domain, $path, 'POST', $params, $timeout);
|
|
|
|
|
|
|
|
|
|
return new Result(['code' => 0, 'data' => $request]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
|
|
|
|
* @return Result
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function upload($domain, $path, $params = [], $timeout = -1): Result
|
|
|
|
|
{
|
|
|
|
|
$request = $this->dispatch($domain, $path, 'POST', $params, $timeout, true);
|
|
|
|
|
|
|
|
|
|
return new Result(['code' => 0, 'data' => $request]);
|
2020-09-11 19:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-12 02:53:27 +08:00
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
2020-12-17 14:09:14 +08:00
|
|
|
* @return Result
|
2020-09-12 02:53:27 +08:00
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2020-12-17 14:09:14 +08:00
|
|
|
public function delete($domain, $path, $params = [], $timeout = -1): Result
|
2020-09-12 02:53:27 +08:00
|
|
|
{
|
2021-03-31 01:33:41 +08:00
|
|
|
$request = $this->dispatch($domain, $path, 'DELETE', $params, $timeout);
|
|
|
|
|
|
|
|
|
|
return new Result(['code' => 0, 'data' => $request]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param $method
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
|
|
|
|
* @param bool $isUpload
|
|
|
|
|
* @return mixed
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
private function dispatch($domain, $path, $method, $params = [], $timeout = -1, $isUpload = false): mixed
|
|
|
|
|
{
|
2021-03-31 11:01:50 +08:00
|
|
|
$ssl = false;
|
|
|
|
|
if (str_starts_with($domain, 'https://')) {
|
|
|
|
|
$domain = str_replace('https://', '', $domain);
|
|
|
|
|
$ssl = true;
|
|
|
|
|
} else if (str_starts_with($domain, 'http://')) {
|
|
|
|
|
$domain = str_replace('http://', '', $domain);
|
|
|
|
|
}
|
2021-03-31 01:33:41 +08:00
|
|
|
|
2021-03-31 11:01:50 +08:00
|
|
|
$client = $this->getClient($domain, $ssl, $timeout);
|
2021-03-31 01:33:41 +08:00
|
|
|
$request = $this->getRequest($domain, $path, $method, $params, $isUpload);
|
|
|
|
|
|
|
|
|
|
$client->send($request);
|
|
|
|
|
defer(function () use ($domain, $path, $client, $request, $method) {
|
|
|
|
|
$pool = Snowflake::app()->getChannel();
|
|
|
|
|
$pool->push($request, 'request.' . $method . $path);
|
|
|
|
|
$pool->push($client, 'http2.' . $domain);
|
|
|
|
|
});
|
2021-04-01 11:34:47 +08:00
|
|
|
if (Context::getContext('http2isRecv') === false) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return $this->recv($client);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 11:03:30 +08:00
|
|
|
|
2021-04-01 11:34:47 +08:00
|
|
|
/**
|
|
|
|
|
* @param $client
|
|
|
|
|
* @return mixed
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
private function recv($client): mixed
|
|
|
|
|
{
|
2021-03-31 11:03:30 +08:00
|
|
|
/** @var Response $response */
|
|
|
|
|
$response = $client->recv();
|
2021-03-31 11:28:03 +08:00
|
|
|
if ($response === false || $response->statusCode > 200) {
|
2021-03-31 14:12:07 +08:00
|
|
|
throw new Exception($client->errMsg, $client->errCode);
|
2021-03-31 11:03:30 +08:00
|
|
|
}
|
2021-03-31 11:05:21 +08:00
|
|
|
$header = $response->headers['content-type'];
|
|
|
|
|
if (str_starts_with($header, 'application/json;')) {
|
|
|
|
|
return Json::decode($response->data);
|
|
|
|
|
} else if (str_starts_with($header, 'application/xml;')) {
|
|
|
|
|
return Xml::toArray($response->data);
|
|
|
|
|
} else {
|
|
|
|
|
return $response->data;
|
|
|
|
|
}
|
2020-09-12 02:53:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param array $params
|
|
|
|
|
* @param int $timeout
|
|
|
|
|
* @return mixed
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2020-12-17 14:09:14 +08:00
|
|
|
public function put($domain, $path, $params = [], $timeout = -1): Result
|
2020-09-12 02:53:27 +08:00
|
|
|
{
|
2021-03-31 01:33:41 +08:00
|
|
|
$request = $this->dispatch($domain, $path, 'PUT', $params, $timeout);
|
|
|
|
|
|
|
|
|
|
return new Result(['code' => 0, 'data' => $request]);
|
2020-09-12 02:53:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-09-11 19:37:32 +08:00
|
|
|
/**
|
|
|
|
|
* @param $domain
|
|
|
|
|
* @param $path
|
|
|
|
|
* @param $method
|
|
|
|
|
* @param $params
|
2021-03-31 01:33:41 +08:00
|
|
|
* @param bool $isUpload
|
2020-09-11 19:37:32 +08:00
|
|
|
* @return Request
|
2021-03-31 11:01:50 +08:00
|
|
|
* @throws Exception
|
2020-09-11 19:37:32 +08:00
|
|
|
*/
|
2021-03-31 01:33:41 +08:00
|
|
|
public function getRequest($domain, $path, $method, $params, $isUpload = false): Request
|
2020-09-11 19:37:32 +08:00
|
|
|
{
|
2021-03-31 10:51:40 +08:00
|
|
|
if (!str_starts_with($path, '/')) {
|
|
|
|
|
$path = '/' . $path;
|
|
|
|
|
}
|
2021-03-31 01:33:41 +08:00
|
|
|
$channel = Snowflake::app()->getChannel();
|
|
|
|
|
$request = $channel->pop('request.' . $method . $path, function () use ($path, $method) {
|
|
|
|
|
$request = new Request();
|
|
|
|
|
$request->method = $method;
|
|
|
|
|
$request->path = $path;
|
|
|
|
|
return $request;
|
|
|
|
|
});
|
|
|
|
|
if ($method === 'GET') {
|
|
|
|
|
$request->path .= '?' . http_build_query($params);
|
2020-09-11 19:37:32 +08:00
|
|
|
} else {
|
2021-03-31 01:33:41 +08:00
|
|
|
$request->data = !is_string($params) && !$isUpload ? Json::encode($params) : $params;
|
|
|
|
|
}
|
2021-03-31 11:30:23 +08:00
|
|
|
$request->headers = Context::getContext('http2Headers');
|
2021-03-31 01:33:41 +08:00
|
|
|
return $request;
|
2020-09-11 19:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $domain
|
2021-03-31 11:01:50 +08:00
|
|
|
* @param bool $isSsl
|
2020-09-11 19:37:32 +08:00
|
|
|
* @param int $timeout
|
|
|
|
|
* @return H2Client
|
2021-03-31 11:13:23 +08:00
|
|
|
* @throws Exception
|
2020-09-11 19:37:32 +08:00
|
|
|
*/
|
2021-03-31 11:01:50 +08:00
|
|
|
private function getClient($domain, $isSsl = false, $timeout = -1): H2Client
|
2020-09-11 19:37:32 +08:00
|
|
|
{
|
2021-03-31 01:33:41 +08:00
|
|
|
$pool = Snowflake::app()->getChannel();
|
|
|
|
|
/** @var H2Client $client */
|
2021-03-31 11:01:50 +08:00
|
|
|
$client = $pool->pop('http2.' . $domain, function () use ($domain, $isSsl, $timeout) {
|
2021-03-31 10:51:40 +08:00
|
|
|
$domain = rtrim($domain, '/');
|
2021-03-31 11:01:50 +08:00
|
|
|
if (str_contains($domain, ':')) {
|
|
|
|
|
[$domain, $port] = explode(':', $domain);
|
|
|
|
|
} else if ($isSsl === true) {
|
|
|
|
|
$port = 443;
|
2021-03-31 10:51:40 +08:00
|
|
|
} else {
|
2021-03-31 11:01:50 +08:00
|
|
|
$port = 80;
|
2021-03-31 10:51:40 +08:00
|
|
|
}
|
2021-03-31 11:08:58 +08:00
|
|
|
$client = new H2Client($domain, (int)$port, $isSsl);
|
2021-03-31 01:33:41 +08:00
|
|
|
$client->set([
|
|
|
|
|
'timeout' => $timeout,
|
|
|
|
|
'ssl_host_name' => $domain
|
|
|
|
|
]);
|
|
|
|
|
return $client;
|
|
|
|
|
});
|
2021-03-31 16:02:08 +08:00
|
|
|
if ($client->connected && $client->ping()) {
|
|
|
|
|
return $client;
|
|
|
|
|
}
|
|
|
|
|
if (!$client->connect()) {
|
2021-03-31 11:15:34 +08:00
|
|
|
throw new Exception($client->errMsg, $client->errCode);
|
2020-09-11 19:37:32 +08:00
|
|
|
}
|
2021-03-31 01:33:41 +08:00
|
|
|
return $client;
|
2020-09-11 19:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|