Alain O'Dea
Alain O'Dea

Reputation: 21716

How do I use Network.Connection.connectionGet in a blocking manner like Data.ByteString.Lazy.hGet?

I am in the midst of porting the amqp package from using GHC.IO.Handle to using Network.Connection.Connection. The motivation for this is to gain transparent SSL/TLS support to allow for encrypted AMQP communications from Haskell.

The trouble is that my Connnection-based implementation doesn't work. I was running into some fairly surprising (to me) differences when I packet trace the alternate implementations.

It became evident that Network.Connection.connectionGet and GHC.IO.Handle.hGet are very different (non-blocking vs blocking):

http://hackage.haskell.org/package/connection-0.1.3.1/docs/Network-Connection.html#v:connectionGet http://hackage.haskell.org/package/bytestring-0.10.4.0/docs/Data-ByteString-Lazy.html#v:hGet

Network.Connection.connectionGet acts like GHC.IO.Handle.hGetNonBlocking.

I was replacing GHC.IO.Handle.hGet with Network.Connection.connectionGet thinking it was a drop-in replacement which it isn't.

How do I use Network.Connection.connectionGet in a blocking manner like Data.ByteString.Lazy.hGet?

Upvotes: 0

Views: 98

Answers (1)

Ankur
Ankur

Reputation: 33657

I wouldn't call this a blocking vs non-blocking thing as that thought lead to the async IO concept which a different concept then what is happening in these APIs.

The difference here is that in hGet when you ask for x number of bytes to be read, it will try to read and wait till it gets that number of bytes from the connection OR the connection get closed, where as the connectionGet function will return whatever bytes it can read from the connection buffer but the count of these bytes will be less than or equals to requested bytes i.e x.

You can make connectionGet behave like hGet using a simple recursion as shown below, NOTE: below has been verified to work :)

import qualified Network.Connection as Conn
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BC

-- ... intervening code

connectionGet' :: Conn.Connection -> Int -> IO BC.ByteString
connectionGet' conn x = do
                  bs <- Conn.connectionGet conn x
                  let diff = BS.length bs - x
                  if BS.length bs == 0 || diff == 0
                    then do
                      return bs
                    else do
                      next <- connectionGet' conn diff
                      return $ BC.append bs next

Upvotes: 2

Related Questions