module Network.Monad.Transfer.Offline 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.Stream as Stream
import Control.Monad.Trans.Reader (ReaderT, runReaderT, )
import Control.Monad.Trans.RWS (RWS, runRWS, tell, )
import Control.Monad.Trans.Class (lift, )
import qualified Control.Monad.Trans.RWS as RWS
import qualified Control.Monad.Exception.Asynchronous as Async
import Data.Char (chr, )
import qualified Data.List as List
import qualified Data.List.HT as ListHT
import Data.Maybe.HT (toMaybe, )
import Data.Tuple.HT (forcePair, mapFst, )
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Prelude hiding (splitAt, )
type T body = RWS Stream.ConnError [body] body
class Body.C body => Body body where
splitAt :: Int -> body -> (body, body)
breakAfter :: (Char -> Bool) -> body -> (body, body)
instance Body.CharType char => Body [char] where
splitAt = List.splitAt
breakAfter p = ListHT.breakAfter (p . Body.toChar)
instance Body BS.ByteString where
splitAt = BS.splitAt
breakAfter p s =
forcePair $
maybe (s,BS.empty)
(\i -> splitAt (i+1) s)
(BS.findIndex (p . chr . fromIntegral) s)
instance Body BL.ByteString where
splitAt = BL.splitAt . fromIntegral
breakAfter p s =
let (prefix,suffix) =
BL.break (p . chr . fromIntegral) s
in forcePair $
maybe
(prefix,suffix)
(mapFst (BL.snoc prefix))
(BL.uncons suffix)
withBuffer :: (Body.C body) =>
(body -> (a, body)) ->
Transfer.AsyncExceptional (T body) a
withBuffer f =
Async.ExceptionalT $
do buf <- RWS.get
let (block,rest) = f buf
RWS.put rest
closeReason <- RWS.ask
return $
Async.Exceptional (toMaybe (Body.isEmpty rest) closeReason) block
transfer :: (Body body) =>
Transfer.T (T body) body
transfer =
Transfer.Cons {
Transfer.readBlock = \n -> withBuffer $ splitAt n,
Transfer.readLine = withBuffer $ breakAfter ('\n'==),
Transfer.writeBlock = \str -> lift $ tell [str]
}
run :: (Body body) =>
Reader.T body (T body) a -> Stream.ConnError -> body -> (a, body, [body])
run m = runRWS (runReaderT m $ transfer)