PageRenderTime 96ms CodeModel.GetById 40ms app.highlight 16ms RepoModel.GetById 25ms app.codeStats 7ms

/Demo/pdist/client.py

http://unladen-swallow.googlecode.com/
Python | 157 lines | 149 code | 6 blank | 2 comment | 0 complexity | 15c4b048c5f383364fad94f8e6525300 MD5 | raw file
  1"""RPC Client module."""
  2
  3import sys
  4import socket
  5import pickle
  6import __builtin__
  7import os
  8
  9
 10# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
 11VERBOSE = 1
 12
 13
 14class Client:
 15
 16    """RPC Client class.  No need to derive a class -- it's fully generic."""
 17
 18    def __init__(self, address, verbose = VERBOSE):
 19        self._pre_init(address, verbose)
 20        self._post_init()
 21
 22    def _pre_init(self, address, verbose = VERBOSE):
 23        if type(address) == type(0):
 24            address = ('', address)
 25        self._address = address
 26        self._verbose = verbose
 27        if self._verbose: print "Connecting to %s ..." % repr(address)
 28        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 29        self._socket.connect(address)
 30        if self._verbose: print "Connected."
 31        self._lastid = 0 # Last id for which a reply has been received
 32        self._nextid = 1 # Id of next request
 33        self._replies = {} # Unprocessed replies
 34        self._rf = self._socket.makefile('r')
 35        self._wf = self._socket.makefile('w')
 36
 37    def _post_init(self):
 38        self._methods = self._call('.methods')
 39
 40    def __del__(self):
 41        self._close()
 42
 43    def _close(self):
 44        if self._rf: self._rf.close()
 45        self._rf = None
 46        if self._wf: self._wf.close()
 47        self._wf = None
 48        if self._socket: self._socket.close()
 49        self._socket = None
 50
 51    def __getattr__(self, name):
 52        if name in self._methods:
 53            method = _stub(self, name)
 54            setattr(self, name, method) # XXX circular reference
 55            return method
 56        raise AttributeError, name
 57
 58    def _setverbose(self, verbose):
 59        self._verbose = verbose
 60
 61    def _call(self, name, *args):
 62        return self._vcall(name, args)
 63
 64    def _vcall(self, name, args):
 65        return self._recv(self._vsend(name, args))
 66
 67    def _send(self, name, *args):
 68        return self._vsend(name, args)
 69
 70    def _send_noreply(self, name, *args):
 71        return self._vsend(name, args, 0)
 72
 73    def _vsend_noreply(self, name, args):
 74        return self._vsend(name, args, 0)
 75
 76    def _vsend(self, name, args, wantreply = 1):
 77        id = self._nextid
 78        self._nextid = id+1
 79        if not wantreply: id = -id
 80        request = (name, args, id)
 81        if self._verbose > 1: print "sending request: %s" % repr(request)
 82        wp = pickle.Pickler(self._wf)
 83        wp.dump(request)
 84        return id
 85
 86    def _recv(self, id):
 87        exception, value, rid = self._vrecv(id)
 88        if rid != id:
 89            raise RuntimeError, "request/reply id mismatch: %d/%d" % (id, rid)
 90        if exception is None:
 91            return value
 92        x = exception
 93        if hasattr(__builtin__, exception):
 94            x = getattr(__builtin__, exception)
 95        elif exception in ('posix.error', 'mac.error'):
 96            x = os.error
 97        if x == exception:
 98            exception = x
 99        raise exception, value
100
101    def _vrecv(self, id):
102        self._flush()
103        if self._replies.has_key(id):
104            if self._verbose > 1: print "retrieving previous reply, id = %d" % id
105            reply = self._replies[id]
106            del self._replies[id]
107            return reply
108        aid = abs(id)
109        while 1:
110            if self._verbose > 1: print "waiting for reply, id = %d" % id
111            rp = pickle.Unpickler(self._rf)
112            reply = rp.load()
113            del rp
114            if self._verbose > 1: print "got reply: %s" % repr(reply)
115            rid = reply[2]
116            arid = abs(rid)
117            if arid == aid:
118                if self._verbose > 1: print "got it"
119                return reply
120            self._replies[rid] = reply
121            if arid > aid:
122                if self._verbose > 1: print "got higher id, assume all ok"
123                return (None, None, id)
124
125    def _flush(self):
126        self._wf.flush()
127
128
129from security import Security
130
131
132class SecureClient(Client, Security):
133
134    def __init__(self, *args):
135        import string
136        apply(self._pre_init, args)
137        Security.__init__(self)
138        self._wf.flush()
139        line = self._rf.readline()
140        challenge = string.atoi(string.strip(line))
141        response = self._encode_challenge(challenge)
142        line = repr(long(response))
143        if line[-1] in 'Ll': line = line[:-1]
144        self._wf.write(line + '\n')
145        self._wf.flush()
146        self._post_init()
147
148class _stub:
149
150    """Helper class for Client -- each instance serves as a method of the client."""
151
152    def __init__(self, client, name):
153        self._client = client
154        self._name = name
155
156    def __call__(self, *args):
157        return self._client._vcall(self._name, args)