This commit is contained in:
2022-09-23 18:55:46 +08:00
parent c190c749f4
commit c01dc5f41a
14 changed files with 239 additions and 331 deletions
+69
View File
@@ -0,0 +1,69 @@
<?php
namespace Kiri\Rpc;
use JetBrains\PhpStorm\ArrayShape;
use Kiri\Annotation\Inject;
use Kiri\Core\Json;
use Kiri\Core\Number;
abstract class AbstractRpcClient
{
public string $service = '';
public string $version = '';
/**
* @var JsonRpcTransporterInterface
*/
#[Inject(JsonRpcTransporterInterface::class)]
private JsonRpcTransporterInterface $transporter;
/**
* @param JsonRpcTransporterInterface $transporter
*/
public function setTransporter(JsonRpcTransporterInterface $transporter): void
{
$this->transporter = $transporter;
}
/**
* @return string
*/
public function getService(): string
{
if (empty($this->service)) {
return get_called_class();
}
return $this->service;
}
/**
* @param string $method
* @param ...$args
* @return string|bool
*/
protected function send(string $method, ...$args): string|bool
{
$result = $this->transporter->push(Json::encode([
'jsonrpc' => $this->version,
'service' => $this->getService(),
'method' => $method,
'params' => $args,
'id' => Number::create(time())
]), $this->getService());
if (is_string($result)) {
return json_decode($result, true);
} else {
return $result;
}
}
}
-41
View File
@@ -1,41 +0,0 @@
<?php
namespace Kiri\Rpc\Annotation;
use Kiri;
use Kiri\Abstracts\Config;
use Kiri\Annotation\AbstractAttribute;
use Kiri\Core\Network;
use Kiri\Exception\ConfigException;
use Kiri\Message\Handler\Router;
use Kiri\Rpc\RpcManager;
use ReflectionException;
#[\Attribute(\Attribute::TARGET_CLASS)] class JsonRpc extends AbstractAttribute
{
private string $uniqueId = '';
/**
* @param string $service
*/
public function __construct(public string $service)
{
}
/**
* @param mixed $class
* @param mixed|string $method
* @return mixed
*/
public function execute(mixed $class, mixed $method = ''): bool
{
$manager = Kiri::getDi()->get(RpcManager::class);
return $manager->add($this->service, $class);
}
}
+1 -1
View File
@@ -51,7 +51,7 @@ class ClientPool extends Component
* @return void
* @throws Exception
*/
public function onBeforeShutdown()
public function onBeforeShutdown(): void
{
foreach ($this->names as $name) {
$this->getPool()->clean($name);
+1 -1
View File
@@ -50,7 +50,7 @@ class Consul extends Component
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function deregister()
public function deregister(): void
{
if (env('environmental') != Kiri::WORKER && env('environmental_workerId') != 0) {
return;
-161
View File
@@ -1,161 +0,0 @@
<?php
namespace Kiri\Rpc;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Kiri\Message\ServerRequest;
use Kiri\Message\Stream;
use Kiri\Core\Number;
use Kiri;
use Kiri\Pool\Pool;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Kiri\Annotation\Inject;
/**
*
*/
abstract class JsonRpcConsumers implements OnRpcConsumerInterface
{
/**
* @var Pool
*/
public Pool $pool;
/**
* @var RpcManager
*/
#[Inject(RpcManager::class)]
public RpcManager $manager;
/**
* @var RpcClientInterface
*/
#[Inject(RpcClientInterface::class)]
public RpcClientInterface $client;
protected string $name = '';
/**
* @param string $method
* @param mixed $data
* @param string $version
* @throws Exception
* @throws ClientExceptionInterface
*/
public function notify(string $method, mixed $data, string $version = '2.0'): void
{
$this->client->withConfig($this->get_consul($this->name))->sendRequest(
$this->requestBody([
'jsonrpc' => $version,
'service' => str_starts_with($this->name, '/') ? $this->name : '/' . $this->name,
'method' => $method,
'params' => $data,
])
);
}
/**
* @param array $data
* @return ServerRequestInterface
*/
private function requestBody(array $data): ServerRequestInterface
{
$server = Kiri::getDi()->get(ServerRequest::class);
return $server->withBody(new Stream(json_encode($data)));
}
/**
* @param string $method
* @param mixed $data
* @param string $version
* @param string $id
* @return mixed
* @throws Exception
* @throws ClientExceptionInterface
*/
public function get(string $method, mixed $data, string $version = '2.0', string $id = ''): ResponseInterface
{
if (empty($id)) $id = Number::create(time());
return $this->client->withConfig($this->get_consul($this->name))->sendRequest(
$this->requestBody([
'jsonrpc' => $version,
'service' => str_starts_with($this->name, '/') ? $this->name : '/' . $this->name,
'method' => $method,
'params' => $data,
'id' => $id
])
);
}
/**
* @param array $data
* @return mixed
* @throws ClientExceptionInterface
* @throws Exception
*/
public function batch(array $data): mixed
{
return $this->client->withConfig($this->get_consul($this->name))->sendRequest(
$this->requestBody($data)
);
}
/**
* @param $service
* @return array
* @throws RpcServiceException|\ReflectionException
* @throws Exception
*/
#[ArrayShape(['Address' => "mixed", 'Port' => "mixed"])]
private function get_consul($service): array
{
if (empty($service)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
$sf = $this->manager->getServices($service);
if (empty($sf) || !is_array($sf)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
return $this->_loadRand($sf);
}
/**
* @param $services
* @return array
*/
#[ArrayShape(['Address' => "mixed", 'Port' => "mixed"])]
private function _loadRand($services): array
{
$array = [];
foreach ($services as $value) {
$value['Weight'] = $value['Weights']['Passing'];
$array[] = $value;
}
if (count($array) < 2) {
$luck = $array[0];
} else {
$luck = Luckdraw::luck($array, 'Weight');
}
return [
'Address' => $luck['TaggedAddresses']['wan_ipv4']['Address'],
'Port' => $luck['TaggedAddresses']['wan_ipv4']['Port']
];
}
}
+8 -19
View File
@@ -12,7 +12,7 @@ use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Swoole\Coroutine\Client;
class JsonRpcPoolTransporter implements RpcClientInterface
class JsonRpcPoolTransporter implements JsonRpcTransporterInterface
{
@@ -23,32 +23,21 @@ class JsonRpcPoolTransporter implements RpcClientInterface
public ClientPool $pool;
const POOL_NAME = 'rpc.client.pool';
/**
* @param string $content
* @param string $service
* @return string|bool
* @throws ConfigException|RpcServiceException
*/
public function init()
public function push(string $content, string $service): string|bool
{
}
/**
* @param RequestInterface $request
* @return ResponseInterface
* @throws Exception
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
$content = $request->getBody()->getContents();
$client = $this->getClient();
$client = $this->get_consul($service)->getClient();
$response = $this->request($client, $content);
$this->pool->push($client, $this->config['Address'], $this->config['Port']);
return (new Response())->withBody(new Stream($response));
return $response;
}
+12 -14
View File
@@ -2,17 +2,13 @@
namespace Kiri\Rpc;
use Kiri\Message\Response;
use Kiri\Message\Stream;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Exception;
/**
*
*/
class JsonRpcTransporter implements RpcClientInterface
class JsonRpcTransporter implements JsonRpcTransporterInterface
{
@@ -20,19 +16,21 @@ class JsonRpcTransporter implements RpcClientInterface
/**
* @param RequestInterface $request
* @return ResponseInterface
* @throws \Exception
* @param string $content
* @param string $service
* @return string|bool
* @throws RpcServiceException
* @throws Exception
*/
public function sendRequest(RequestInterface $request): ResponseInterface
public function push(string $content, string $service): string|bool
{
$content = $request->getBody()->getContents();
$client = $this->get_consul($service)->newClient();
$body = $this->request($this->newClient(), $content);
$body = $this->request($client, $content);
$response = \Kiri::getDi()->get(ResponseInterface::class);
$client->close();
return $response->withBody(new Stream($body));
return $body;
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace Kiri\Rpc;
interface JsonRpcTransporterInterface
{
/**
* @param string $content
* @param string $service
* @return string|bool
*/
public function push(string $content, string $service): string|bool;
}
-14
View File
@@ -1,14 +0,0 @@
<?php
namespace Kiri\Rpc;
use Psr\Http\Client\ClientInterface;
/**
* @mixin JsonRpcTransporter
*/
interface RpcClientInterface extends ClientInterface
{
}
+43 -34
View File
@@ -5,19 +5,17 @@ namespace Kiri\Rpc;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Kiri;
use Kiri\Di\LocalService;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Annotation;
use Kiri\Consul\Agent;
use Kiri\Context;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Kiri\Message\Constrict\RequestInterface;
use Kiri\Message\Handler\DataGrip;
use Kiri\Message\Handler\Router;
use Kiri\Message\Handler\RouterCollector;
use Kiri\Message\ServerRequest;
use Kiri\Server\Contract\OnCloseInterface;
use Kiri\Server\Contract\OnConnectInterface;
use Kiri\Server\Contract\OnReceiveInterface;
@@ -26,7 +24,6 @@ use Kiri\Server\Events\OnServerBeforeStart;
use Psr\Container\ContainerExceptionInterface;
use Kiri\Di\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ServerRequestInterface;
use ReflectionException;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
@@ -41,6 +38,8 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
private array $consul = [];
public RouterCollector $collector;
/**
* @param ContainerInterface $container
@@ -48,7 +47,6 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
* @param Annotation $annotation
* @param DataGrip $dataGrip
* @param RpcManager $manager
* @param RouterCollector $collector
* @param EventProvider $eventProvider
* @param array $config
* @throws Exception
@@ -58,7 +56,6 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
public Annotation $annotation,
public DataGrip $dataGrip,
public RpcManager $manager,
public RouterCollector $collector,
public EventProvider $eventProvider,
array $config = [])
{
@@ -68,17 +65,39 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
/**
* @return void
* @throws ReflectionException|ConfigException
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function init(): void
{
$this->eventProvider->on(OnBeforeShutdown::class, [$this, 'onBeforeShutdown']);
scan_directory(APP_PATH . 'rpc', 'app\Rpc');
$this->consul = Config::get('rpc.consul', null);
if (!empty($this->consul)) {
$this->eventProvider->on(OnServerBeforeStart::class, [$this, 'register']);
}
// $this->consul = Config::get('rpc.consul', null);
// if (!empty($this->consul)) {
// $this->eventProvider->on(OnServerBeforeStart::class, [$this, 'register']);
// }
$this->collector = $this->dataGrip->get('rpc');
$this->registerConsumers();
}
/**
* @return void
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function registerConsumers(): void
{
$consumers = Config::get('rpc.consumers', []);
if (!is_array($consumers)) {
return;
}
$local = $this->container->get(LocalService::class);
foreach ($consumers as $consumer) {
$local->set($consumer['id'], $consumer);
}
}
@@ -134,10 +153,12 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
* @param int $fd
* @param int $reactor_id
* @param string $data
* @return bool
*/
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): void
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): bool
{
try {
if (!isJson($data)) return $server->send($fd, 'success', $reactor_id);
$data = json_decode($data, true);
if (!is_array($data)) {
throw new Exception('Parse error语法解析错误', -32700);
@@ -145,11 +166,11 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
if (!isset($data['jsonrpc']) || !isset($data['method']) || $data['jsonrpc'] != '2.0') {
throw new Exception('Invalid Request无效请求', -32600);
}
$server->send($fd, $this->batchDispatch($data));
return $server->send($fd, $this->batchDispatch($data), $reactor_id);
} catch (\Throwable $throwable) {
$this->logger->error('JsonRpc: ' . $throwable->getMessage());
$response = Json::encode($this->failure(-32700, $throwable->getMessage()));
$server->send($fd, $response);
return $server->send($fd, $response, $reactor_id);
}
}
@@ -208,19 +229,18 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
private function dispatch($data): array
{
try {
$handler = $this->collector->find($data['service'], 'GET');
if (is_integer($handler) || is_null($handler)) {
$class = $this->container->get(LocalService::class)->get($data['service']);
if (!$this->container->has($class)) {
throw new Exception('Handler not found', -32601);
}
$controller = $this->container->get($handler->callback[0]);
$controller = $this->container->get($class);
if (!method_exists($controller, $data['method'])) {
throw new Exception('Method not found', -32601);
}
$params = $this->container->getArgs($data['method'], $controller::class);
Context::setContext(RequestInterface::class, $this->createServerRequest($params));
return $this->handler($controller, $data['method'], $params);
if (!isset($data['params']) || !is_array($data['params'])) {
$data['params'] = [];
}
return $this->handler($controller, $data['method'], $data['params']);
} catch (\Throwable $throwable) {
$code = $throwable->getCode() == 0 ? -32603 : $throwable->getCode();
return $this->failure($code, jTraceEx($throwable), [], $data['id'] ?? null);
@@ -228,17 +248,6 @@ class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterfa
}
/**
* @param $params
* @return ServerRequestInterface
* @throws Exception
*/
private function createServerRequest($params): ServerRequestInterface
{
return (new ServerRequest())->withParsedBody($params);
}
/**
* @param $controller
* @param string $method
+27
View File
@@ -0,0 +1,27 @@
<?php
use Kiri\Rpc\AbstractRpcClient;
use Kiri\Rpc\Annotation\JsonRpc;
use Kiri\Rpc\JsonRpcTransporterInterface;
class TestRpc extends AbstractRpcClient
{
public string $service = '';
/**
* @param $data
* @param $nba
* @return mixed
*/
public function test($data, $nba): mixed
{
$resp = $this->send(__FUNCTION__, $data, $nba);
return json_decode($resp, true);
}
}
+54 -26
View File
@@ -3,6 +3,8 @@
namespace Kiri\Rpc;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Kiri\Annotation\Inject;
use Kiri\Context;
use Kiri\Core\Json;
use Swoole\Client;
@@ -12,35 +14,72 @@ trait TraitTransporter
{
protected array $config;
protected array $clients = [];
/**
* @param $config
* @return $this
* @var RpcManager
*/
public function withConfig($config): static
{
$this->config = $config;
return $this;
}
#[Inject(RpcManager::class)]
public RpcManager $manager;
protected array $config;
/**
* @param Client|Coroutine\Client $client
* @param $content
* @return mixed
* @return string|bool
*/
private function request(Client|Coroutine\Client $client, $content): mixed
private function request(Client|Coroutine\Client $client, $content): string|bool
{
$client->send($content);
return $client->recv();
}
/**
* @param string $service
* @return $this
* @throws RpcServiceException
*/
private function get_consul(string $service): static
{
if (empty($service)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
$sf = $this->manager->getServices($service);
if (empty($sf) || !is_array($sf)) {
throw new RpcServiceException('You need set rpc service name if used.');
}
$this->config = $this->_loadRand($sf);
return $this;
}
/**
* @param $services
* @return array
*/
#[ArrayShape(['Address' => "mixed", 'Port' => "mixed"])]
private function _loadRand($services): array
{
$array = [];
foreach ($services as $value) {
$value['Weight'] = $value['Weights']['Passing'];
$array[] = $value;
}
if (count($array) < 2) {
$luck = $array[0];
} else {
$luck = Luckdraw::luck($array, 'Weight');
}
return [
'Address' => $luck['TaggedAddresses']['wan_ipv4']['Address'],
'Port' => $luck['TaggedAddresses']['wan_ipv4']['Port']
];
}
/**
* @return Client|Coroutine\Client
* @throws Exception
@@ -59,15 +98,4 @@ trait TraitTransporter
return $client;
}
/**
* @param array $config
* @return string
*/
private function alias(array $config): string
{
return $config['Address'] . '::' . $config['Port'];
}
}
+1 -2
View File
@@ -10,8 +10,7 @@
"license": "MIT",
"require": {
"php": ">=8.0",
"ext-json": "*",
"psr/http-client": "^1.0"
"ext-json": "*"
},
"autoload": {
"psr-4": {
+1 -11
View File
@@ -17,17 +17,6 @@ return [
],
'events' => [
Constant::RECEIVE => [RpcJsonp::class, 'onReceive']
],
'consumers' => [
'class' => TestRpcService::class,
'name' => 'test-rpc',
'package' => 'test',
'register' => [
'host' => '',
'port' => ''
]
]
],
@@ -37,6 +26,7 @@ return [
"datacenter" => "dc1",
"id" => "40e4a748-2192-161a-0510-9bf59fe950b5",
"node" => "FriendRpcService",
'class' => TestRpc::class,
"skipNodeUpdate" => false,
"service" => [
"id" => "redis1",