jsonrpc 2.0 added to services.
This commit is contained in:
+129
@@ -3948,6 +3948,7 @@ class Service(object):
|
||||
self.rss_procedures = {}
|
||||
self.json_procedures = {}
|
||||
self.jsonrpc_procedures = {}
|
||||
self.jsonrpc2_procedures = {}
|
||||
self.xmlrpc_procedures = {}
|
||||
self.amfrpc_procedures = {}
|
||||
self.amfrpc3_procedures = {}
|
||||
@@ -4069,6 +4070,25 @@ class Service(object):
|
||||
self.jsonrpc_procedures[f.__name__] = f
|
||||
return f
|
||||
|
||||
def jsonrpc2(self, f):
|
||||
"""
|
||||
example:
|
||||
|
||||
service = Service()
|
||||
@service.jsonrpc2
|
||||
def myfunction(a, b):
|
||||
return a + b
|
||||
def call():
|
||||
return service()
|
||||
|
||||
Then call it with:
|
||||
|
||||
wget --post-data '{"jsonrpc": "2.0", "id": 1, "method": "mymethod", "params": {"param1": "val1", "param2": "val2"}}' http://..../app/default/call/jsonrpc2/myfunction
|
||||
|
||||
"""
|
||||
self.jsonrpc2_procedures[f.__name__] = f
|
||||
return f
|
||||
|
||||
def xmlrpc(self, f):
|
||||
"""
|
||||
example:
|
||||
@@ -4250,8 +4270,21 @@ class Service(object):
|
||||
|
||||
class JsonRpcException(Exception):
|
||||
def __init__(self, code, info):
|
||||
jrpc_error = Service.jsonrpc_errors.get(code)
|
||||
if jrpc_error:
|
||||
self.message, self.description = jrpc_error
|
||||
self.code, self.info = code, info
|
||||
|
||||
# jsonrpc 2.0 error types. records the following structure {code: (message,meaning)}
|
||||
jsonrpc_errors = {
|
||||
-32700: ("Parse error. Invalid JSON was received by the server.", "An error occurred on the server while parsing the JSON text."),
|
||||
-32600: ("Invalid Request", "The JSON sent is not a valid Request object."),
|
||||
-32601: ("Method not found", "The method does not exist / is not available."),
|
||||
-32602: ("Invalid params", "Invalid method parameter(s)."),
|
||||
-32603: ("Internal error", "Internal JSON-RPC error."),
|
||||
-32099: ("Server error", "Reserved for implementation-defined server-errors.")}
|
||||
|
||||
|
||||
def serve_jsonrpc(self):
|
||||
def return_response(id, result):
|
||||
return serializers.json({'version': '1.1',
|
||||
@@ -4272,6 +4305,9 @@ class Service(object):
|
||||
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||
methods = self.jsonrpc_procedures
|
||||
data = json_parser.loads(request.body.read())
|
||||
jsonrpc_2 = dataget('jsonrpc')
|
||||
if jsonrpc_2: #hand over to version 2 of the protocol
|
||||
self.serve_jsonrpc2(data)
|
||||
id, method, params = data['id'], data['method'], data.get('params', '')
|
||||
if not method in methods:
|
||||
return return_error(id, 100, 'method "%s" does not exist' % method)
|
||||
@@ -4295,6 +4331,97 @@ class Service(object):
|
||||
etype, eval, etb = sys.exc_info()
|
||||
return return_error(id, 100, 'Exception %s: %s' % (etype, eval))
|
||||
|
||||
def serve_jsonrpc2(self, data=None):
|
||||
|
||||
def return_response(id, result):
|
||||
if not must_respond:
|
||||
return None
|
||||
return serializers.json({'jsonrpc': '2.0',
|
||||
'id': id, 'result': result})
|
||||
|
||||
def return_error(id, code, message=None, data=None):
|
||||
error = {'code': code}
|
||||
if message is None:
|
||||
error['message'] = Service.jsonrpc_errors[code][0]
|
||||
else:
|
||||
error['message'] = message
|
||||
if data is None:
|
||||
error['data'] = Service.jsonrpc_errors[code][1]
|
||||
else:
|
||||
error['data'] = data
|
||||
return serializers.json({'jsonrpc': '2.0',
|
||||
'id': id,
|
||||
'error': error})
|
||||
|
||||
def validate(data):
|
||||
"""
|
||||
Validate request as defined in: http://www.jsonrpc.org/specification#request_object.
|
||||
|
||||
:param data: The json object.
|
||||
:type name: str.
|
||||
|
||||
:returns:
|
||||
- True -- if successful
|
||||
- False -- if no error should be reported (i.e. data is missing 'id' member)
|
||||
|
||||
:raises: JsonRPCException
|
||||
|
||||
"""
|
||||
|
||||
iparms = set(data.keys())
|
||||
mandatory_args = set(['jsonrpc', 'method'])
|
||||
missing_args = mandatory_args - iparms
|
||||
|
||||
if missing_args:
|
||||
raise Service.JsonRpcException(-32600, 'Missing arguments %s.' % list(missing_args))
|
||||
if data['jsonrpc'] != '2.0':
|
||||
raise Service.JsonRpcException(-32603, 'Unsupported jsonrpc version "%s"' % data['jsonrpc'])
|
||||
if 'id' not in iparms:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
if not data:
|
||||
request = current.request
|
||||
response = current.response
|
||||
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||
methods = self.jsonrpc2_procedures
|
||||
try:
|
||||
data = json_parser.loads(request.body.read())
|
||||
except ValueError: # decoding error in json lib
|
||||
return return_error(None, -32700)
|
||||
except json_parser.JSONDecodeError: # decoding error in simplejson lib
|
||||
return return_error(None, -32700)
|
||||
try:
|
||||
must_respond = validate(data)
|
||||
except Service.JsonRpcException, e:
|
||||
return return_error(None, e.code, e.info)
|
||||
|
||||
id, method, params = data['id'], data['method'], data.get('params', '')
|
||||
if not method in methods:
|
||||
return return_error(id, -32601, data='Method "%s" does not exist' % method)
|
||||
try:
|
||||
if isinstance(params,dict):
|
||||
s = methods[method](**params)
|
||||
else:
|
||||
s = methods[method](*params)
|
||||
if hasattr(s, 'as_list'):
|
||||
s = s.as_list()
|
||||
return return_response(id, s)
|
||||
except Service.JsonRpcException, e:
|
||||
return return_error(id, e.code, e.info)
|
||||
except BaseException:
|
||||
etype, eval, etb = sys.exc_info()
|
||||
code = -32001
|
||||
data = '%s: %s\n' % (etype.__name__, eval) + request.is_local and traceback.format_tb(etb)
|
||||
return return_error(id, code, data=data)
|
||||
except:
|
||||
etype, eval, etb = sys.exc_info()
|
||||
return return_error(id, 32099, data='Exception %s: %s' % (etype, eval))
|
||||
|
||||
|
||||
def serve_xmlrpc(self):
|
||||
request = current.request
|
||||
response = current.response
|
||||
@@ -4438,6 +4565,8 @@ class Service(object):
|
||||
return self.serve_json(request.args[1:])
|
||||
elif arg0 == 'jsonrpc':
|
||||
return self.serve_jsonrpc()
|
||||
elif arg0 == 'jsonrpc2':
|
||||
return self.serve_jsonrpc2()
|
||||
elif arg0 == 'xmlrpc':
|
||||
return self.serve_xmlrpc()
|
||||
elif arg0 == 'amfrpc':
|
||||
|
||||
Reference in New Issue
Block a user