comparison wibble/client/ServerProxy2.py @ 0:6a61cfdf6930

Initial version
author Ben Croston <ben@croston.org>
date Tue, 30 Aug 2011 22:19:48 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:6a61cfdf6930
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