blob: 56202bcd0a6c8236cda6fcea95ce4e08d8fafdfd [file] [log] [blame]
mblighe8819cd2008-02-15 16:48:40 +00001"""\
2RPC request handler Django. Exposed RPC interface functions should be
3defined in rpc_interface.py.
4"""
5
6__author__ = 'showard@google.com (Steve Howard)'
7
showardef6fe022009-03-27 20:55:16 +00008import traceback, pydoc, re, urllib
mblighe8819cd2008-02-15 16:48:40 +00009from frontend.afe.json_rpc import serviceHandler
showard7c785282008-05-29 19:45:12 +000010from frontend.afe import rpc_utils
mblighe8819cd2008-02-15 16:48:40 +000011
mblighe8819cd2008-02-15 16:48:40 +000012
13class RpcMethodHolder(object):
jadmanski0afbb632008-06-06 21:10:57 +000014 'Dummy class to hold RPC interface methods as attributes.'
mblighe8819cd2008-02-15 16:48:40 +000015
16
showard7c785282008-05-29 19:45:12 +000017class RpcHandler(object):
jadmanski0afbb632008-06-06 21:10:57 +000018 def __init__(self, rpc_interface_modules, document_module=None):
19 self._rpc_methods = RpcMethodHolder()
showardef6fe022009-03-27 20:55:16 +000020 self._dispatcher = serviceHandler.ServiceHandler(self._rpc_methods)
mblighe8819cd2008-02-15 16:48:40 +000021
jadmanski0afbb632008-06-06 21:10:57 +000022 # store all methods from interface modules
23 for module in rpc_interface_modules:
24 self._grab_methods_from(module)
showard7c785282008-05-29 19:45:12 +000025
jadmanski0afbb632008-06-06 21:10:57 +000026 # get documentation for rpc_interface we can send back to the
27 # user
28 if document_module is None:
29 document_module = rpc_interface_modules[0]
30 self.html_doc = pydoc.html.document(document_module)
showard7c785282008-05-29 19:45:12 +000031
32
showardef6fe022009-03-27 20:55:16 +000033 def get_rpc_documentation(self):
showard2d7ac832009-06-22 18:14:10 +000034 return rpc_utils.raw_http_response(self.html_doc)
showardef6fe022009-03-27 20:55:16 +000035
36
showard3d6ae112009-05-02 00:45:48 +000037 def raw_request_data(self, request):
showardef6fe022009-03-27 20:55:16 +000038 if request.method == 'POST':
39 return request.raw_post_data
40 return urllib.unquote(request.META['QUERY_STRING'])
41
42
showard3d6ae112009-05-02 00:45:48 +000043 def execute_request(self, json_request):
44 return self._dispatcher.handleRequest(json_request)
45
46
47 def decode_request(self, json_request):
48 return self._dispatcher.translateRequest(json_request)
49
50
51 def dispatch_request(self, decoded_request):
52 return self._dispatcher.dispatchRequest(decoded_request)
53
54
showardef6fe022009-03-27 20:55:16 +000055 def handle_rpc_request(self, request):
showard3d6ae112009-05-02 00:45:48 +000056 json_request = self.raw_request_data(request)
57 result = self.execute_request(json_request)
58 return rpc_utils.raw_http_response(result)
showardef6fe022009-03-27 20:55:16 +000059
60
61 def handle_jsonp_rpc_request(self, request):
62 request_data = request.GET['request']
63 callback_name = request.GET['callback']
64 # callback_name must be a simple identifier
65 assert re.search(r'^\w+$', callback_name)
66
showard3d6ae112009-05-02 00:45:48 +000067 result = self.execute_request(request_data)
showardef6fe022009-03-27 20:55:16 +000068 padded_result = '%s(%s)' % (callback_name, result)
showard3d6ae112009-05-02 00:45:48 +000069 return rpc_utils.raw_http_response(padded_result,
70 content_type='text/javascript')
showardef6fe022009-03-27 20:55:16 +000071
72
jadmanski0afbb632008-06-06 21:10:57 +000073 @staticmethod
74 def _allow_keyword_args(f):
75 """\
76 Decorator to allow a function to take keyword args even though
77 the RPC layer doesn't support that. The decorated function
78 assumes its last argument is a dictionary of keyword args and
79 passes them to the original function as keyword args.
80 """
81 def new_fn(*args):
82 assert args
83 keyword_args = args[-1]
84 args = args[:-1]
85 return f(*args, **keyword_args)
86 new_fn.func_name = f.func_name
87 return new_fn
showard7c785282008-05-29 19:45:12 +000088
89
jadmanski0afbb632008-06-06 21:10:57 +000090 def _grab_methods_from(self, module):
91 for name in dir(module):
92 attribute = getattr(module, name)
93 if not callable(attribute):
94 continue
showardef6fe022009-03-27 20:55:16 +000095 decorated_function = RpcHandler._allow_keyword_args(attribute)
jadmanski0afbb632008-06-06 21:10:57 +000096 setattr(self._rpc_methods, name, decorated_function)