Files
kiri-rpc/RpcJsonp.php
T

272 lines
6.5 KiB
PHP
Raw Normal View History

2022-01-09 14:00:32 +08:00
<?php
namespace Kiri\Rpc;
2022-03-03 16:39:46 +08:00
use Exception;
2022-05-04 03:11:10 +08:00
use JetBrains\PhpStorm\ArrayShape;
2022-01-14 11:29:16 +08:00
use Kiri;
2022-09-23 18:55:46 +08:00
use Kiri\Di\LocalService;
2022-01-09 14:00:32 +08:00
use Kiri\Abstracts\Component;
2022-06-17 13:44:24 +08:00
use Kiri\Core\Json;
2022-03-03 18:30:59 +08:00
use Kiri\Events\EventProvider;
2022-01-10 11:39:56 +08:00
use Kiri\Server\Contract\OnCloseInterface;
use Kiri\Server\Contract\OnConnectInterface;
use Kiri\Server\Contract\OnReceiveInterface;
use Kiri\Server\Events\OnBeforeShutdown;
use Kiri\Server\Events\OnServerBeforeStart;
2022-01-14 11:29:16 +08:00
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
2022-02-23 16:32:08 +08:00
use ReflectionException;
2022-01-09 14:00:32 +08:00
use Swoole\Coroutine;
2023-07-31 23:09:00 +08:00
use Kiri\Router\RouterCollector;
use Psr\Container\ContainerInterface;
2022-01-09 14:00:32 +08:00
use Swoole\Coroutine\Channel;
use Swoole\Server;
2023-07-31 23:09:00 +08:00
use Kiri\Router\DataGrip;
2022-01-09 14:00:32 +08:00
/**
*
*/
class RpcJsonp extends Component implements OnConnectInterface, OnReceiveInterface, OnCloseInterface
{
2022-09-23 18:55:46 +08:00
public RouterCollector $collector;
2022-06-16 17:38:23 +08:00
/**
* @param ContainerInterface $container
* @param DataGrip $dataGrip
* @param RpcManager $manager
* @param EventProvider $eventProvider
* @throws Exception
*/
public function __construct(public ContainerInterface $container,
public DataGrip $dataGrip,
public RpcManager $manager,
2023-07-31 23:09:00 +08:00
public EventProvider $eventProvider)
2022-06-16 17:38:23 +08:00
{
2023-07-31 23:09:00 +08:00
parent::__construct();
2022-06-16 17:38:23 +08:00
}
2023-07-31 23:09:00 +08:00
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws ReflectionException
* @throws Exception
*/
2022-06-16 17:38:23 +08:00
public function init(): void
{
$this->eventProvider->on(OnBeforeShutdown::class, [$this, 'onBeforeShutdown']);
2023-07-31 23:09:00 +08:00
2022-06-16 17:38:23 +08:00
$this->collector = $this->dataGrip->get('rpc');
2022-09-23 18:55:46 +08:00
$this->registerConsumers();
}
/**
* @return void
2023-07-31 23:09:00 +08:00
* @throws ContainerExceptionInterface
2022-09-23 18:55:46 +08:00
* @throws NotFoundExceptionInterface
*/
public function registerConsumers(): void
{
2023-05-25 16:59:19 +08:00
$consumers = \config('rpc.consumers', []);
2022-09-23 18:55:46 +08:00
if (!is_array($consumers)) {
return;
}
$local = $this->container->get(LocalService::class);
foreach ($consumers as $consumer) {
$local->set($consumer['id'], $consumer);
}
2022-06-16 17:38:23 +08:00
}
2022-06-08 14:27:49 +08:00
2022-06-16 17:38:23 +08:00
2023-07-31 23:09:00 +08:00
/**
* @param OnBeforeShutdown $beforeShutdown
* @return void
*/
2022-06-16 17:38:23 +08:00
public function onBeforeShutdown(OnBeforeShutdown $beforeShutdown): void
{
if (env('environmental') != Kiri::WORKER && env('environmental_workerId') != 0) {
2022-05-31 11:43:06 +08:00
return;
}
2022-06-16 17:38:23 +08:00
}
2022-05-31 11:11:12 +08:00
/**
* @param OnServerBeforeStart $server
*/
2022-06-16 17:38:23 +08:00
public function register(OnServerBeforeStart $server)
{
}
/**
* @param Server $server
* @param int $fd
*/
public function onConnect(Server $server, int $fd): void
{
// TODO: Implement onConnect() method.
}
/**
* @param Server $server
* @param int $fd
* @param int $reactor_id
* @param string $data
2022-09-23 18:55:46 +08:00
* @return bool
2022-06-16 17:38:23 +08:00
*/
2022-09-23 18:55:46 +08:00
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): bool
2022-06-16 17:38:23 +08:00
{
try {
2022-09-23 19:02:26 +08:00
$data = json_decode($data, true);
if (is_null($data)) return $server->send($fd, 'success', $reactor_id);
2022-06-16 17:38:23 +08:00
$data = json_decode($data, true);
if (!is_array($data)) {
throw new Exception('Parse error语法解析错误', -32700);
}
if (!isset($data['jsonrpc']) || !isset($data['method']) || $data['jsonrpc'] != '2.0') {
throw new Exception('Invalid Request无效请求', -32600);
}
2022-09-23 18:55:46 +08:00
return $server->send($fd, $this->batchDispatch($data), $reactor_id);
2022-06-16 17:38:23 +08:00
} catch (\Throwable $throwable) {
2022-06-17 13:44:24 +08:00
$response = Json::encode($this->failure(-32700, $throwable->getMessage()));
2022-09-23 18:55:46 +08:00
return $server->send($fd, $response, $reactor_id);
2022-06-16 17:38:23 +08:00
}
}
/**
* @param array $data
* @return string|bool
*/
private function batchDispatch(array $data): string|bool
{
if (isset($data['jsonrpc'])) {
$result = $this->dispatch($data);
if (!isset($data['id'])) {
$result = [1];
}
} else {
$channel = new Channel($total = count($data));
foreach ($data as $datum) {
$this->_execute($channel, $datum);
}
$result = [];
for ($i = 0; $i < $total; $i++) {
$result[] = $channel->pop();
}
}
return json_encode($result, JSON_UNESCAPED_UNICODE);
}
/**
* @param $channel
* @param $datum
*/
private function _execute($channel, $datum)
{
Coroutine::create(function () use ($channel, $datum) {
if (empty($datum) || !isset($datum['jsonrpc'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else if (!isset($datum['method'])) {
$channel->push($this->failure(-32700, 'Parse error语法解析错误'));
} else {
$dispatch = $this->dispatch($datum);
if (!isset($dispatch['id'])) {
$dispatch = [1];
}
$channel->push($dispatch);
2022-05-31 11:11:12 +08:00
}
2022-06-16 17:38:23 +08:00
});
}
/**
* @param $data
* @return array
*/
private function dispatch($data): array
{
try {
2022-09-23 18:55:46 +08:00
$class = $this->container->get(LocalService::class)->get($data['service']);
if (!$this->container->has($class)) {
2022-06-16 17:38:23 +08:00
throw new Exception('Handler not found', -32601);
}
2022-09-23 18:55:46 +08:00
$controller = $this->container->get($class);
2022-06-16 17:38:23 +08:00
if (!method_exists($controller, $data['method'])) {
throw new Exception('Method not found', -32601);
}
2022-09-23 18:55:46 +08:00
if (!isset($data['params']) || !is_array($data['params'])) {
$data['params'] = [];
}
return $this->handler($controller, $data['method'], $data['params']);
2022-06-16 17:38:23 +08:00
} catch (\Throwable $throwable) {
$code = $throwable->getCode() == 0 ? -32603 : $throwable->getCode();
return $this->failure($code, jTraceEx($throwable), [], $data['id'] ?? null);
2022-05-31 11:11:12 +08:00
}
2022-06-16 17:38:23 +08:00
}
/**
* @param $controller
* @param string $method
* @param $params
* @return array
*/
#[ArrayShape([])]
private function handler($controller, string $method, $params): array
{
$result = call_user_func([$controller, $method], ...$params);
return [
'jsonrpc' => '2.0',
'result' => $result,
'id' => $data['id'] ?? null
];
}
/**
* @param $code
* @param $message
* @param array $data
* @param null $id
* @return array
*/
#[ArrayShape([])]
protected function failure($code, $message, array $data = [], $id = null): array
{
$error = [
'jsonrpc' => '2.0',
'error' => [
'code' => $code,
'message' => $message,
'data' => $data
]
];
if (!is_null($id)) {
$error['id'] = $id;
}
return $error;
}
2023-07-31 23:09:00 +08:00
/**
* @param Server $server
* @param int $fd
* @return void
*/
public function OnClose(Server $server, int $fd): void
2022-06-16 17:38:23 +08:00
{
// TODO: Implement onClose() method.
}
2022-01-09 14:00:32 +08:00
}