jsonrpc 2.0 added to services.

This commit is contained in:
Michele Comitini
2013-01-19 18:32:17 +01:00
parent e5a8319f0b
commit 6a497b3894
+129
View File
@@ -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':