jsonrpc 2.0 added to services.
This commit is contained in:
+129
@@ -3948,6 +3948,7 @@ class Service(object):
|
|||||||
self.rss_procedures = {}
|
self.rss_procedures = {}
|
||||||
self.json_procedures = {}
|
self.json_procedures = {}
|
||||||
self.jsonrpc_procedures = {}
|
self.jsonrpc_procedures = {}
|
||||||
|
self.jsonrpc2_procedures = {}
|
||||||
self.xmlrpc_procedures = {}
|
self.xmlrpc_procedures = {}
|
||||||
self.amfrpc_procedures = {}
|
self.amfrpc_procedures = {}
|
||||||
self.amfrpc3_procedures = {}
|
self.amfrpc3_procedures = {}
|
||||||
@@ -4069,6 +4070,25 @@ class Service(object):
|
|||||||
self.jsonrpc_procedures[f.__name__] = f
|
self.jsonrpc_procedures[f.__name__] = f
|
||||||
return 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):
|
def xmlrpc(self, f):
|
||||||
"""
|
"""
|
||||||
example:
|
example:
|
||||||
@@ -4250,8 +4270,21 @@ class Service(object):
|
|||||||
|
|
||||||
class JsonRpcException(Exception):
|
class JsonRpcException(Exception):
|
||||||
def __init__(self, code, info):
|
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
|
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 serve_jsonrpc(self):
|
||||||
def return_response(id, result):
|
def return_response(id, result):
|
||||||
return serializers.json({'version': '1.1',
|
return serializers.json({'version': '1.1',
|
||||||
@@ -4272,6 +4305,9 @@ class Service(object):
|
|||||||
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||||
methods = self.jsonrpc_procedures
|
methods = self.jsonrpc_procedures
|
||||||
data = json_parser.loads(request.body.read())
|
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', '')
|
id, method, params = data['id'], data['method'], data.get('params', '')
|
||||||
if not method in methods:
|
if not method in methods:
|
||||||
return return_error(id, 100, 'method "%s" does not exist' % method)
|
return return_error(id, 100, 'method "%s" does not exist' % method)
|
||||||
@@ -4295,6 +4331,97 @@ class Service(object):
|
|||||||
etype, eval, etb = sys.exc_info()
|
etype, eval, etb = sys.exc_info()
|
||||||
return return_error(id, 100, 'Exception %s: %s' % (etype, eval))
|
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):
|
def serve_xmlrpc(self):
|
||||||
request = current.request
|
request = current.request
|
||||||
response = current.response
|
response = current.response
|
||||||
@@ -4438,6 +4565,8 @@ class Service(object):
|
|||||||
return self.serve_json(request.args[1:])
|
return self.serve_json(request.args[1:])
|
||||||
elif arg0 == 'jsonrpc':
|
elif arg0 == 'jsonrpc':
|
||||||
return self.serve_jsonrpc()
|
return self.serve_jsonrpc()
|
||||||
|
elif arg0 == 'jsonrpc2':
|
||||||
|
return self.serve_jsonrpc2()
|
||||||
elif arg0 == 'xmlrpc':
|
elif arg0 == 'xmlrpc':
|
||||||
return self.serve_xmlrpc()
|
return self.serve_xmlrpc()
|
||||||
elif arg0 == 'amfrpc':
|
elif arg0 == 'amfrpc':
|
||||||
|
|||||||
Reference in New Issue
Block a user