add a field in Delayed that lets us specify a clean up action that can use the result of bodyD to perform some IO clean up operation

This commit is contained in:
Alp Mestanogullari 2016-10-15 12:02:30 +02:00 committed by Oleg Grenrus
parent cce0f59ec8
commit 124c6de1eb
2 changed files with 30 additions and 13 deletions

View file

@ -400,7 +400,7 @@ instance HasServer Raw context where
type ServerT Raw m = Application type ServerT Raw m = Application
route Proxy _ rawApplication = RawRouter $ \ env request respond -> do route Proxy _ rawApplication = RawRouter $ \ env request respond -> do
r <- runDelayed rawApplication env request (r, _) <- runDelayed rawApplication env request
case r of case r of
Route app -> app request (respond . Route) Route app -> app request (respond . Route)
Fail a -> respond $ Fail a Fail a -> respond $ Fail a

View file

@ -6,10 +6,13 @@
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TupleSections #-}
module Servant.Server.Internal.RoutingApplication where module Servant.Server.Internal.RoutingApplication where
import Control.Monad (ap, liftM) import Control.Monad (ap, liftM)
import Control.Monad.Trans (MonadIO(..)) import Control.Monad.Trans (MonadIO(..))
import Control.Monad.Trans.Except (runExceptT)
import Data.IORef (newIORef, readIORef, writeIORef)
import Network.Wai (Application, Request, import Network.Wai (Application, Request,
Response, ResponseReceived) Response, ResponseReceived)
import Prelude () import Prelude ()
@ -103,6 +106,10 @@ data Delayed env c where
, authD :: DelayedIO auth , authD :: DelayedIO auth
, bodyD :: DelayedIO body , bodyD :: DelayedIO body
, serverD :: captures -> auth -> body -> Request -> RouteResult c , serverD :: captures -> auth -> body -> Request -> RouteResult c
, cleanupD :: body -> IO ()
-- not in DelayedIO because:
-- - most likely should not depend on the request
-- - simpler
} -> Delayed env c } -> Delayed env c
instance Functor (Delayed env) where instance Functor (Delayed env) where
@ -142,7 +149,7 @@ instance MonadIO DelayedIO where
-- | A 'Delayed' without any stored checks. -- | A 'Delayed' without any stored checks.
emptyDelayed :: RouteResult a -> Delayed env a emptyDelayed :: RouteResult a -> Delayed env a
emptyDelayed result = emptyDelayed result =
Delayed (const r) r r r (\ _ _ _ _ -> result) Delayed (const r) r r r (\ _ _ _ _ -> result) (const $ return ())
where where
r = return () r = return ()
@ -198,6 +205,7 @@ addBodyCheck Delayed{..} new =
Delayed Delayed
{ bodyD = (,) <$> bodyD <*> new { bodyD = (,) <$> bodyD <*> new
, serverD = \ c a (z, v) req -> ($ v) <$> serverD c a z req , serverD = \ c a (z, v) req -> ($ v) <$> serverD c a z req
, cleanupD = cleanupD . fst -- not sure that's right
, .. , ..
} -- Note [Existential Record Update] } -- Note [Existential Record Update]
@ -240,13 +248,19 @@ passToServer Delayed{..} x =
runDelayed :: Delayed env a runDelayed :: Delayed env a
-> env -> env
-> Request -> Request
-> IO (RouteResult a) -> IO (RouteResult a, IO ())
runDelayed Delayed{..} env = runDelayedIO $ do runDelayed Delayed{..} env req = do
c <- capturesD env cleanupRef <- newIORef (return ())
routeRes <- runDelayedIO
(do c <- capturesD env
methodD methodD
a <- authD a <- authD
b <- bodyD b <- bodyD
DelayedIO (\ req -> return $ serverD c a b req) liftIO (writeIORef cleanupRef $ cleanupD b)
DelayedIO $ \ req -> return (serverD c a b req)
)
req
fmap (routeRes,) $ readIORef cleanupRef
-- | Runs a delayed server and the resulting action. -- | Runs a delayed server and the resulting action.
-- Takes a continuation that lets us send a response. -- Takes a continuation that lets us send a response.
@ -258,8 +272,11 @@ runAction :: Delayed env (Handler a)
-> (RouteResult Response -> IO r) -> (RouteResult Response -> IO r)
-> (a -> RouteResult Response) -> (a -> RouteResult Response)
-> IO r -> IO r
runAction action env req respond k = runAction action env req respond k = do
runDelayed action env req >>= go >>= respond (routeResult, cleanup) <- runDelayed action env req
resp <- go routeResult
cleanup
respond resp
where where
go (Fail e) = return $ Fail e go (Fail e) = return $ Fail e
go (FailFatal e) = return $ FailFatal e go (FailFatal e) = return $ FailFatal e