Mercurial > hg > AuthRPC
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wibble/client/ServerProxy2.py Tue Aug 30 22:19:48 2011 +0100 @@ -0,0 +1,174 @@ +#!/usr/bin/env python2.7 +from uuid import uuid4 +from urlparse import urlparse +try: + import json +except: + import simplejson as json +import httplib +import copy +import socket +import hashlib + +class _Method(object): + def __init__(self, call, name, username=None, password=None): + self.call = call + self.name = name + self._username = username + self._password = password + + def __call__(self, *args, **kwargs): + request = {} + request['id'] = str(uuid4()) + request['method'] = self.name + + if len(kwargs) is not 0: + params = copy.copy(kwargs) + index = 0 + for arg in args: + params[str(index)] = arg + index = index + 1 + elif len(args) is not 0: + params = copy.copy(args) + else: + params = None + request['params'] = params + + if self._username is not None: + request['username'] = self._username + if self._password is not None: + request['password'] = hashlib.md5(self._password).hexdigest() + + resp = self.call(json.dumps(request)) + if resp is not None and resp['error'] is None and resp['id'] == request['id']: + return resp['result'] + else: + raise Exception('This is not supposed to happen -- btc') ######## + + def __getattr__(self, name): + return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) + +class _JSONRPCTransport(object): + headers = {'Content-Type':'application/json', + 'Accept':'application/json'} + + def __init__(self, uri, proxy_uri=None, user_agent=None): + self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' + if proxy_uri is not None: + self.connection_url = urlparse(proxy_uri) + self.request_path = uri + else: + self.connection_url = urlparse(uri) + self.request_path = self.connection_url.path + + def request(self, request_body): + if self.connection_url.scheme == 'http': + if self.connection_url.port is None: + port = 80 + else: + port = self.connection_url.port + connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port)) + elif self.connection_url.scheme == 'https': + if self.connection_url.port is None: + port = 443 + else: + port = self.connection_url.port + connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port)) + else: + raise Exception('unsupported transport') + connection.request('POST', self.request_path, body=request_body, headers=self.headers) + return connection.getresponse() + +class BadRequestException(Exception): + """HTTP 400 - Bad Request""" + def __init__(self): + Exception.__init__(self,'HTTP 400 - Bad Request') + +class UnauthorisedException(Exception): + """HTTP 401 - Unauthorised""" + def __init__(self): + Exception.__init__(self,'HTTP 401 - Unauthorised') + +class ForbiddenException(Exception): + """HTTP 403 - Forbidden""" + def __init__(self): + Exception.__init__(self,'HTTP 403 - Forbidden') + +class NotFoundException(Exception): + """HTTP 404 - Not Found""" + def __init__(self): + Exception.__init__(self,'HTTP 404 - Not Found') + +class NetworkSocketException(Exception): + def __init__(self): + Exception.__init__(self,'Network socket exception') + +class BadGatewayException(Exception): + """HTTP 502 - Bad Gateway""" + def __init__(self): + Exception.__init__(self,'HTTP 502 - Bad Gateway') + +class ServerProxy2(object): + def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): + if uri is None and transport is None: + raise Exception('either uri or transport needs to be specified') + + if transport is None: + transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) + self.__transport = transport + self._username = username + self._password = password + + def __request(self, request): + # call a method on the remote server + try: + response = self.__transport.request(request) + except socket.error: + raise NetworkSocketException + if response.status == 200: + return json.loads(response.read()) + elif response.status == 400: + raise BadRequestException + elif response.status == 401: + raise UnauthorisedException + elif response.status == 403: + raise ForbiddenException + elif response.status == 404: + raise NotFoundException + elif response.status == 500: + msg = json.loads(response.read()) + raise Exception('JSONRPCError\n%s'%msg['error']['error']) + elif response.status == 502: + raise BadGatewayException + else: + raise Exception('HTTP Status %s'%response.status) + + def __repr__(self): + return ( + "<ServerProxy for %s%s>" % + (self.__host, self.__handler) + ) + + __str__ = __repr__ + + def __getattr__(self, name): + # magic method dispatcher + return _Method(self.__request, name, self._username, self._password) + +if __name__ == '__main__': + ##### btc fixme + jsonrpc_client = ServerProxy2('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter') + #jsonrpc_client = ServerProxy2('https://www.croston.org/test/index.py', + # username='testuser', + # password='', + # user_agent='Py2NotInternetExploiter') + assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod() + try: + print(jsonrpc_client.wibble('this should fail')) + except BadRequestException: + pass # test passed + else: + raise Exception('Test failed (calling unknown method)') + + print 'All tests passed' +