fixbot/fifo.py
author terom@fixme.fi
Mon, 15 Sep 2008 00:53:59 +0300
changeset 23 67e71e9170e5
parent 21 aa6df8f9c44a
child 25 6c0a53a512d8
permissions -rw-r--r--
rename plugin fixbot -> fixbot_nexus, add fixbot_logwatch plugin, fix some random bugs
# read a stream from a fifo

from twisted.internet import reactor, interfaces
from twisted.python import log
from zope.interface import implements

import os, fcntl, errno

class EOF (Exception) : pass

BUF_SIZE = 2048

class Fifo (object) :
    implements(interfaces.IReadDescriptor)

    def __init__ (self, path) :
        self.path = path
        self.fd = None

        self._open()

    def _open (self) :
        self.fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK)

        reactor.addReader(self)
        
        log.msg("opened fifo %s as %d" % (self.path, self.fd))

    def _close (self) :
        if self.fd :
            reactor.removeReader(self)
            os.close(self.fd)

            log.msg("closed fifo %d at %s" % (self.fd, self.path))
            
            self.fd = None
    close = _close

    def reopen (self) :
        """
            Close and re-open the fifo. This is useful for handling EOF
        """
        self._close()
        self._open()

    def _read (self, length) :

        log.msg("(read %d bytes from %d:%s)" % (length, self.fd, self.path))
        try :
            data = os.read(self.fd, length)

        except OSError, e :
            if e.errno == errno.EAGAIN :
                log.msg("\tEAGAIN")
                return None
            else :
                log.msg("\tERROR: %s" % e)
                raise

        if not data :
            log.msg("\tEOF")
            raise EOF()
        
        log.msg("\tDATA: %d: %r" % (len(data), data))
        return data
    
    def fileno (self) :
        return self.fd

    def doRead (self) :
        while True :
            log.msg("fifo doRead loop")

            try :
                data = self._read(BUF_SIZE)
            except EOF :
                self.handleEOF()
                return

            if data :
                self.dataReceived(data)
            else :
                break
        
    def dataReceived (self, data) :
        pass
    
    def handleEOF (self) :
        pass
    
    def connectionLost (self, reason) :
        self.close()
    
    def logPrefix (self) :
        return "FIFO:%d:%s" % (self.fd, self.path)

    def __del__ (self) :
        """
            !!! this is important
        """
        self.close()