3 Copyright 2011 Jeff Garzik 5 AuthServiceProxy has the following improvements over python-jsonrpc's 8 - HTTP connections persist for the life of the AuthServiceProxy object 9 (if server supports HTTP/1.1) 10 - sends protocol 'version', per JSON-RPC 1.1 11 - sends proper, incrementing 'id' 12 - sends Basic HTTP authentication headers 13 - parses all JSON numbers that look like floats as Decimal 14 - uses standard Python json lib 16 Previous copyright, from python-jsonrpc/jsonrpc/proxy.py: 18 Copyright (c) 2007 Jan-Klaas Kollhof 20 This file is part of jsonrpc. 22 jsonrpc is free software; you can redistribute it and/or modify 23 it under the terms of the GNU Lesser General Public License as published by 24 the Free Software Foundation; either version 2.1 of the License, or 25 (at your option) any later version. 27 This software is distributed in the hope that it will be useful, 28 but WITHOUT ANY WARRANTY; without even the implied warranty of 29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 GNU Lesser General Public License for more details. 32 You should have received a copy of the GNU Lesser General Public License 33 along with this software; if not, write to the Free Software 34 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 38 import http.client
as httplib
46 import urllib.parse
as urlparse
50 USER_AGENT =
"AuthServiceProxy/0.1" 54 log = logging.getLogger(
"BitcoinRPC")
58 Exception.__init__(self)
63 if isinstance(o, decimal.Decimal):
65 raise TypeError(repr(o) +
" is not JSON serializable")
71 def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True):
75 self.
__url = urlparse.urlparse(service_url)
76 if self.
__url.port
is None:
79 port = self.
__url.port
80 (user, passwd) = (self.
__url.username, self.
__url.password)
82 user = user.encode(
'utf8')
83 except AttributeError:
86 passwd = passwd.encode(
'utf8')
87 except AttributeError:
89 authpair = user + b
':' + passwd
95 elif self.
__url.scheme ==
'https':
96 self.
__conn = httplib.HTTPSConnection(self.
__url.hostname, port,
99 self.
__conn = httplib.HTTPConnection(self.
__url.hostname, port,
103 if name.startswith(
'__')
and name.endswith(
'__'):
112 Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout). 113 This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5. 115 headers = {
'Host': self.
__url.hostname,
116 'User-Agent': USER_AGENT,
118 'Content-type':
'application/json'}
120 self.
__conn.request(method, path, postdata, headers)
122 except httplib.BadStatusLine
as e:
125 self.
__conn.request(method, path, postdata, headers)
131 AuthServiceProxy.__id_count += 1
133 log.debug(
"-%s-> %s %s"%(AuthServiceProxy.__id_count, self.
_service_name,
134 json.dumps(args, default=EncodeDecimal, ensure_ascii=self.
ensure_ascii)))
135 postdata = json.dumps({
'version':
'1.1',
138 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.
ensure_ascii)
139 response = self.
_request(
'POST', self.
__url.path, postdata.encode(
'utf-8'))
140 if response[
'error']
is not None:
142 elif 'result' not in response:
144 'code': -343,
'message':
'missing JSON-RPC result'})
146 return response[
'result']
149 postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.
ensure_ascii)
150 log.debug(
"--> "+postdata)
151 return self.
_request(
'POST', self.
__url.path, postdata.encode(
'utf-8'))
154 http_response = self.
__conn.getresponse()
155 if http_response
is None:
157 'code': -342,
'message':
'missing HTTP response from server'})
159 content_type = http_response.getheader(
'Content-Type')
160 if content_type !=
'application/json':
162 'code': -342,
'message':
'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)})
164 responsedata = http_response.read().decode(
'utf8')
165 response = json.loads(responsedata, parse_float=decimal.Decimal)
166 if "error" in response
and response[
"error"]
is None:
167 log.debug(
"<-%s- %s"%(response[
"id"], json.dumps(response[
"result"], default=EncodeDecimal, ensure_ascii=self.
ensure_ascii)))
169 log.debug(
"<-- "+responsedata)
def _batch(self, rpc_call_list)
def __init__(self, rpc_error)
def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True)
def __getattr__(self, name)
def _request(self, method, path, postdata)