1

I'm trying to understand how to write a web service using warp that has a long lived resource that I want access to from all my requests (i.e. I want the resource to exist for the life time of server, not per request). I'm assuming this is a use for ResourceT, but I'm unsure how I actually do this.

My particular use is that I want to expose a file handle, that I currently have wrapped up in the state monad. I'm happy to change this approach, if this doesn't make sense when using warp and ResourceT. An early version of this code can be seen on code review: https://codereview.stackexchange.com/questions/9177/my-simple-haskell-key-value-file-store

Thanks in advance,

Matt

Community
  • 1
  • 1
thatismatt
  • 9,832
  • 10
  • 42
  • 54

1 Answers1

4

The most obvious way is to pass the file handle in as a parameter to the Application.

import Control.Monad.Trans (liftIO)
import Data.ByteString.Lazy as Bl
import Network.HTTP.Types
import Network.Wai
import Network.Wai.Handler.Warp as Warp
import System.IO

doSomethingWithAFileHandle :: Handle -> IO ()
doSomethingWithAFileHandle =
  undefined -- insert your logic here

app :: Handle -> Application
app h req = do
  let headers = []
      body    = Bl.empty

  liftIO $ doSomethingWithAFileHandle h

  return $! responseLBS ok200 headers body

main :: IO ()
main =
  -- get some file handle
  withBinaryFile "/dev/random" ReadMode $ \ h ->

    -- and then partially apply it to get an Application
    Warp.run 3000 (app h)
Nathan Howell
  • 4,627
  • 1
  • 22
  • 30
  • That's really helpful, thank you. What is the correct way to extend this so that access to the file handle is encapsulated. I'm thinking of something similar to my usage of the state monad at http://codereview.stackexchange.com/questions/9177/my-simple-haskell-key-value-file-store ? Thanks again. – thatismatt Mar 27 '12 at 09:23
  • 1
    @thatismatt If you look at the type signature of 'run' you'll find that it really wants a 'Request -> ResourceT IO Response'. That doesn't give you the flexibility to replace IO with 'ReaderT Handle IO' or a StateT equivalent. It would be safe to extended this to ReaderT (see the forkable-monad and monad-fork packages) but I don't see much benefit from doing so – Nathan Howell Mar 27 '12 at 16:48