module Network.Monad.Transfer.ChunkyLazyIO (
Body(length),
transfer,
run,
) where
import qualified Network.Monad.Transfer as Transfer
import qualified Network.Monad.Reader as Reader
import qualified Network.Monad.Body as Body
import qualified Network.TCP as TCP
import Control.Monad.Trans.Reader (ReaderT, runReaderT, )
import qualified Control.Monad.Exception.Asynchronous as Async
import qualified System.IO.Lazy as LazyIO
import Data.Monoid (Monoid, mempty, mappend, )
import qualified Data.List as List
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Prelude hiding (length, )
class Body.C body => Body body where
length :: body -> Int
instance Body.CharType char => Body [char] where
length = List.length
instance Body BS.ByteString where
length = BS.length
instance Body BL.ByteString where
length = fromIntegral . BL.length
transfer :: (TCP.HStream body, Body body) =>
Int ->
TCP.HandleStream body ->
Transfer.T LazyIO.T body
transfer chunkSize h =
Transfer.Cons {
Transfer.readLine =
Transfer.liftAsync $ LazyIO.interleave $ TCP.readLine h,
Transfer.readBlock = \n ->
readBlockChunky chunkSize h n,
Transfer.writeBlock = \str ->
Transfer.liftSync $ LazyIO.interleave $ TCP.writeBlock h str
}
run :: (TCP.HStream body, Body body) =>
Reader.T body LazyIO.T a
->
Int ->
TCP.HandleStream body ->
IO a
run m chunkSize h = LazyIO.run $ runReaderT m $ transfer chunkSize h
readBlockChunky :: (TCP.HStream body, Body body) =>
Int -> TCP.HandleStream body ->
Int -> Transfer.AsyncExceptional LazyIO.T body
readBlockChunky chunkSize h =
let go todo =
if todo>0
then
(Transfer.liftAsync $ LazyIO.interleave $
TCP.readBlock h (min chunkSize todo))
`Async.bindT`
(\str ->
fmap (mappend str) $ go (max 0 (todo length str)))
else mempty
in go