Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,17 @@

# RPC Library

## JSON-RPC Implementation
Built-in support for batch-like requests. Processing depends on client implementation (may not be real batch)

## Common interfaces
* RPC request (call)
* RPC response (result)
* RPC error
## Decorators
* Lazy client decorator
* Loggable client decorator
* Cacheable client decorator

# JSON-RPC Implementation

[JSON-RPC 2.0 Specification](http://www.jsonrpc.org/specification)
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"minimum-stability": "stable",
"require": {
"php": "~5.5|~7.0",
"psr/log": "~1.0",
"guzzlehttp/guzzle": "~6.0",
"paragonie/random_compat": "~1.1@stable"
},
"require-dev": {
"phpunit/phpunit": "~4.5|~5.1",
"psr/log": "~1.0",
"psr/cache": "~1.0"
},
"autoload": {
Expand All @@ -25,7 +25,6 @@
}
},
"suggest": {
"psr/log": "For LoggableRpcClient decorator",
"psr/cache": "For CacheableRpcClient decorator"
}
}
81 changes: 45 additions & 36 deletions src/ScayTrase/Api/JsonRpc/JsonRpcClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use ScayTrase\Api\IdGenerator\IdGeneratorInterface;
use ScayTrase\Api\IdGenerator\UuidGenerator;
use ScayTrase\Api\Rpc\Exception\RemoteCallFailedException;
Expand All @@ -29,44 +31,76 @@ final class JsonRpcClient implements RpcClientInterface
private $uri;
/** @var IdGeneratorInterface */
private $idGenerator;
/** @var LoggerInterface */
private $logger;

/**
* JsonRpcClient constructor.
* @param ClientInterface $client
* @param UriInterface $endpoint
* @param IdGeneratorInterface|null $idGenerator
* @param LoggerInterface $logger
*/
public function __construct(ClientInterface $client, UriInterface $endpoint, IdGeneratorInterface $idGenerator = null)
public function __construct(
ClientInterface $client,
UriInterface $endpoint,
IdGeneratorInterface $idGenerator = null,
LoggerInterface $logger = null
)
{
$this->client = $client;
$this->uri = $endpoint;
$this->idGenerator = $idGenerator;
$this->logger = $logger;

if (null === $this->idGenerator) {
$this->idGenerator = new UuidGenerator();
}

if (null === $this->logger) {
$this->logger = new NullLogger();
}
}

/**
* {@inheritdoc}
*/
public function invoke($calls)
{
if (!is_array($calls) && ($calls instanceof RpcRequestInterface)) {
$calls = [$calls];
}
try {
if (!is_array($calls) && ($calls instanceof RpcRequestInterface)) {
$transformedCall = $this->transformCall($calls);
return new JsonRpcResponseCollection(
$this->client->sendAsync(
$this->createHttpRequest($transformedCall)
),
[new RequestTransformation($calls, $transformedCall)]
);
}

$requests = [];
$batchRequest = [];

$requests = [];
$requestBody = [];
foreach ($calls as $key => $call) {
$transformedCall = $this->transformCall($call);
$requests[spl_object_hash($call)] = new RequestTransformation($call, $transformedCall);
$batchRequest[] = $transformedCall;
}

foreach ($calls as $key => $call) {
$transformedCall = $this->transformCall($call);
$requests[spl_object_hash($call)] = new RequestTransformation($call, $transformedCall);
$requestBody[] = $this->formatJsonRpcCall($transformedCall);
return new JsonRpcResponseCollection($this->client->sendAsync($this->createHttpRequest($batchRequest)), $requests);
} catch (GuzzleException $exception) {
throw new RemoteCallFailedException($exception->getMessage(), 0, $exception);
}
}

/**
* @param $requestBody
* @return Request
*/
private function createHttpRequest($requestBody)
{
/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
$request = new Request(
return new Request(
'POST',
$this->uri,
[
Expand All @@ -75,12 +109,6 @@ public function invoke($calls)
],
json_encode($requestBody, JSON_PRETTY_PRINT)
);

try {
return new JsonRpcResponseCollection($this->client->sendAsync($request), $requests);
} catch (GuzzleException $exception) {
throw new RemoteCallFailedException($exception->getMessage(), 0, $exception);
}
}

/**
Expand All @@ -96,23 +124,4 @@ private function transformCall(RpcRequestInterface $call)
}
return $transformedCall;
}

/**
* @param JsonRpcRequestInterface|RpcRequestInterface $request
* @return array
*/
private function formatJsonRpcCall(JsonRpcRequestInterface $request)
{
$result = [
'jsonrpc' => static::VERSION,
'method' => $request->getMethod(),
'params' => $request->getParameters(),
];

if (!$request->isNotification()) {
$result['id'] = $request->getId();
}

return $result;
}
}
27 changes: 21 additions & 6 deletions src/ScayTrase/Api/JsonRpc/JsonRpcError.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,52 @@ final class JsonRpcError implements JsonRpcErrorInterface
private $code;
/** @var string */
private $message;
/** @var null|\StdClass */
/** @var null|\stdClass */
private $data;

/**
* JsonRpcError constructor.
* @param int $code
* @param string $message
* @param \StdClass|null $data
* @param \stdClass|mixed|null $data
*/
public function __construct($code, $message, \StdClass $data = null)
public function __construct($code, $message, $data = null)
{
$this->code = $code;
$this->message = $message;
$this->data = $data;
}

/** @return int */
/** {@inheritdoc} */
public function getCode()
{
return $this->code;
}

/** @return string */
/** {@inheritdoc} */
public function getMessage()
{
return $this->message;
}

/** @return \StdClass|null error data */
/** {@inheritdoc} */
public function getData()
{
return $this->data;
}

/** {@inheritdoc} */
public function jsonSerialize()
{
$error = [
self::ERROR_CODE_FIELD => $this->getCode(),
self::ERROR_MESSAGE_FIELD => $this->getMessage(),
];

if (null !== ($data = $this->getData())) {
$error[self::ERROR_DATA_FIELD] = $data;
}

return $error;
}
}
36 changes: 34 additions & 2 deletions src/ScayTrase/Api/JsonRpc/JsonRpcErrorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,46 @@

