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 self._provider = provider
73 @defer.inlineCallbacks
74 def render_POST(self, request):
75 # missing batching, 1.0 notifications
81 data = request.content.read()
84 req = json.loads(data)
86 raise Error(-32700, u'Parse error')
89 id_ = req.get('id', None)
90 method = req['method']
91 if not isinstance(method, basestring):
93 params = req.get('params', [])
94 if not isinstance(params, list):
97 raise Error(-32600, u'Invalid Request')
99 method_meth = getattr(self._provider, 'rpc_' + method, None)
100 if method_meth is None:
101 raise Error(-32601, u'Method not found')
103 result = yield method_meth(request, *params)
111 log.err(None, 'Squelched JSON error:')
112 raise Error(-32099, u'Unknown error')
117 data = json.dumps(dict(
123 request.setHeader('Content-Type', 'application/json')
124 request.setHeader('Content-Length', len(data))