Skip to content

Commit

Permalink
6.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
smortensen committed Feb 28, 2020
1 parent a7e331a commit ad4d735
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 45 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [6.1.0] - 2020-02-28
### Added
- The "Client::preEncode" and "Client::postDecode" methods have been added to allow
advanced users to inspect and tweak the inner workings of the JSON-RPC library.
- The "Server::rawReply" method has been added to complement the new "Client" methods.

## [6.0.0] - 2019-07-25
### Changed
- There are now two types of responses--an "ErrorResponse" and a "ResultResponse"--
Expand Down
101 changes: 74 additions & 27 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,37 +90,65 @@ public function notify($method, array $arguments = null): self
}

/**
* Encodes the requests as a valid JSON-RPC 2.0 string
* Encodes the request(s) as a valid JSON-RPC 2.0 string
*
* This also resets the Client, so you can perform more queries using
* the same Client object.
* This also resets the Client, so you can use the same Client object
* to perform more queries.
*
* @return null|string
* @return string|null
* Returns a valid JSON-RPC 2.0 message string
* Returns null if there is nothing to encode
*/
public function encode()
{
$count = count($this->requests);
$input = $this->preEncode();

if ($count === 0) {
if ($input === null) {
return null;
}

if ($count === 1) {
$input = array_shift($this->requests);
return json_encode($input);
}

/**
* Encodes the request(s) as a JSON-RPC 2.0 array, but does NOT perform
* the final "json_encode" step which is necessary to turn the array
* into a valid JSON-RPC 2.0 string. This gives you the opportunity
* to inspect or modify the raw data, or to alter the encoding algorithm.
*
* When you're finished manipulating the request, you are responsible for
* JSON-encoding the value to construct the final JSON-RPC 2.0 string.
* @see self::encode()
*
* This also resets the Client, so you can use the same Client object
* to perform more queries.
*
* @return array|null
* Returns a JSON-RPC 2.0 request array
* Returns null if no requests have been queued
*/
public function preEncode()
{
$n = count($this->requests);

if ($n === 0) {
return null;
}

if ($n === 1) {
$input = $this->requests[0];
} else {
$input = $this->requests;
}

$this->reset();

return json_encode($input);
return $input;
}

/**
* Translates a JSON-RPC 2.0 server reply into an array of "Response"
* objects
* objects.
*
* @param string $json
* String reply from a JSON-RPC 2.0 server
Expand All @@ -133,21 +161,48 @@ public function encode()
*/
public function decode(string $json)
{
set_error_handler(__CLASS__ . '::onError');
$input = json_decode($json, true);

try {
$input = json_decode($json, true);
} finally {
restore_error_handler();
}
$errorCode = json_last_error();

if ($errorCode !== 0) {
$errorMessage = json_last_error_msg();
$jsonException = new ErrorException($errorMessage, $errorCode);

if (($input === null) && (strtolower(trim($json)) !== 'null')) {
$valueText = self::getValueText($json);
throw new ErrorException("Invalid JSON: {$valueText}");
throw new ErrorException("Invalid JSON: {$valueText}", 0, E_ERROR, __FILE__, __LINE__, $jsonException);
}

return $this->postDecode($input);
}

/**
* Translates a JSON-decoded server reply into an array of "Response"
* objects.
*
* This gives you the opportunity to use your own modified "json_decode"
* algorithm, or to inspect or modify the server response before it is
* processed under the JSON-RPC 2.0 specifications. This can be handy
* if you're tweaking or extending the JSON-RPC 2.0 format.
*
* Before calling this method, you are responsible for JSON-decoding
* the server reply string. You should have that decoded array value
* to use as the input here.
* @see self::decode()
*
* @param mixed $input
* An array containing the JSON-decoded server reply
*
* @return Response[]
* Returns a zero-indexed array of "Response" objects
*
* @throws ErrorException
* Throws an "ErrorException" if the reply was not well-formed
*/
public function postDecode($input)
{
if (!$this->getResponses($input, $responses)) {
$valueText = self::getValueText($json);
$valueText = self::getValueText($input);
throw new ErrorException("Invalid JSON-RPC 2.0 response: {$valueText}");
}

Expand Down Expand Up @@ -308,12 +363,4 @@ private function getBatchResponses($input, &$responses)

return true;
}

public static function onError($level, $message, $file, $line)
{
$message = trim($message);
$code = 0;

throw new ErrorException($message, $code, $level, $file, $line);
}
}
60 changes: 42 additions & 18 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,40 +47,64 @@ public function __construct(Evaluator $evaluator)
}

/**
* Processes the user input, and prepares a response (if necessary).
* Processes a JSON-RPC 2.0 client request string and prepares a valid
* response.
*
* @param string $json
* Single request object, or an array of request objects, as a JSON string.
*
* @return string|null
* Returns a response object (or an error object) as a JSON string, when a query is made.
* Returns an array of response/error objects as a JSON string, when multiple queries are made.
* Returns null, when no response is necessary.
* @return null|string
* Returns null when no response is necessary.
* Returns a response/error object, as a JSON string, when a query is made.
* Returns an array of response/error objects, as a JSON string, when multiple queries are made.
* @see Responses\ResultResponse
* @see Responses\ErrorResponse
*/
public function reply($json)
{
if ($this->getInput($json, $input)) {
$output = $this->processInput($input);
if (is_string($json)) {
$input = json_decode($json, true);
} else {
$output = $this->parseError();
$input = null;
}

if ($output === null) {
return null;
$reply = $this->rawReply($input);

if (is_array($reply)) {
$output = json_encode($reply);
} else {
$output = null;
}

return json_encode($output);
return $output;
}

private function getInput($json, &$input)
/**
* Processes a JSON-RPC 2.0 client request array and prepares a valid
* response. This method skips the JSON encoding and decoding steps,
* so you can use your own alternative encoding algorithm, or extend
* the JSON-RPC 2.0 format.
*
* When you use this method, you are taking responsibility for
* performing the necessary JSON encoding and decoding steps yourself.
* @see self::reply()
*
* @param mixed $input
* An array containing the JSON-decoded client request.
*
* @return null|array
* Returns null if no reply is necessary
* Returns the JSON-RPC 2.0 server reply as an array
*/
public function rawReply($input)
{
if (!is_string($json)) {
return false;
if (is_array($input)) {
$reply = $this->processInput($input);
} else {
$reply = $this->parseError();
}

$input = json_decode($json, true);

return is_array($input);
return $reply;
}

/**
Expand All @@ -94,7 +118,7 @@ private function getInput($json, &$input)
* Returns an array of response/error objects when multiple queries are made.
* Returns null when no response is necessary.
*/
private function processInput($input)
private function processInput(array $input)
{
if (count($input) === 0) {
return $this->requestError();
Expand Down

0 comments on commit ad4d735

Please sign in to comment.