use ScayTrase\Api\Rpc\RpcErrorInterface;

interface JsonRpcErrorInterface extends RpcErrorInterface
interface JsonRpcErrorInterface extends RpcErrorInterface, \JsonSerializable
{
const ERROR_CODE_FIELD = 'code';
const ERROR_MESSAGE_FIELD = 'message';
const ERROR_DATA_FIELD = 'data';

CONST PARSE_ERROR = -32700;
CONST INVALID_REQUEST = -32600;
CONST METHOD_NOT_FOUND = -32601;
CONST INVALID_PARAMS = -32602;
CONST INTERNAL_ERROR = -32603;

/** @return \StdClass|null error data */
/**
* Returns error code
*
* A Number that indicates the error type that occurred.
* This MUST be an integer.
*
* @return int
*/
public function getCode();

/**
* Return error message
*
* String providing a short description of the error.
* The message SHOULD be limited to a concise single sentence.
*
* @return string
*/
public function getMessage();

/**
* Returns amy additional error information specified by server
*
* A Primitive or Structured value that contains additional information about the error.
* This may be omitted.
* The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
*
* @return \stdClass|mixed|null error data
*/
public function getData();
}
22 changes: 19 additions & 3 deletions src/ScayTrase/Api/JsonRpc/JsonRpcNotification.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ final class JsonRpcNotification implements JsonRpcRequestInterface
{
/** @var string */
private $method;
/** @var array */
/** @var \stdClass|array|null */
private $parameters;

/**
* JsonRpcNotificationRequest constructor.
* @param string $method
* @param array $parameters
* @param \stdClass|array|null $parameters
*/
public function __construct($method, array $parameters)
public function __construct($method, $parameters)
{
$this->method = $method;
$this->parameters = $parameters;
Expand Down Expand Up @@ -48,4 +48,20 @@ public function getParameters()
{
return $this->parameters;
}

/** {@inheritdoc} */
public function getVersion()
{
return JsonRpcClient::VERSION;
}

/** {@inheritdoc} */
public function jsonSerialize()
{
return [
self::VERSION_FIELD => JsonRpcClient::VERSION,
self::METHOD_FIELD => $this->getMethod(),
self::PARAMETERS_FIELD => $this->getParameters(),
];
}
}
9 changes: 9 additions & 0 deletions src/ScayTrase/Api/JsonRpc/JsonRpcNotificationResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ public function getId()
{
return null;
}

/**
* {@inheritdoc}
* @throws \LogicException
*/
public function jsonSerialize()
{
throw new \LogicException('Notification should not have transferable response representation');
}
}
34 changes: 32 additions & 2 deletions src/ScayTrase/Api/JsonRpc/JsonRpcRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ final class JsonRpcRequest implements JsonRpcRequestInterface
private $id;
/** @var string */
private $method;
/** @var \StdClass|\StdClass[]|null */
/** @var \stdClass|array|null */
private $parameters;

/**
* JsonRpcRequest constructor.
* @param string $method
* @param \StdClass|\StdClass[]|null $parameters
* @param \stdClass|array|null $parameters
* @param string $id
*/
public function __construct($method, $parameters = null, $id = null)
Expand Down Expand Up @@ -64,4 +64,34 @@ public function getParameters()
{
return $this->parameters;
}

/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
$result = [
self::VERSION_FIELD => JsonRpcClient::VERSION,
self::METHOD_FIELD => $this->getMethod(),
self::PARAMETERS_FIELD => $this->getParameters(),
];

if (!$this->isNotification()) {
$result[self::ID_FIELD] = $this->getId();
}

return $result;
}

/**
* Returns version of the JSON-RPC request
*
* A String specifying the version of the JSON-RPC protocol. MUST be exactly "2.0".
*
* @return string JSON-RPC version
*/
public function getVersion()
{
return JsonRpcClient::VERSION;
}
}
Loading