haskellyesodconduithaskell-waihaskell-warp

Warp web service with a long lived resource (a file handle)


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


Solution

  • 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)