Source code for concurrent.core.transport.pyjsonrpc.rpclib
#!/usr/bin/env python
# coding: utf-8
import sys
import traceback
import rpcrequest
import rpcresponse
import rpcerror
from rpcjson import json
[docs]class JsonRpc(object):
"""
JSON-RPC
"""
def __init__(self, methods = None):
"""
Initializes the JSON-RPC-Class
:param methods: Json-RPC-Methods. `None` or dictionary with
method names as keys and functions as values. Syntax::
{
"<method_name>": <method_function>,
...
}
"""
self.methods = methods or {}
self.methods["system.describe"] = self.system_describe
[docs] def call(self, json_request):
"""
Parses the *json_request*, calls the function(s)
and returns the *json_response*.
:param json_request: JSON-RPC-string with one or more JSON-RPC-requests
:return: JSON-RPC-string with one or more responses.
"""
# List for the responses
responses = []
# List with requests
requests = rpcrequest.parse_request_json(json_request)
if not isinstance(requests, list):
requests = [requests]
# Every JSON-RPC request in a batch of requests
for request in requests:
# Request-Data
jsonrpc = request.jsonrpc
id = request.id
method = request.get("method", "")
if not method in self.methods:
# Method not found error
responses.append(
rpcresponse.Response(
jsonrpc = jsonrpc,
id = id,
error = rpcerror.MethodNotFound(
data = u"Method name: '%s'" % method
)
)
)
continue
# split positional and named params
positional_params, named_params = request.get_splitted_params()
# Call the method with parameters
try:
rpc_function = self.methods[method]
result = rpc_function(*positional_params, **named_params)
# No return value is OK if we donĀ“t have an ID (=notification)
if result is None:
if id:
responses.append(
rpcresponse.Response(
jsonrpc = jsonrpc,
id = id,
error = rpcerror.InternalError(
data = u"No result from JSON-RPC method."
)
)
)
else:
# Successful response
responses.append(
rpcresponse.Response(jsonrpc = jsonrpc, id = id, result = result)
)
except TypeError, err:
traceback_info = "".join(traceback.format_exception(*sys.exc_info()))
if "takes exactly" in unicode(err) and "arguments" in unicode(err):
responses.append(
rpcresponse.Response(
jsonrpc = jsonrpc,
id = id,
error = rpcerror.InvalidParams(data = traceback_info)
)
)
else:
responses.append(
rpcresponse.Response(
jsonrpc = jsonrpc,
id = id,
error = rpcerror.InternalError(data = traceback_info)
)
)
except BaseException, err:
traceback_info = "".join(traceback.format_exception(*sys.exc_info()))
if hasattr(err, "data"):
error_data = err.data
else:
error_data = None
responses.append(
rpcresponse.Response(
jsonrpc = jsonrpc,
id = id,
error = rpcerror.InternalError(
data = error_data or traceback_info
)
)
)
# Convert responses to dictionaries
responses_ = []
for response in responses:
responses_.append(response.to_dict())
responses = responses_
# Return as JSON-string (batch or normal)
if len(requests) == 1:
return json.dumps(responses[0])
elif len(requests) > 1:
return json.dumps(responses)
else:
return None
def __call__(self, json_request):
"""
Redirects the requests to *self.call*
"""
return self.call(json_request)
def __getitem__(self, key):
"""
Gets back the requested method
"""
return self.methods[key]
def __setitem__(self, key, value):
"""
Appends or replaces a method
"""
self.methods[key] = value
def __delitem__(self, key):
"""
Deletes a method
"""
del self.methods[key]
[docs] def system_describe(self):
"""
Returns a system description
See: http://web.archive.org/web/20100718181845/http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#ServiceDescription
"""
# ToDo: not finished yet
return u"[not finished]"