[Twisted-web] integrating inotify into a protocol

Jason Pepas cell at phunware.com
Tue Mar 29 21:21:03 EDT 2011


hey guys,

I'm new to twisted, and I'm trying to figure out how to integrate the
inotify support into a client protocol.

let's say I have a client protocol which connects to a server and
stays connected, like the "Echo" example here:
http://twistedmatrix.com/documents/10.2.0/core/howto/clients.html#auto3

I've taken that example a tweaked it so that it echos back to the
server, rather than to stdout (see echo.py, attached), and takes its
port number as sys.argv[1].

now, I can start the "server":


  $ cat | socat - tcp4-listen:1234


and start the client:


  $ python echo.py 1234
  Started to connect.
  Connected.


and if I type something into the server, it gets printed on client's
stdout, and then echoed back to the server:


  $ cat | socat - tcp4-listen:1234
  blah
  blah

  $ python foo.py 1234
  Started to connect.
  Connected.
  blah


life is good.

now, let's say I want to integrate inotify support into my persistent
client.  let's say that whenever a new file appears in /tmp, I want to
client to announce this file to the server, over its persistent
connection.  accordingly, I've added 'def announceNewFile()' to the
Echo() protocol class (see echo_inotify, attached).

but herein lies the rub: the inotify notifier just takes a list of
callback functions, not a list of objects.  so how can I get the
notifier to call a method on my Echo protocol object?

another way to say this is that the protocol/client/factory side of
things is all object-oriented, but the inotify side of things is just
procedural.  n'ere the twain shall meet?

specifically, the notifier expects the callback to accept 3 args:
_Watch object, path, and mask.  so, when you try to pass in a class
method as one of its callbacks, you get something like this:

  exceptions.TypeError: unbound method announceNewFile() must be
called with Echo instance as first argument (got _Watch instance
instead)

halp?

-jason
-------------- next part --------------
from twisted.internet.protocol import Protocol, ClientFactory
from sys import stdout

class Echo(Protocol):
    def dataReceived(self, data):
        stdout.write(data)
        self.transport.write(data)

    def announceNewFile(self, watch_obj, path, mask):
        # problem!!! the inotify callback sends three args (watch_obj, path, mask)
        # but we require a reference to self.  halp?
        self.transport.write(msg)

class EchoClientFactory(ClientFactory):
    def startedConnecting(self, connector):
        print 'Started to connect.'

    def buildProtocol(self, addr):
        print 'Connected.'
        return Echo()

    def clientConnectionLost(self, connector, reason):
        print 'Lost connection.  Reason:', reason

    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed. Reason:', reason

if __name__ == "__main__":
    from twisted.internet import reactor, inotify
    from twisted.python import filepath
    import sys
    reactor.connectTCP("localhost", int(sys.argv[1]), EchoClientFactory())

    notifier = inotify.INotify()
    notifier.startReading()
    watch_mask = inotify.IN_CREATE
    notifier.watch(filepath.FilePath("/tmp"), mask=watch_mask, callbacks=[Echo.announceNewFile])
    # again, there is no way for notifier to actually call the announceNewFile
    # method on an Echo() object, because it doesn't have an Echo() object.  lolwut?

    # speaking generally, the protocol/client/factory situation is all object-oriented,
    # but the inotify stuff if procedure (ie, just a callback function).  how does one
    # reconcile these two realms?
    
    reactor.run()
-------------- next part --------------
from twisted.internet.protocol import Protocol, ClientFactory
from sys import stdout

class Echo(Protocol):
    def dataReceived(self, data):
        stdout.write(data)
        self.transport.write(data)

class EchoClientFactory(ClientFactory):
    def startedConnecting(self, connector):
        print 'Started to connect.'

    def buildProtocol(self, addr):
        print 'Connected.'
        return Echo()

    def clientConnectionLost(self, connector, reason):
        print 'Lost connection.  Reason:', reason

    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed. Reason:', reason

if __name__ == "__main__":
    from twisted.internet import reactor, inotify
    from twisted.python import filepath
    import sys
    reactor.connectTCP("localhost", int(sys.argv[1]), EchoClientFactory())
    reactor.run()


More information about the Twisted-web mailing list