Reputation: 23
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
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