User:Brahmana/Netwerk Docs/Stream Operations
The three main players are and a small player:
- nsIInputStream - The Stream
- nsIStreamListener - The Listener
- nsIInputStreamPump - The Pump
- nsIInputStreamCallback - The Callback
(Forget the super classes)
The Stream is a straight forward thing and here it represents a stream of data that can be read. The stream can be blocking or non-blocking. Lets assume for now that it is not blocking. Now the standard way of reading from the stream would be to poll the stream at some regular intervals and ask it if there is some data. [Actually the standard way is to QueryInterface the stream for nsIAsyncInputStream and use asyncWait; regular polling is only necessary if you want to use a nonblocking stream that doesn't support nsIAsyncInputStream, which is rare. A blocking stream that doesn't support nsIAsyncInputStream can of course simply be read on a background thread. Biesi 17:45, 4 January 2009 (UTC)] If it says yes then we call read.
To avoid this, there are stream listeners, The Listener in our case. The Listener provides methods to notify it of Start, Stop and data availability. Now we would expect The Stream to take this listener and call the methods on it. But that is not how it works here. Probably because it is not a good to tie the listener with Stream. Honestly I do not know the precise reason. It might have something to do with blocking streams. Basically you cannot just directly pass a listener to a stream and ask it to notify you when there is data. [biesi: Any explanation?] [There's nsIAsyncInputStream, see above. That said, streamlistener semantics are somewhat complicated so it makes sense not to require all streams to be able to handle them. Biesi 17:45, 4 January 2009 (UTC)]
This is where The Pump comes into picture. The pump takes a stream and a listener and plays the mediator between the two. It basically factors out the responsibility of notifying a listener from the stream.
If the stream is non-blocking and also implements nsIAsyncInputStream, the pump just calls AsyncWait on the stream and the stream notifies the pump with the callback whether the stream is ready. It might notify readiness for reading or for closing. If its readiness for read the pump then fetches info about the available data like its size and all and passes it to the stream listener along with the stream from which the listener ultimately reads the data.
If the stream is a blocking one and does not implement nsIAsyncStream, then the pump creates a nsITransport using the nsIStreamTransportService. This nsITransport takes the blocking stream and returns a stream that implements nsIAsyncStream. Essentially, the pump gets a nsIAsyncStream and calls asyncWait() on that to get notified. This happens in EnsureWaiting(). Since we get one notification for every call to asyncWait(), EnsureWaiting() is called after processing every callback notification.
With this the user of this stream can create a StreamPump and pass his listener to it. The pump will then notify the listener about the Start, Stop and availability of data. [Well, the pump itself handles that too, the user doesn't have to create the nsITransport themselves. Biesi 17:45, 4 January 2009 (UTC)]