summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorctrlaltca <>2012-08-30 20:04:53 +0000
committerctrlaltca <>2012-08-30 20:04:53 +0000
commit29af95f438d89e8b437640acf21b50efae3a57b5 (patch)
tree12ce462bc53372e3cfd089b3497b3b89b5de4060
parent1cd0bbc8cda0491baa46cf2a79c9e67e00c5245d (diff)
TJsonRpcProtocol: full support for both version 1.0 and 2.0 of the specifications
-rw-r--r--framework/Web/Services/TRpcService.php129
1 files changed, 102 insertions, 27 deletions
diff --git a/framework/Web/Services/TRpcService.php b/framework/Web/Services/TRpcService.php
index 06849ea1..8c8a6835 100644
--- a/framework/Web/Services/TRpcService.php
+++ b/framework/Web/Services/TRpcService.php
@@ -62,7 +62,7 @@ class TRpcService extends TService
if(($_providerClass = $_properties->remove('class')) === null)
throw new TConfigurationException('rpcservice_apiprovider_required');
- prado::using($_providerClass);
+ Prado::using($_providerClass);
$_providerClassName = ($_pos = strrpos($_providerClass, '.')) !== false ? substr($_providerClass, $_pos + 1) : $_providerClass;
if(!is_subclass_of($_providerClassName, self::BASE_API_PROVIDER))
@@ -71,7 +71,7 @@ class TRpcService extends TService
if(($_rpcServerClass = $_properties->remove('server')) === null)
$_rpcServerClass = self::BASE_RPC_SERVER;
- prado::using($_rpcServerClass);
+ Prado::using($_rpcServerClass);
$_rpcServerClassName = ($_pos = strrpos($_rpcServerClass, '.')) !== false ? substr($_rpcServerClass, $_pos + 1) : $_rpcServerClass;
if($_rpcServerClassName!==self::BASE_RPC_SERVER && !is_subclass_of($_rpcServerClassName, self::BASE_RPC_SERVER))
@@ -311,8 +311,11 @@ abstract class TRpcProtocol
if(!isset($this->rpcMethods[$methodName]))
throw new TRpcException('Method "'.$methodName.'" not found');
+ if($parameters === null)
+ $parameters = array();
+
if(!is_array($parameters))
- throw new TRpcException('Invalid parameters');
+ $parameters = array($parameters);
return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
}
}
@@ -323,14 +326,16 @@ abstract class TRpcProtocol
* Implements the JSON RPC protocol
*
* @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @author Fabio Bas <ctrlaltca@gmail.com>
* @version $Id$
* @package System.Web.Services
* @since 3.2
*/
class TJsonRpcProtocol extends TRpcProtocol
{
- // methods
- protected $_id=0;
+ protected $_id=null;
+ protected $_specificationVersion=1.0;
+
/**
* Handles the RPC request
* @param string $requestPayload
@@ -338,18 +343,50 @@ class TJsonRpcProtocol extends TRpcProtocol
*/
public function callMethod($requestPayload)
{
- $_request = $this->decode($requestPayload);
try
{
- if(!isset($_request['id']))
- throw new TRpcException('Missing mandatory request id');
-
- $this->_id=$_request['id'];
- return $this->encode(array(
- 'id' => $this->_id,
- 'result' => $this->callApiMethod($_request['method'], $_request['params']),
- 'error' => null
- ));
+ $_request = $this->decode($requestPayload);
+
+ if(isset($_request['jsonrpc']))
+ {
+ $this->_specificationVersion=$_request['jsonrpc'];
+ if($this->_specificationVersion > 2.0)
+ throw new TRpcException('Unsupported specification version', '-32600');
+ }
+
+ if(isset($_request['id']))
+ $this->_id=$_request['id'];
+
+ if(!isset($_request['method']))
+ throw new TRpcException('Missing request method', '-32600');
+
+ if(!isset($_request['params']))
+ $parameters = array();
+ else
+ $parameters = $_request['params'];
+
+ if(!is_array($parameters))
+ $parameters = array($parameters);
+
+ $ret = $this->callApiMethod($_request['method'], $parameters);
+ // a request without an id is a notification that doesn't need a response
+ if($this->_id !== null)
+ {
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'jsonrpc' => '2.0',
+ 'id' => $this->_id,
+ 'result' => $ret
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => $this->callApiMethod($_request['method'], $_request['params']),
+ 'error' => null
+ ));
+ }
+ }
}
catch(TRpcException $e)
{
@@ -361,7 +398,7 @@ class TJsonRpcProtocol extends TRpcProtocol
}
catch(Exception $e)
{
- return $this->createErrorResponse(new TRpcException('An internal error occured'));
+ return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603'));
}
}
@@ -372,15 +409,27 @@ class TJsonRpcProtocol extends TRpcProtocol
*/
public function createErrorResponse(TRpcException $exception)
{
- return $this->encode(array(
- 'id' => $this->_id,
- 'result' => null,
- 'error'=> array(
- 'code' => $exception->getCode(),
- 'message'=> $exception->getMessage(),
- 'data' => null,
- )
- ));
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => null,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ }
}
/**
@@ -400,7 +449,9 @@ class TJsonRpcProtocol extends TRpcProtocol
*/
public function decode($data)
{
- return json_decode($data, true);
+ $s = json_decode($data, true);
+ self::checkJsonError();
+ return $s;
}
/**
@@ -410,7 +461,31 @@ class TJsonRpcProtocol extends TRpcProtocol
*/
public function encode($data)
{
- return json_encode($data);
+ $s = json_encode($data);
+ self::checkJsonError();
+ return $s;
+ }
+
+ private static function checkJsonError()
+ {
+ $errnum = json_last_error();
+ if($errnum != JSON_ERROR_NONE)
+ throw new Exception("JSON error: $msg", $err);
+ }
+
+ /**
+ * Calls the callback handler for the given method
+ * Overrides parent implementation to correctly handle error codes
+ * @param string $methodName of the RPC
+ * @param array $parameters for the callback handler as provided by the client
+ * @return mixed whatever the callback handler returns
+ */
+ public function callApiMethod($methodName, $parameters)
+ {
+ if(!isset($this->rpcMethods[$methodName]))
+ throw new TRpcException('Method "'.$methodName.'" not found', '-32601');
+
+ return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
}
}