Mercurial > hg > AuthRPC
view wibble/client/ServerProxy.py @ 7:3a6f3193cc7d
Created new tests
author | Ben Croston <ben@croston.org> |
---|---|
date | Thu, 01 Sep 2011 19:19:03 +0100 |
parents | f5e3ba8cfcd0 |
children | 685479d1f0a7 |
line wrap: on
line source
#!/usr/bin/env python # Copyright (c) 2011 Ben Croston # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies # of the Software, and to permit persons to whom the Software is furnished to do # so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from uuid import uuid4 from urlparse import urlparse import 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 ServerProxy(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 = ServerProxy('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter') #jsonrpc_client = ServerProxy('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'