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