module Network.HTTP.Toolkit.Connection (
Connection(..)
, makeConnection
, connectionFromHandle
, connectionRead
, connectionUnread
, connectionReadAtLeast
) where
import Prelude hiding (read)
import Control.Monad (join, unless)
import System.IO (Handle)
import Data.IORef
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
data Connection = Connection {
_read :: IO ByteString
, _unread :: ByteString -> IO ()
}
connectionFromHandle :: Handle -> IO Connection
connectionFromHandle h = makeConnection (B.hGetSome h 4096)
makeConnection :: IO ByteString -> IO Connection
makeConnection read = do
ref <- newIORef []
return $ Connection {
_read = join $ atomicModifyIORef ref $ \xs -> case xs of
y : ys -> (ys, return y)
_ -> (xs, read)
, _unread = \x -> atomicModifyIORef ref $ \xs -> (x : xs, ())
}
connectionRead :: Connection -> IO ByteString
connectionRead = _read
connectionUnread :: Connection -> ByteString -> IO ()
connectionUnread conn bs = unless (B.null bs) (_unread conn bs)
connectionReadAtLeast :: Connection -> Int -> IO ByteString
connectionReadAtLeast conn n = connectionRead conn >>= go
where
go :: ByteString -> IO ByteString
go xs
| B.length xs < n = do
ys <- connectionRead conn
go (xs `B.append` ys)
| otherwise = return xs