1 from __future__ import division
5 from twisted.internet import defer
6 from twisted.python import log
7 from twisted.web import client, error
9 import deferred_resource
11 class Error(Exception):
12 def __init__(self, code, message, data=None):
13 if not isinstance(code, int):
14 raise TypeError('code must be an int')
15 #if not isinstance(message, unicode):
16 # raise TypeError('message must be a unicode')
17 self.code, self.message, self.data = code, message, data
19 return '%i %s' % (self.code, self.message) + (' %r' % (self.data, ) if self.data is not None else '')
23 'message': self.message,
28 def __init__(self, url, headers={}, timeout=5):
30 self._headers = headers
31 self._timeout = timeout
33 @defer.inlineCallbacks
34 def callRemote(self, method, *params):
38 data = yield client.getPage(
41 headers=dict(self._headers, **{'Content-Type': 'application/json'}),
48 timeout=self._timeout,
50 except error.Error, e:
52 resp = json.loads(e.response)
56 resp = json.loads(data)
59 raise ValueError('invalid id')
60 if 'error' in resp and resp['error'] is not None:
61 raise Error(**resp['error'])
62 defer.returnValue(resp['result'])
64 def __getattr__(self, attr):
65 if attr.startswith('rpc_'):
66 return lambda *params: self.callRemote(attr[len('rpc_'):], *params)
67 raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, attr))
69 class Server(deferred_resource.DeferredResource):
70 def __init__(self, provider):
71 deferred_resource.DeferredResource.__init__(self)
72 self._provider = provider
74 @defer.inlineCallbacks
75 def render_POST(self, request):
80 data = request.content.read()
83 req = json.loads(data)
85 raise Error(-32700, u'Parse error')
87 id_ = req.get('id', None)
88 method = req.get('method', None)
89 if not isinstance(method, basestring):
90 raise Error(-32600, u'Invalid Request')
91 params = req.get('params', [])
92 if not isinstance(params, list):
93 raise Error(-32600, u'Invalid Request')
95 method_meth = getattr(self._provider, 'rpc_' + method, None)
96 if method_meth is None:
97 raise Error(-32601, u'Method not found')
99 result = yield method_meth(request, *params)
104 log.err(None, 'Squelched JSON error:')
105 raise Error(-32099, u'Unknown error')
110 data = json.dumps(dict(
116 request.setHeader('Content-Type', 'application/json')
117 request.setHeader('Content-Length', len(data))