class Connection(object): """Provides network I/O for a Proton connection via a socket-like object. """ def __init__(self, socket, eventHandler, name=None): """socket - Python socket. Expected to be configured and connected. name - optional name for this SocketTransport """ self._name = name self._socket = socket self._pn_transport = Transport() self._pn_connection = Connection() self._pn_transport.bind(self._pn_connection) self._pn_transport.trace(proton.Transport.TRACE_FRM) self._handler = eventHandler self._read_done = False self._write_done = False self._next_tick = 0 self._sasl_done = False self._pn_connection.open() def fileno(self): """Allows use of a Connection by the python select() call. """ return self._socket.fileno() @property # @todo - hopefully remove def transport(self): return self._pn_transport @property # @todo - hopefully remove def connection(self): return self._pn_connection @property def socket(self): return self._socket @property def name(self): return self._name @property # @todo - think about server side use of this! def sasl(self): return self._pn_transport.sasl() def tick(self, now): """Invoke the transport's tick method. 'now' is seconds since Epoch. Returns the timestamp for the next tick, or zero if no next tick. """ self._next_tick = self._pn_transport.tick(now) return self._next_tick @property def next_tick(self): """Timestamp for next call to tick() """ return self._next_tick @property def need_read(self): """True when the Transport requires data from the network layer. """ return (not self._read_done) and self._pn_transport.capacity() > 0 @property def need_write(self): """True when the Transport has data to write to the network layer. """ return (not self._write_done) and self._pn_transport.pending() > 0 def read_input(self): """Read from the network layer and processes all data read. Can support both blocking and non-blocking sockets. """ if self._read_done: return None c = self._pn_transport.capacity() if c < 0: try: self._socket.shutdown(socket.SHUT_RD) except: pass self._read_done = True return None if c > 0: try: buf = self._socket.recv(c) if buf: self._pn_transport.push(buf) return len(buf) # else socket closed self._pn_transport.close_tail() self._read_done = True return None except socket.timeout, e: raise # let the caller handle this except socket.error, e: err = e.args[0] if (err != errno.EAGAIN and err != errno.EWOULDBLOCK and err != errno.EINTR): # otherwise, unrecoverable: self._pn_transport.close_tail() self._read_done = True raise except: # beats me...