yesod-core: New handlerToIO function.
This commit is contained in:
parent
d94a95da3e
commit
60046bad96
@ -95,6 +95,7 @@ module Yesod.Handler
|
|||||||
, newIdent
|
, newIdent
|
||||||
-- * Lifting
|
-- * Lifting
|
||||||
, MonadLift (..)
|
, MonadLift (..)
|
||||||
|
, handlerToIO
|
||||||
-- * i18n
|
-- * i18n
|
||||||
, getMessageRender
|
, getMessageRender
|
||||||
-- * Per-request caching
|
-- * Per-request caching
|
||||||
@ -177,6 +178,7 @@ import Control.Exception.Lifted (catch)
|
|||||||
import Control.Monad.Trans.Control
|
import Control.Monad.Trans.Control
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import Control.Monad.Base
|
import Control.Monad.Base
|
||||||
|
import Data.Conduit.List (sourceList)
|
||||||
import Yesod.Routes.Class
|
import Yesod.Routes.Class
|
||||||
import Data.Word (Word64)
|
import Data.Word (Word64)
|
||||||
import Language.Haskell.TH.Syntax (Loc)
|
import Language.Haskell.TH.Syntax (Loc)
|
||||||
@ -391,6 +393,68 @@ getCurrentRoute = handlerRoute `liftM` ask
|
|||||||
getRouteToMaster :: GHandler sub master (Route sub -> Route master)
|
getRouteToMaster :: GHandler sub master (Route sub -> Route master)
|
||||||
getRouteToMaster = handlerToMaster `liftM` ask
|
getRouteToMaster = handlerToMaster `liftM` ask
|
||||||
|
|
||||||
|
|
||||||
|
-- | Returns a function that runs 'GHandler' actions inside @IO@.
|
||||||
|
--
|
||||||
|
-- Sometimes you want to run an inner 'GHandler' action outside
|
||||||
|
-- the control flow of an HTTP request (on the outer 'GHandler'
|
||||||
|
-- action). For example, you may want to spawn a new thread:
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- getFooR :: Handler RepHtml
|
||||||
|
-- getFooR = do
|
||||||
|
-- runHandler <- handlerToIO
|
||||||
|
-- liftIO $ forkIO $ runHandler $ do
|
||||||
|
-- /Code here runs inside GHandler but on a new thread./
|
||||||
|
-- /This is the inner GHandler./
|
||||||
|
-- ...
|
||||||
|
-- /Code here runs inside the request's control flow./
|
||||||
|
-- /This is the outer GHandler./
|
||||||
|
-- ...
|
||||||
|
-- @
|
||||||
|
--
|
||||||
|
-- Another use case for this function is creating a stream of
|
||||||
|
-- server-sent events using 'GHandler' actions (see
|
||||||
|
-- @yesod-eventsource@).
|
||||||
|
--
|
||||||
|
-- Most of the environment from the outer 'GHandler' is preserved
|
||||||
|
-- on the inner 'GHandler', however:
|
||||||
|
--
|
||||||
|
-- * The request body is cleared (otherwise it would be very
|
||||||
|
-- difficult to prevent huge memory leaks).
|
||||||
|
--
|
||||||
|
-- * The cache is cleared (see 'CacheKey').
|
||||||
|
--
|
||||||
|
-- Changes to the response made inside the inner 'GHandler' are
|
||||||
|
-- ignored (e.g., session variables, cookies, response headers).
|
||||||
|
-- This allows the inner 'GHandler' to outlive the outer
|
||||||
|
-- 'GHandler' (e.g., on the @forkIO@ example above, a response
|
||||||
|
-- may be sent to the client without killing the new thread).
|
||||||
|
handlerToIO :: MonadIO m => GHandler sub master (GHandler sub master a -> m a)
|
||||||
|
handlerToIO =
|
||||||
|
GHandler $ \oldHandlerData -> do
|
||||||
|
-- Let go of the request body, cache and response headers.
|
||||||
|
let oldReq = handlerRequest oldHandlerData
|
||||||
|
oldWaiReq = reqWaiRequest oldReq
|
||||||
|
newWaiReq = oldWaiReq { W.requestBody = sourceList [] }
|
||||||
|
newReq = oldReq { reqWaiRequest = newWaiReq
|
||||||
|
, reqBodySize = 0 }
|
||||||
|
newState <- liftIO $ do
|
||||||
|
oldState <- I.readIORef (handlerState oldHandlerData)
|
||||||
|
return $ oldState { ghsRBC = Nothing
|
||||||
|
, ghsIdent = 1
|
||||||
|
, ghsCache = mempty
|
||||||
|
, ghsHeaders = mempty }
|
||||||
|
|
||||||
|
-- Return GHandler running function.
|
||||||
|
return $ \(GHandler f) -> liftIO $ do
|
||||||
|
-- The state IORef needs to be created here, otherwise it
|
||||||
|
-- will be shared by different invocations of this function.
|
||||||
|
newStateIORef <- I.newIORef newState
|
||||||
|
runResourceT $ f oldHandlerData { handlerRequest = newReq
|
||||||
|
, handlerState = newStateIORef }
|
||||||
|
|
||||||
|
|
||||||
-- | Function used internally by Yesod in the process of converting a
|
-- | Function used internally by Yesod in the process of converting a
|
||||||
-- 'GHandler' into an 'W.Application'. Should not be needed by users.
|
-- 'GHandler' into an 'W.Application'. Should not be needed by users.
|
||||||
runHandler :: HasReps c
|
runHandler :: HasReps c
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user