tranma
tranma

Reputation: 23

Stream from `Managed` pipe

I'm using Control.Monad.Managed to wrap pipes-http's withHTTP in a continuation transformer, but I also want to stream the HTTP response out afterwards:

import Pipes
import Pipes.ByteString
import Pipes.HTTP
import Control.Applicative
import Control.Monad
import Control.Monad.Managed
import qualified Data.ByteString.Char8       as BC

type RespBody = BC.ByteString

managedHTTP :: Request -> Manager -> Managed (Response (Producer RespBody IO ()))
managedHTTP r m = managed (withHTTP r m)

fromHTTP :: Request -> Manager -> Producer RespBody IO ()
fromHTTP request manager = join $ liftIO $ fmap (hoist liftIO) $ with response return
  where response = responseBody <$> managedHTTP request manager 

Here fromHTTP is meant to stream out the response body. If the above is run with:

main = do
  request <- parseUrl "http://en.wikipedia.org/"
  manager <- newManager defaultManagerSettings
  runEffect $ fromHTTP request manager >-> stdout

I get recv: invalid argument (Bad file descriptor) after the first chunk because http-client's responseClose already closed my response body.

How should I go about streaming HTTP responses with pipes if I want to expose a non-with style interface?

Thanks & apologies if I'm seriously misunderstanding continuations and pipes.

Upvotes: 2

Views: 125

Answers (1)

Michael
Michael

Reputation: 2909

Your definition of fromHTTP is a little hard to follow, but it clearly has you exiting the managed environment before you actually start using the producer. Something like this might be closer to what you intend:

import Pipes
import Pipes.ByteString
import Pipes.HTTP
import Control.Applicative
import Control.Monad
import Control.Monad.Managed
import qualified Data.ByteString.Char8       as BC

type RespBody = BC.ByteString

managedHTTP :: Request -> Manager -> Managed (Response (Producer RespBody IO ()))
managedHTTP r m = managed (withHTTP r m)

managedManager :: ManagerSettings -> Managed Manager
managedManager settings = managed (withManager settings)

main = runManaged $ 
  do request <- liftIO $ parseUrl "http://en.wikipedia.org/" 
     manager <-  managedManager defaultManagerSettings
     producer <- managedHTTP request manager
     liftIO $ runEffect $ responseBody producer >-> stdout

or just scrap the definitions and write

main = runManaged $ 
  do request  <- liftIO $ parseUrl "http://en.wikipedia.org/" 
     manager  <- managed (withManager defaultManagerSettings)
     producer <- managed (withHTTP request manager)
     liftIO $ runEffect $ responseBody producer >-> stdout

Note that you can make the producer run in the Managed monad as well:

main = runManaged $ 
  do request  <- liftIO $ parseUrl "http://en.wikipedia.org/" 
     manager  <- managed (withManager defaultManagerSettings)
     producer <- managed (withHTTP request manager)
     runEffect $ hoist liftIO (responseBody producer) >-> stdout

Upvotes: 1

Related Questions