comparison server/JsonRpcApp.py @ 2:c7a236de5214

-
author Ben Croston <ben@croston.org>
date Tue, 30 Aug 2011 23:37:53 +0100
parents wibble/server/JsonRpcApp.py@6a61cfdf6930
children
comparison
equal deleted inserted replaced
1:317e6f82c733 2:c7a236de5214
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