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