コード例 #1
0
ファイル: sockbuf.py プロジェクト: jmacarthur/morph
class SocketBuffer(StateMachine):

    def __init__(self, sock, max_buffer):
        StateMachine.__init__(self, 'reading')

        self._sock = sock
        self._max_buffer = max_buffer

    def __repr__(self):
        return '<SocketBuffer at 0x%x: socket %s max_buffer %i>' % (
                id(self), self._sock, self._max_buffer)

    def setup(self):        
        src = self._src = SocketEventSource(self._sock)
        src.stop_writing() # We'll start writing when we need to.
        self.mainloop.add_event_source(src)

        self._wbuf = StringBuffer()

        spec = [
            # state, source, event_class, new_state, callback
            ('reading', src, SocketReadable, 'reading', self._fill),
            ('reading', self, _WriteBufferNotEmpty, 'rw', 
                self._start_writing),
            ('reading', self, SocketBufferEof, 'idle', None),
            ('reading', self, _Close, None, self._really_close),
            
            ('rw', src, SocketReadable, 'rw', self._fill),
            ('rw', src, SocketWriteable, 'rw', self._flush),
            ('rw', self, _WriteBufferIsEmpty, 'reading', self._stop_writing),
            ('rw', self, SocketBufferEof, 'w', None),
            ('rw', self, _Close, 'wc', None),
            
            ('idle', self, _WriteBufferNotEmpty, 'w', self._start_writing),
            ('idle', self, _Close, None, self._really_close),
            
            ('w', src, SocketWriteable, 'w', self._flush),
            ('w', self, _WriteBufferIsEmpty, 'idle', self._stop_writing),

            ('wc', src, SocketWriteable, 'wc', self._flush),
            ('wc', self, _WriteBufferIsEmpty, None, self._really_close),
        ]
        self.add_transitions(spec)

    def write(self, data):
        '''Put data into write queue.'''
        
        was_empty = len(self._wbuf) == 0
        self._wbuf.add(data)
        if was_empty and len(self._wbuf) > 0:
            self._start_writing(None, None)
            self.mainloop.queue_event(self, _WriteBufferNotEmpty())

    def close(self):
        '''Tell state machine to terminate.'''
        self.mainloop.queue_event(self, _Close())

    def _report_error(self, event_source, event):
        logging.error(str(event))

    def _fill(self, event_source, event):
        try:
            data = event.sock.read(self._max_buffer)
        except (IOError, OSError), e:
            logging.debug(
                '%s: _fill(): Exception %s from sock.read()', self, e)
            return [SocketError(event.sock, e)]

        if data:
            self.mainloop.queue_event(self, SocketBufferNewData(data))
        else:
            event_source.stop_reading()
            self.mainloop.queue_event(self, SocketBufferEof())
