blob: 70ef6cdf35a8f1e26bd9e65d5512d1d24614c4c8 [file] [log] [blame]
"""\
RPC request handler Django. Exposed RPC interface functions should be
defined in rpc_interface.py.
"""
__author__ = 'showard@google.com (Steve Howard)'
import django.http
import traceback, pydoc
from frontend.afe.json_rpc import serviceHandler
from frontend.afe import rpc_utils
class RpcMethodHolder(object):
'Dummy class to hold RPC interface methods as attributes.'
class RpcHandler(object):
def __init__(self, rpc_interface_modules, document_module=None):
self._rpc_methods = RpcMethodHolder()
self._dispatcher = serviceHandler.ServiceHandler(
self._rpc_methods)
# store all methods from interface modules
for module in rpc_interface_modules:
self._grab_methods_from(module)
# get documentation for rpc_interface we can send back to the
# user
if document_module is None:
document_module = rpc_interface_modules[0]
self.html_doc = pydoc.html.document(document_module)
def handle_rpc_request(self, request):
response = django.http.HttpResponse()
if len(request.POST):
response.write(self._dispatcher.handleRequest(
request.raw_post_data))
else:
response.write(self.html_doc)
response['Content-length'] = str(len(response.content))
return response
@staticmethod
def _allow_keyword_args(f):
"""\
Decorator to allow a function to take keyword args even though
the RPC layer doesn't support that. The decorated function
assumes its last argument is a dictionary of keyword args and
passes them to the original function as keyword args.
"""
def new_fn(*args):
assert args
keyword_args = args[-1]
args = args[:-1]
return f(*args, **keyword_args)
new_fn.func_name = f.func_name
return new_fn
def _grab_methods_from(self, module):
for name in dir(module):
attribute = getattr(module, name)
if not callable(attribute):
continue
decorated_function = (
RpcHandler._allow_keyword_args(attribute))
setattr(self._rpc_methods, name, decorated_function)