2021-10-26 18:58:09 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Kiri\Rpc;
|
|
|
|
|
|
|
|
|
|
use Annotation\Inject;
|
|
|
|
|
use Http\Constrict\ResponseInterface;
|
|
|
|
|
use Http\Handler\Abstracts\HandlerManager;
|
|
|
|
|
use Http\Handler\Dispatcher;
|
2021-10-28 14:02:25 +08:00
|
|
|
use Http\Handler\Handler;
|
2021-10-26 18:58:09 +08:00
|
|
|
use Http\Handler\Router;
|
|
|
|
|
use Http\Message\ServerRequest;
|
2021-10-28 14:02:25 +08:00
|
|
|
use Kiri\Kiri;
|
|
|
|
|
use ReflectionMethod;
|
2021-10-26 18:58:09 +08:00
|
|
|
use Server\SInterface\OnCloseInterface;
|
|
|
|
|
use Server\SInterface\OnConnectInterface;
|
|
|
|
|
use Server\SInterface\OnReceiveInterface;
|
|
|
|
|
use Swoole\Coroutine;
|
|
|
|
|
use Swoole\Coroutine\Channel;
|
|
|
|
|
use Swoole\Server;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
class RpcJsonp implements OnConnectInterface, OnReceiveInterface, OnCloseInterface
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[Inject(Router::class)]
|
|
|
|
|
public Router $router;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
*/
|
|
|
|
|
public function onReceive(Server $server, int $fd, int $reactor_id, string $data): void
|
|
|
|
|
{
|
|
|
|
|
$data = json_decode($data, true);
|
|
|
|
|
if (is_null($data)) {
|
|
|
|
|
$this->failure(-32700, 'Parse error语法解析错误');
|
|
|
|
|
} else if (!isset($data['jsonrpc']) || !isset($data['method']) || $data['jsonrpc'] != '2.0') {
|
|
|
|
|
$this->failure(-32600, 'Invalid Request无效请求');
|
|
|
|
|
} else {
|
|
|
|
|
$this->batchDispatch($server, $fd, $data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param Server $server
|
|
|
|
|
* @param int $fd
|
|
|
|
|
* @param array $data
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
private function batchDispatch(Server $server, int $fd, array $data): void
|
|
|
|
|
{
|
|
|
|
|
if (isset($data['jsonrpc'])) {
|
|
|
|
|
$dispatch = $this->dispatch($data);
|
|
|
|
|
if (!isset($data['id'])) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$result = json_encode($dispatch, JSON_UNESCAPED_UNICODE);
|
|
|
|
|
} else {
|
|
|
|
|
$channel = new Channel($total = count($data));
|
|
|
|
|
foreach ($data as $datum) {
|
|
|
|
|
$this->_execute($channel, $datum);
|
|
|
|
|
}
|
|
|
|
|
$result = [];
|
|
|
|
|
for ($i = 0; $i < $total; $i++) {
|
|
|
|
|
$params = $channel->pop();
|
|
|
|
|
if (empty($params)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$result[] = $params;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$server->send($fd, 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 = null;
|
|
|
|
|
}
|
|
|
|
|
$channel->push($dispatch);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $data
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
private function dispatch($data): array
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$handler = HandlerManager::get($data['method'], 'json-rpc');
|
|
|
|
|
if (is_integer($handler)) {
|
|
|
|
|
throw new \Exception('Invalid Request无效请求', -32600);
|
|
|
|
|
} else if (is_null($handler)) {
|
|
|
|
|
throw new \Exception('Method not found', -32601);
|
|
|
|
|
} else {
|
|
|
|
|
return $this->handler($handler, $data);
|
|
|
|
|
}
|
|
|
|
|
} catch (\Throwable $throwable) {
|
|
|
|
|
$code = $throwable->getCode() == 0 ? -32603 : $throwable->getCode();
|
|
|
|
|
return $this->failure($code, jTraceEx($throwable), [], $data['id'] ?? null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2021-10-28 14:02:25 +08:00
|
|
|
* @param Handler $handler
|
2021-10-26 18:58:09 +08:00
|
|
|
* @param $data
|
|
|
|
|
* @return array
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
*/
|
2021-10-28 14:02:25 +08:00
|
|
|
private function handler(Handler $handler, $data): array
|
2021-10-26 18:58:09 +08:00
|
|
|
{
|
2021-10-28 14:02:25 +08:00
|
|
|
/** @var ReflectionMethod $reflection */
|
|
|
|
|
$reflection = Kiri::getDi()->getReflectMethod($handler->callback[0]::class, $handler->callback[1]);
|
2021-10-28 14:45:33 +08:00
|
|
|
|
|
|
|
|
$params = [];
|
2021-10-28 14:02:25 +08:00
|
|
|
foreach ($reflection->getParameters() as $value) {
|
2021-10-28 14:45:33 +08:00
|
|
|
$params[] = $data['params'][$value->getName()] ?? null;
|
2021-10-28 14:02:25 +08:00
|
|
|
}
|
2021-10-28 14:45:33 +08:00
|
|
|
$handler->params = $params;
|
2021-10-28 14:02:25 +08:00
|
|
|
|
|
|
|
|
$dispatcher = (new Dispatcher($handler, $handler->_middlewares))->handle((new ServerRequest())->withData($data['params']));
|
2021-10-26 18:58:09 +08:00
|
|
|
if ($dispatcher instanceof ResponseInterface) {
|
|
|
|
|
$dispatcher = json_decode($dispatcher->getBody()->getContents(), true);
|
|
|
|
|
}
|
|
|
|
|
return ['jsonrpc' => '2.0', 'result' => $dispatcher, 'id' => $data['id'] ?? null];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $code
|
|
|
|
|
* @param $message
|
|
|
|
|
* @param array $data
|
|
|
|
|
* @param null $id
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param Server $server
|
|
|
|
|
* @param int $fd
|
|
|
|
|
*/
|
|
|
|
|
public function onClose(Server $server, int $fd): void
|
|
|
|
|
{
|
|
|
|
|
// TODO: Implement onClose() method.
|
|
|
|
|
}
|
|
|
|
|
}
|