コード例 #2
0
ファイル: jm.py プロジェクト: nowster/morph
class JsonMachine(StateMachine):

    '''A state machine for sending/receiving JSON messages across TCP.'''

    max_buffer = 16 * 1024

    def __init__(self, conn):
        StateMachine.__init__(self, 'rw')
        self.conn = conn
        self.debug_json = False

    def __repr__(self):
        return '<JsonMachine at 0x%x: socket %s, max_buffer %s>' % \
            (id(self), self.conn, self.max_buffer)

    def setup(self):
        sockbuf = self.sockbuf = SocketBuffer(self.conn, self.max_buffer)
        self.mainloop.add_state_machine(sockbuf)

        self._eof = False
        self.receive_buf = StringBuffer()

        spec = [
            # state, source, event_class, new_state, callback
            ('rw', sockbuf, SocketBufferNewData, 'rw', self._parse),
            ('rw', sockbuf, SocketBufferEof, 'w', self._send_eof),
            ('rw', self, _Close2, None, self._really_close),
            
            ('w', self, _Close2, None, self._really_close),
        ]
        self.add_transitions(spec)
        
    def send(self, msg):
        '''Send a message to the other side.'''
        if self.debug_json:
            logging.debug('JsonMachine: Sending message %s' % repr(msg))
        s = json.dumps(yaml.safe_dump(msg))
        if self.debug_json:
            logging.debug('JsonMachine: As %s' % repr(s))
        self.sockbuf.write('%s\n' % s)
    
    def close(self):
        '''Tell state machine it should shut down.
        
        The state machine will vanish once it has flushed any pending
        writes.
        
        '''
        
        self.mainloop.queue_event(self, _Close2())
        
    def _parse(self, event_source, event):
        data = event.data
        self.receive_buf.add(data)
        if self.debug_json:
            logging.debug('JsonMachine: Received: %s' % repr(data))
        while True:
            line = self.receive_buf.readline()
            if line is None:
                break
            line = line.rstrip()
            if self.debug_json:
                logging.debug('JsonMachine: line: %s' % repr(line))
            msg = yaml.load(json.loads(line))
            self.mainloop.queue_event(self, JsonNewMessage(msg))

    def _send_eof(self, event_source, event):
        self.mainloop.queue_event(self, JsonEof())

    def _really_close(self, event_source, event):
        self.sockbuf.close()
        self._send_eof(event_source, event)
コード例 #3
0
class SocketBuffer(StateMachine):
    def __init__(self, sock, max_buffer):
        StateMachine.__init__(self, 'reading')

        self._sock = sock
        self._max_buffer = max_buffer

    def __repr__(self):
        return '<SocketBuffer at 0x%x: socket %s max_buffer %i>' % (
            id(self), self._sock, self._max_buffer)

    def setup(self):
        src = self._src = SocketEventSource(self._sock)
        src.stop_writing()  # We'll start writing when we need to.
        self.mainloop.add_event_source(src)

        self._wbuf = StringBuffer()

        spec = [
            # state, source, event_class, new_state, callback
            ('reading', src, SocketReadable, 'reading', self._fill),
            ('reading', self, _WriteBufferNotEmpty, 'rw', self._start_writing),
            ('reading', self, SocketBufferEof, 'idle', None),
            ('reading', self, _Close, None, self._really_close),
            ('rw', src, SocketReadable, 'rw', self._fill),
            ('rw', src, SocketWriteable, 'rw', self._flush),
            ('rw', self, _WriteBufferIsEmpty, 'reading', self._stop_writing),
            ('rw', self, SocketBufferEof, 'w', None),
            ('rw', self, _Close, 'wc', None),
            ('idle', self, _WriteBufferNotEmpty, 'w', self._start_writing),
            ('idle', self, _Close, None, self._really_close),
            ('w', src, SocketWriteable, 'w', self._flush),
            ('w', self, _WriteBufferIsEmpty, 'idle', self._stop_writing),
            ('wc', src, SocketWriteable, 'wc', self._flush),
            ('wc', self, _WriteBufferIsEmpty, None, self._really_close),
        ]
        self.add_transitions(spec)

    def write(self, data):
        '''Put data into write queue.'''

        was_empty = len(self._wbuf) == 0
        self._wbuf.add(data)
        if was_empty and len(self._wbuf) > 0:
            self._start_writing(None, None)
            self.mainloop.queue_event(self, _WriteBufferNotEmpty())

    def close(self):
        '''Tell state machine to terminate.'''
        self.mainloop.queue_event(self, _Close())

    def _report_error(self, event_source, event):
        logging.error(str(event))

    def _fill(self, event_source, event):
        try:
            data = event.sock.read(self._max_buffer)
        except (IOError, OSError), e:
            logging.debug('%s: _fill(): Exception %s from sock.read()', self,
                          e)
            return [SocketError(event.sock, e)]

        if data:
            self.mainloop.queue_event(self, SocketBufferNewData(data))
        else:
            event_source.stop_reading()
            self.mainloop.queue_event(self, SocketBufferEof())