THIS SPECIFICATION IS IN PROGRESS DO NOT READ IT. (This needs to be updated to take [ticket:1956 the new proposed tubes package] into account.) {{wrongtitle|title=Asynchronous File I/O}} === Problem === Twisted has no API for asynchronous file I/O. It oughtta. === Solution === {{{ #!html
def FilePath.openStream(mode)
"""
@param mode: As per C{file.__init__}'s C{mode} parameter.
@return: A L{Deferred} which results in an L{AsynchronousFileIOLayer}.
"""
def AsynchronousFileIOLayer.read(consumer, start=0, end=None)
"""
@param consumer: IFilePathConsumer provider.
@param start: The byte offset into the file at which to start producing.
@param end: The byte offset into the file at which to stop
producing, or None to indicate the end of the file.
@return: None
"""
def AsynchronousFileIOLayer.write(producer, start=0)
"""
@param producer: IFilePathProducer provider. Its produceTo method
will be called.
@param start: The byte offset into the file at which to start
writing. If the file was opened in append mode, then this
parameter must not be specified.
@return: None.
"""
interface IFilePathConsumer:
"""
A consumer of data. Code which calls methods on this interface
should call consumeFrom(p), followed by zero or more calls to
write(d), followed by finished(r). Implementors should expect
such.
"""
def consumeFrom(producerRegulator):
"""
Get ready to receive data.
@param producerRegulator: The provider of L{IProducerRegulator}
which can be used to control the production of data.
"""
def write(data):
"""
Handle incoming data.
"""
def finished(reason):
"""
@param reason: An instance of L{Failure} or None. If it's None
then everything's great. Otherwise it's a failure
describing the problem.
"""
interface IFilePathProducer:
"""
A thing what has data to send.
"""
def produceTo(consumer):
"""
Start sending data to the given consumer.
@param consumer: The IFilePathConsumer to which data should be
sent.
An appopriate L{IProducerRegulator} must be created and passed
to the consumer's L{consumeFrom}
method, to allow the consumer to control the production of
data.
"""
class IProducerRegulator:
"""
A thing which pauses, resumes, and perhaps stops an IProducer.
"""
def pause():
"""
Consumer is busy. Temporarily cease calling L{IConsumer.write}.
Absolutely stop calling write on the consumer until resume is
called.
"""
def resume():
"""
Consumer is no longer busy. Start calling L{IConsumer.write}
again. This must only be called after a call to L{pause}, and
must not be called twice in a row.
"""
def stop(reason):
"""
Called to indicate that the producer should send no more
data. L{IConsumer.finished} must be called and the producer
must stop calling L{IConsumer.write}.
@param reason: a Failure instance.
"""
}}}
=== Open Issues ===
Should produceTo and consumeFrom return Deferreds? If they do, it is
important to note this means there will be duplicate completion
notifications between the deferred and the .finished method. The order
these are called in should perhaps be well-defined.
What about duplicating filepath.create()'s behavior asynchronously?
openStream is kind of a strange name, given web2.streams.
I tried writing a "copy a file" example but got confused. someone do that please.
=== Punchline ===
The astute reader will notice that this is actually a redesign of the
producer/consumer framework.