proxy.py 4.5 KB

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