0
|
1 #!/usr/bin/env python2.7
|
|
2 from uuid import uuid4
|
|
3 from urlparse import urlparse
|
|
4 try:
|
|
5 import json
|
|
6 except:
|
|
7 import simplejson as json
|
|
8 import httplib
|
|
9 import copy
|
|
10 import socket
|
|
11 import hashlib
|
|
12
|
|
13 class _Method(object):
|
|
14 def __init__(self, call, name, username=None, password=None):
|
|
15 self.call = call
|
|
16 self.name = name
|
|
17 self._username = username
|
|
18 self._password = password
|
|
19
|
|
20 def __call__(self, *args, **kwargs):
|
|
21 request = {}
|
|
22 request['id'] = str(uuid4())
|
|
23 request['method'] = self.name
|
|
24
|
|
25 if len(kwargs) is not 0:
|
|
26 params = copy.copy(kwargs)
|
|
27 index = 0
|
|
28 for arg in args:
|
|
29 params[str(index)] = arg
|
|
30 index = index + 1
|
|
31 elif len(args) is not 0:
|
|
32 params = copy.copy(args)
|
|
33 else:
|
|
34 params = None
|
|
35 request['params'] = params
|
|
36
|
|
37 if self._username is not None:
|
|
38 request['username'] = self._username
|
|
39 if self._password is not None:
|
|
40 request['password'] = hashlib.md5(self._password).hexdigest()
|
|
41
|
|
42 resp = self.call(json.dumps(request))
|
|
43 if resp is not None and resp['error'] is None and resp['id'] == request['id']:
|
|
44 return resp['result']
|
|
45 else:
|
|
46 raise Exception('This is not supposed to happen -- btc') ########
|
|
47
|
|
48 def __getattr__(self, name):
|
|
49 return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password)
|
|
50
|
|
51 class _JSONRPCTransport(object):
|
|
52 headers = {'Content-Type':'application/json',
|
|
53 'Accept':'application/json'}
|
|
54
|
|
55 def __init__(self, uri, proxy_uri=None, user_agent=None):
|
|
56 self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib'
|
|
57 if proxy_uri is not None:
|
|
58 self.connection_url = urlparse(proxy_uri)
|
|
59 self.request_path = uri
|
|
60 else:
|
|
61 self.connection_url = urlparse(uri)
|
|
62 self.request_path = self.connection_url.path
|
|
63
|
|
64 def request(self, request_body):
|
|
65 if self.connection_url.scheme == 'http':
|
|
66 if self.connection_url.port is None:
|
|
67 port = 80
|
|
68 else:
|
|
69 port = self.connection_url.port
|
|
70 connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port))
|
|
71 elif self.connection_url.scheme == 'https':
|
|
72 if self.connection_url.port is None:
|
|
73 port = 443
|
|
74 else:
|
|
75 port = self.connection_url.port
|
|
76 connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port))
|
|
77 else:
|
|
78 raise Exception('unsupported transport')
|
|
79 connection.request('POST', self.request_path, body=request_body, headers=self.headers)
|
|
80 return connection.getresponse()
|
|
81
|
|
82 class BadRequestException(Exception):
|
|
83 """HTTP 400 - Bad Request"""
|
|
84 def __init__(self):
|
|
85 Exception.__init__(self,'HTTP 400 - Bad Request')
|
|
86
|
|
87 class UnauthorisedException(Exception):
|
|
88 """HTTP 401 - Unauthorised"""
|
|
89 def __init__(self):
|
|
90 Exception.__init__(self,'HTTP 401 - Unauthorised')
|
|
91
|
|
92 class ForbiddenException(Exception):
|
|
93 """HTTP 403 - Forbidden"""
|
|
94 def __init__(self):
|
|
95 Exception.__init__(self,'HTTP 403 - Forbidden')
|
|
96
|
|
97 class NotFoundException(Exception):
|
|
98 """HTTP 404 - Not Found"""
|
|
99 def __init__(self):
|
|
100 Exception.__init__(self,'HTTP 404 - Not Found')
|
|
101
|
|
102 class NetworkSocketException(Exception):
|
|
103 def __init__(self):
|
|
104 Exception.__init__(self,'Network socket exception')
|
|
105
|
|
106 class BadGatewayException(Exception):
|
|
107 """HTTP 502 - Bad Gateway"""
|
|
108 def __init__(self):
|
|
109 Exception.__init__(self,'HTTP 502 - Bad Gateway')
|
|
110
|
|
111 class ServerProxy2(object):
|
|
112 def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None):
|
|
113 if uri is None and transport is None:
|
|
114 raise Exception('either uri or transport needs to be specified')
|
|
115
|
|
116 if transport is None:
|
|
117 transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent)
|
|
118 self.__transport = transport
|
|
119 self._username = username
|
|
120 self._password = password
|
|
121
|
|
122 def __request(self, request):
|
|
123 # call a method on the remote server
|
|
124 try:
|
|
125 response = self.__transport.request(request)
|
|
126 except socket.error:
|
|
127 raise NetworkSocketException
|
|
128 if response.status == 200:
|
|
129 return json.loads(response.read())
|
|
130 elif response.status == 400:
|
|
131 raise BadRequestException
|
|
132 elif response.status == 401:
|
|
133 raise UnauthorisedException
|
|
134 elif response.status == 403:
|
|
135 raise ForbiddenException
|
|
136 elif response.status == 404:
|
|
137 raise NotFoundException
|
|
138 elif response.status == 500:
|
|
139 msg = json.loads(response.read())
|
|
140 raise Exception('JSONRPCError\n%s'%msg['error']['error'])
|
|
141 elif response.status == 502:
|
|
142 raise BadGatewayException
|
|
143 else:
|
|
144 raise Exception('HTTP Status %s'%response.status)
|
|
145
|
|
146 def __repr__(self):
|
|
147 return (
|
|
148 "<ServerProxy for %s%s>" %
|
|
149 (self.__host, self.__handler)
|
|
150 )
|
|
151
|
|
152 __str__ = __repr__
|
|
153
|
|
154 def __getattr__(self, name):
|
|
155 # magic method dispatcher
|
|
156 return _Method(self.__request, name, self._username, self._password)
|
|
157
|
|
158 if __name__ == '__main__':
|
|
159 ##### btc fixme
|
|
160 jsonrpc_client = ServerProxy2('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter')
|
|
161 #jsonrpc_client = ServerProxy2('https://www.croston.org/test/index.py',
|
|
162 # username='testuser',
|
|
163 # password='',
|
|
164 # user_agent='Py2NotInternetExploiter')
|
|
165 assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod()
|
|
166 try:
|
|
167 print(jsonrpc_client.wibble('this should fail'))
|
|
168 except BadRequestException:
|
|
169 pass # test passed
|
|
170 else:
|
|
171 raise Exception('Test failed (calling unknown method)')
|
|
172
|
|
173 print 'All tests passed'
|
|
174
|