Mercurial > hg > AuthRPC
comparison wibble/client/__init__.py @ 9:23743b0f67ab
Moved client.ServerProxy into client.__init__
author | Ben Croston <ben@croston.org> |
---|---|
date | Sun, 04 Sep 2011 23:44:50 +0100 |
parents | ad5a8748afcf |
children | 21eb67081c43 |
comparison
equal
deleted
inserted
replaced
8:685479d1f0a7 | 9:23743b0f67ab |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 # Copyright (c) 2011 Ben Croston | |
4 # | |
5 # Permission is hereby granted, free of charge, to any person obtaining a copy of | |
6 # this software and associated documentation files (the "Software"), to deal in | |
7 # the Software without restriction, including without limitation the rights to | |
8 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 # of the Software, and to permit persons to whom the Software is furnished to do | |
10 # so, subject to the following conditions: | |
11 # | |
12 # The above copyright notice and this permission notice shall be included in all | |
13 # copies or substantial portions of the Software. | |
14 # | |
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 # SOFTWARE. | |
22 | |
23 from uuid import uuid4 | |
24 from urlparse import urlparse | |
25 import json | |
26 import httplib | |
27 import copy | |
28 import socket | |
29 import hashlib | |
30 import platform | |
31 | |
32 if platform.python_version().startswith('3'): | |
33 IS_PY3 = True | |
34 else: | |
35 IS_PY3 = False | |
36 | |
37 class _Method(object): | |
38 def __init__(self, call, name, username=None, password=None): | |
39 self.call = call | |
40 self.name = name | |
41 self._username = username | |
42 self._password = password | |
43 | |
44 def __call__(self, *args, **kwargs): | |
45 request = {} | |
46 request['id'] = str(uuid4()) | |
47 request['method'] = self.name | |
48 | |
49 if len(kwargs) is not 0: | |
50 params = copy.copy(kwargs) | |
51 index = 0 | |
52 for arg in args: | |
53 params[str(index)] = arg | |
54 index = index + 1 | |
55 elif len(args) is not 0: | |
56 params = copy.copy(args) | |
57 else: | |
58 params = None | |
59 request['params'] = params | |
60 | |
61 if self._username is not None: | |
62 request['username'] = self._username | |
63 if self._password is not None: | |
64 if IS_PY3: | |
65 request['password'] = hashlib.md5(self._password.encode()).hexdigest() | |
66 else: | |
67 request['password'] = hashlib.md5(self._password).hexdigest() | |
68 | |
69 resp = self.call(json.dumps(request)) | |
70 if resp is not None and resp['error'] is None and resp['id'] == request['id']: | |
71 return resp['result'] | |
72 else: | |
73 raise Exception('This is not supposed to happen -- btc') ######## | |
74 | |
75 def __getattr__(self, name): | |
76 return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) | |
77 | |
78 class _JSONRPCTransport(object): | |
79 headers = {'Content-Type':'application/json', | |
80 'Accept':'application/json'} | |
81 | |
82 def __init__(self, uri, proxy_uri=None, user_agent=None): | |
83 self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' | |
84 if proxy_uri is not None: | |
85 self.connection_url = urlparse(proxy_uri) | |
86 self.request_path = uri | |
87 else: | |
88 self.connection_url = urlparse(uri) | |
89 self.request_path = self.connection_url.path | |
90 | |
91 def request(self, request_body): | |
92 if self.connection_url.scheme == 'http': | |
93 if self.connection_url.port is None: | |
94 port = 80 | |
95 else: | |
96 port = self.connection_url.port | |
97 connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port)) | |
98 elif self.connection_url.scheme == 'https': | |
99 if self.connection_url.port is None: | |
100 port = 443 | |
101 else: | |
102 port = self.connection_url.port | |
103 connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port)) | |
104 else: | |
105 raise Exception('unsupported transport') | |
106 connection.request('POST', self.request_path, body=request_body, headers=self.headers) | |
107 return connection.getresponse() | |
108 | |
109 class BadRequestException(Exception): | |
110 """HTTP 400 - Bad Request""" | |
111 def __init__(self): | |
112 Exception.__init__(self,'HTTP 400 - Bad Request') | |
113 | |
114 class UnauthorisedException(Exception): | |
115 """HTTP 401 - Unauthorised""" | |
116 def __init__(self): | |
117 Exception.__init__(self,'HTTP 401 - Unauthorised') | |
118 | |
119 class ForbiddenException(Exception): | |
120 """HTTP 403 - Forbidden""" | |
121 def __init__(self): | |
122 Exception.__init__(self,'HTTP 403 - Forbidden') | |
123 | |
124 class NotFoundException(Exception): | |
125 """HTTP 404 - Not Found""" | |
126 def __init__(self): | |
127 Exception.__init__(self,'HTTP 404 - Not Found') | |
128 | |
129 class NetworkSocketException(Exception): | |
130 def __init__(self): | |
131 Exception.__init__(self,'Network socket exception') | |
132 | |
133 class BadGatewayException(Exception): | |
134 """HTTP 502 - Bad Gateway""" | |
135 def __init__(self): | |
136 Exception.__init__(self,'HTTP 502 - Bad Gateway') | |
137 | |
138 class ServerProxy(object): | |
139 def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): | |
140 if uri is None and transport is None: | |
141 raise Exception('either uri or transport needs to be specified') | |
142 | |
143 if transport is None: | |
144 transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) | |
145 self.__transport = transport | |
146 self._username = username | |
147 self._password = password | |
148 | |
149 def __request(self, request): | |
150 # call a method on the remote server | |
151 try: | |
152 response = self.__transport.request(request) | |
153 except socket.error: | |
154 raise NetworkSocketException | |
155 if response.status == 200: | |
156 if IS_PY3: | |
157 return json.loads(response.read().decode()) | |
158 else: | |
159 return json.loads(response.read()) | |
160 elif response.status == 400: | |
161 raise BadRequestException | |
162 elif response.status == 401: | |
163 raise UnauthorisedException | |
164 elif response.status == 403: | |
165 raise ForbiddenException | |
166 elif response.status == 404: | |
167 raise NotFoundException | |
168 elif response.status == 500: | |
169 if IS_PY3: | |
170 msg = json.loads(response.read().decode()) | |
171 else: | |
172 msg = json.loads(response.read()) | |
173 raise Exception('JSONRPCError\n%s'%msg['error']['error']) | |
174 elif response.status == 502: | |
175 raise BadGatewayException | |
176 else: | |
177 raise Exception('HTTP Status %s'%response.status) | |
178 | |
179 def __repr__(self): | |
180 return ( | |
181 "<ServerProxy for %s%s>" % | |
182 (self.__host, self.__handler) | |
183 ) | |
184 | |
185 __str__ = __repr__ | |
186 | |
187 def __getattr__(self, name): | |
188 # magic method dispatcher | |
189 return _Method(self.__request, name, self._username, self._password) | |
190 |