module Data.Connection where import qualified Data.ByteString as B import qualified Data.ByteString.Lazy.Internal as L import qualified System.IO.Streams as S -- | A simple connection abstraction. -- -- 'Connection' s from this package are supposed to have following properties: -- -- * 'S.InputStream' is choosen to simplify streaming processing. -- You can easily push back some data with 'S.unRead', -- reading 'S.InputStream' will block until GHC IO manager find data is ready, for example: -- @'S.readExactly' 1024@ will block until at least 1024 bytes are available. -- -- * The type @'L.ByteString' -> 'IO' ()@ is choosen because it worked well with haskell's builder infrastructure. -- -- is used automatically when there's more than one chunk to send to save system call. -- -- * 'connExtraInfo' field store extra data about the connection, 'N.SockAddr' for example. -- You can also use this field as a type tag to distinguish different type of connection. -- -- * 'close' should close connection resource, thus the 'Connection' shouldn't be used anymore -- after 'close' is called. -- -- * You should make sure there's no pending recv/send before you 'close' a 'Connection'. -- That means either you call 'close' in the same thread you recv/send, or use async exception -- to terminate recv/send thread before call 'close' in other thread(such as a reaper thread). -- Otherwise you may run into -- . -- -- * Exception or closed by other peer during recv/send will NOT close underline socket, -- you should always use 'close' with 'E.bracket' to ensure safety. -- -- @since 1.0 -- data Connection a = Connection { source :: {-# UNPACK #-} !(S.InputStream B.ByteString) -- ^ receive data as 'S.InputStream' , send :: L.ByteString -> IO () -- ^ send data with connection , close :: IO () -- ^ close connection , connExtraInfo :: a -- ^ extra info }