proxy.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. """
  2. Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
  3. Added http_timeout from mmgen.config
  4. Previous copyright from bitcoin-python/proxy.py:
  5. Copyright 2011 Jeff Garzik
  6. AuthServiceProxy has the following improvements over python-jsonrpc's
  7. ServiceProxy class:
  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
  15. Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
  16. Copyright (c) 2007 Jan-Klaas Kollhof
  17. This file is part of jsonrpc.
  18. jsonrpc is free software; you can redistribute it and/or modify
  19. it under the terms of the GNU Lesser General Public License as published by
  20. the Free Software Foundation; either version 2.1 of the License, or
  21. (at your option) any later version.
  22. This software is distributed in the hope that it will be useful,
  23. but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. GNU Lesser General Public License for more details.
  26. You should have received a copy of the GNU Lesser General Public License
  27. along with this software; if not, write to the Free Software
  28. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  29. """
  30. try:
  31. import http.client as httplib
  32. except ImportError:
  33. import httplib
  34. import base64
  35. import json
  36. import decimal
  37. try:
  38. import urllib.parse as urlparse
  39. except ImportError:
  40. import urlparse
  41. USER_AGENT = "AuthServiceProxy/0.1"
  42. class JSONRPCException(Exception):
  43. def __init__(self, rpcError):
  44. Exception.__init__(self)
  45. self.error = rpcError
  46. import mmgen.config as g
  47. class AuthServiceProxy(object):
  48. def __init__(self, serviceURL, serviceName = None):
  49. self.__serviceURL = serviceURL
  50. self.__serviceName = serviceName
  51. self.__url = urlparse.urlparse(serviceURL)
  52. if self.__url.port is None:
  53. port = 80
  54. else:
  55. port = self.__url.port
  56. self.__idcnt = 0
  57. authpair = "%s:%s" % (self.__url.username, self.__url.password)
  58. authpair = authpair.encode('utf8')
  59. self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair)
  60. http_timeout = g.http_timeout
  61. if self.__url.scheme == 'https':
  62. self.__conn = httplib.HTTPSConnection(self.__url.hostname, port,
  63. None, None, False, timeout=http_timeout)
  64. else:
  65. self.__conn = httplib.HTTPConnection(self.__url.hostname, port,
  66. False, timeout=http_timeout)
  67. def __getattr__(self, name):
  68. if self.__serviceName != None:
  69. name = "%s.%s" % (self.__serviceName, name)
  70. return AuthServiceProxy(self.__serviceURL, name)
  71. def __call__(self, *args):
  72. self.__idcnt += 1
  73. postdata = json.dumps({
  74. 'version': '1.1',
  75. 'method': self.__serviceName,
  76. 'params': args,
  77. 'id': self.__idcnt})
  78. try:
  79. self.__conn.request('POST', self.__url.path, postdata,
  80. { 'Host' : self.__url.hostname,
  81. 'User-Agent' : USER_AGENT,
  82. 'Authorization' : self.__authhdr,
  83. 'Content-type' : 'application/json' })
  84. except:
  85. from mmgen.utils import msg
  86. import sys
  87. msg("\nUnable to connect to bitcoind.")
  88. sys.exit(2)
  89. httpresp = self.__conn.getresponse()
  90. if httpresp is None:
  91. raise JSONRPCException({
  92. 'code' : -342, 'message' : 'missing HTTP response from server'})
  93. resp = httpresp.read()
  94. resp = resp.decode('utf8')
  95. resp = json.loads(resp, parse_float=decimal.Decimal)
  96. if 'error' in resp and resp['error'] != None:
  97. raise JSONRPCException(resp['error'])
  98. elif 'result' not in resp:
  99. raise JSONRPCException({
  100. 'code' : -343, 'message' : 'missing JSON-RPC result'})
  101. else:
  102. return resp['result']
  103. def _batch(self, rpc_call_list):
  104. postdata = json.dumps(list(rpc_call_list))
  105. self.__conn.request('POST', self.__url.path, postdata,
  106. { 'Host' : self.__url.hostname,
  107. 'User-Agent' : USER_AGENT,
  108. 'Authorization' : self.__authhdr,
  109. 'Content-type' : 'application/json' })
  110. httpresp = self.__conn.getresponse()
  111. if httpresp is None:
  112. raise JSONRPCException({
  113. 'code' : -342, 'message' : 'missing HTTP response from server'})
  114. resp = httpresp.read()
  115. resp = resp.decode('utf8')
  116. resp = json.loads(resp, parse_float=decimal.Decimal)
  117. return resp