1 from __future__ import division
6 from twisted.internet import defer
7 from twisted.python import log
8 from twisted.web import client, error
10 from p2pool.util import deferred_resource, memoize
12 class Error(Exception):
13 def __init__(self, code, message, data=None):
14 if type(self) is Error:
15 raise TypeError("can't directly instantiate Error class; use Error_for_code")
16 if not isinstance(code, int):
17 raise TypeError('code must be an int')
18 #if not isinstance(message, unicode):
19 # raise TypeError('message must be a unicode')
20 self.code, self.message, self.data = code, message, data
22 return '%i %s' % (self.code, self.message) + (' %r' % (self.data, ) if self.data is not None else '')
26 'message': self.message,
30 @memoize.memoize_with_backing(weakref.WeakValueDictionary())
31 def Error_for_code(code):
32 class NarrowError(Error):
33 def __init__(self, *args, **kwargs):
34 Error.__init__(self, code, *args, **kwargs)
38 def __init__(self, url, headers={}, timeout=5):
40 self._headers = headers
41 self._timeout = timeout
43 @defer.inlineCallbacks
44 def callRemote(self, method, *params):
48 data = yield client.getPage(
51 headers=dict(self._headers, **{'Content-Type': 'application/json'}),
58 timeout=self._timeout,
60 except error.Error, e:
62 resp = json.loads(e.response)
66 resp = json.loads(data)
69 raise ValueError('invalid id')
70 if 'error' in resp and resp['error'] is not None:
71 raise Error_for_code(resp['error']['code'])(resp['error']['message'], resp['error'].get('data', None))
72 defer.returnValue(resp['result'])
74 def __getattr__(self, attr):
75 if attr.startswith('rpc_'):
76 return lambda *params: self.callRemote(attr[len('rpc_'):], *params)
77 raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, attr))
79 class Server(deferred_resource.DeferredResource):
80 def __init__(self, provider):
81 deferred_resource.DeferredResource.__init__(self)
82 self._provider = provider
84 @defer.inlineCallbacks
85 def render_POST(self, request):
90 data = request.content.read()
93 req = json.loads(data)
95 raise Error_for_code(-32700)(u'Parse error')
97 id_ = req.get('id', None)
98 method = req.get('method', None)
99 if not isinstance(method, basestring):
100 raise Error_for_code(-32600)(u'Invalid Request')
101 params = req.get('params', [])
102 if not isinstance(params, list):
103 raise Error_for_code(-32600)(u'Invalid Request')
105 method_meth = getattr(self._provider, 'rpc_' + method, None)
106 if method_meth is None:
107 raise Error_for_code(-32601)(u'Method not found')
109 result = yield method_meth(request, *params)
114 log.err(None, 'Squelched JSON error:')
115 raise Error_for_code(-32099)(u'Unknown error')
120 data = json.dumps(dict(
126 request.setHeader('Content-Type', 'application/json')
127 request.setHeader('Content-Length', len(data))