0
|
1 from webob import Request, Response, exc
|
|
2 try:
|
|
3 from json import loads, dumps
|
|
4 except:
|
|
5 from simplejson import loads, dumps
|
|
6 import traceback
|
|
7 import sys
|
|
8
|
|
9 class JsonRpcApp(object):
|
|
10 """
|
|
11 Serve the given object via json-rpc (http://json-rpc.org/)
|
|
12 """
|
|
13
|
|
14 def __init__(self, obj, auth=None):
|
|
15 """
|
|
16 obj - a class of functions available using jsonrpc
|
|
17 auth - an authentication function (optional)
|
|
18 """
|
|
19 self.obj = obj
|
|
20 self.auth = auth
|
|
21
|
|
22 def __call__(self, environ, start_response):
|
|
23 req = Request(environ)
|
|
24 try:
|
|
25 resp = self.process(req)
|
|
26 except ValueError, e:
|
|
27 resp = exc.HTTPBadRequest(str(e))
|
|
28 except exc.HTTPException, e:
|
|
29 resp = e
|
|
30 return resp(environ, start_response)
|
|
31
|
|
32 def process(self, req):
|
|
33 if not req.method == 'POST':
|
|
34 raise exc.HTTPMethodNotAllowed("Only POST allowed").exception
|
|
35
|
|
36 try:
|
|
37 json = loads(req.body)
|
|
38 except ValueError, e:
|
|
39 raise ValueError('Bad JSON: %s' % e)
|
|
40
|
|
41 try:
|
|
42 method = json['method']
|
|
43 params = json['params']
|
|
44 id = json['id']
|
|
45 username = json['username'] if 'username' in json else None
|
|
46 password = json['password'] if 'password' in json else None
|
|
47 except KeyError, e:
|
|
48 raise ValueError("JSON body missing parameter: %s" % e)
|
|
49
|
|
50 if params is None:
|
|
51 params = []
|
|
52 if not isinstance(params, list):
|
|
53 raise ValueError("Bad params %r: must be a list" % params)
|
|
54 text = traceback.format_exc()
|
|
55 exc_value = sys.exc_info()[1]
|
|
56 error_value = dict(
|
|
57 name='JSONRPCError',
|
|
58 code=100,
|
|
59 message=str(exc_value),
|
|
60 error=text)
|
|
61 return Response(
|
|
62 status=500,
|
|
63 content_type='application/json',
|
|
64 body=dumps(dict(result=None,
|
|
65 error=error_value,
|
|
66 id=id)))
|
|
67
|
|
68 obj = self.obj
|
|
69 if isinstance(self.obj,tuple) or isinstance(self.obj,list):
|
|
70 for x in self.obj:
|
|
71 if method.startswith('%s.'%x.__class__.__name__):
|
|
72 obj = x
|
|
73 method = method.replace('%s.'%obj.__class__.__name__,'',1)
|
|
74 break
|
|
75 elif method.startswith('%s.'%self.obj.__class__.__name__):
|
|
76 method = method.replace('%s.'%self.obj.__class__.__name__,'',1)
|
|
77 if method.startswith('_'):
|
|
78 raise exc.HTTPForbidden("Bad method name %s: must not start with _" % method).exception
|
|
79 try:
|
|
80 method = getattr(obj, method)
|
|
81 except AttributeError:
|
|
82 raise ValueError("No such method %s" % method)
|
|
83
|
|
84 if self.auth is not None:
|
|
85 try:
|
|
86 auth_result = self.auth(username, password, req.user_agent)
|
|
87 except:
|
|
88 text = traceback.format_exc()
|
|
89 exc_value = sys.exc_info()[1]
|
|
90 error_value = dict(
|
|
91 name='JSONRPCError',
|
|
92 code=100,
|
|
93 message=str(exc_value),
|
|
94 error=text)
|
|
95 return Response(
|
|
96 status=500,
|
|
97 content_type='application/json',
|
|
98 body=dumps(dict(result=None,
|
|
99 error=error_value,
|
|
100 id=id)))
|
|
101 if not auth_result:
|
|
102 raise exc.HTTPUnauthorized().exception
|
|
103
|
|
104 try:
|
|
105 result = method(*params)
|
|
106 except:
|
|
107 text = traceback.format_exc()
|
|
108 exc_value = sys.exc_info()[1]
|
|
109 error_value = dict(
|
|
110 name='JSONRPCError',
|
|
111 code=100,
|
|
112 message=str(exc_value),
|
|
113 error=text)
|
|
114 return Response(
|
|
115 status=500,
|
|
116 content_type='application/json',
|
|
117 body=dumps(dict(result=None,
|
|
118 error=error_value,
|
|
119 id=id)))
|
|
120
|
|
121 return Response(
|
|
122 content_type='application/json',
|
|
123 body=dumps(dict(result=result,
|
|
124 error=None,
|
|
125 id=id)))
|
|
126
|