6
6
{-# LANGUAGE KindSignatures #-}
7
7
{-# LANGUAGE RecordWildCards #-}
8
8
{-# LANGUAGE StandaloneDeriving #-}
9
+ {-# LANGUAGE TupleSections #-}
9
10
module Servant.Server.Internal.RoutingApplication where
10
11
11
12
import Control.Monad (ap , liftM )
12
13
import Control.Monad.Trans (MonadIO (.. ))
14
+ import Control.Monad.Trans.Except (runExceptT )
15
+ import Data.IORef (newIORef , readIORef , writeIORef )
13
16
import Network.Wai (Application , Request ,
14
17
Response , ResponseReceived )
15
18
import Prelude ()
@@ -103,6 +106,10 @@ data Delayed env c where
103
106
, authD :: DelayedIO auth
104
107
, bodyD :: DelayedIO body
105
108
, serverD :: captures -> auth -> body -> Request -> RouteResult c
109
+ , cleanupD :: body -> IO ()
110
+ -- not in DelayedIO because:
111
+ -- - most likely should not depend on the request
112
+ -- - simpler
106
113
} -> Delayed env c
107
114
108
115
instance Functor (Delayed env ) where
@@ -142,7 +149,7 @@ instance MonadIO DelayedIO where
142
149
-- | A 'Delayed' without any stored checks.
143
150
emptyDelayed :: RouteResult a -> Delayed env a
144
151
emptyDelayed result =
145
- Delayed (const r) r r r (\ _ _ _ _ -> result)
152
+ Delayed (const r) r r r (\ _ _ _ _ -> result) ( const $ return () )
146
153
where
147
154
r = return ()
148
155
@@ -196,8 +203,9 @@ addBodyCheck :: Delayed env (a -> b)
196
203
-> Delayed env b
197
204
addBodyCheck Delayed {.. } new =
198
205
Delayed
199
- { bodyD = (,) <$> bodyD <*> new
200
- , serverD = \ c a (z, v) req -> ($ v) <$> serverD c a z req
206
+ { bodyD = (,) <$> bodyD <*> new
207
+ , serverD = \ c a (z, v) req -> ($ v) <$> serverD c a z req
208
+ , cleanupD = cleanupD . fst -- not sure that's right
201
209
, ..
202
210
} -- Note [Existential Record Update]
203
211
@@ -240,13 +248,19 @@ passToServer Delayed{..} x =
240
248
runDelayed :: Delayed env a
241
249
-> env
242
250
-> Request
243
- -> IO (RouteResult a )
244
- runDelayed Delayed {.. } env = runDelayedIO $ do
245
- c <- capturesD env
246
- methodD
247
- a <- authD
248
- b <- bodyD
249
- DelayedIO (\ req -> return $ serverD c a b req)
251
+ -> IO (RouteResult a , IO () )
252
+ runDelayed Delayed {.. } env req = do
253
+ cleanupRef <- newIORef (return () )
254
+ routeRes <- runDelayedIO
255
+ (do c <- capturesD env
256
+ methodD
257
+ a <- authD
258
+ b <- bodyD
259
+ liftIO (writeIORef cleanupRef $ cleanupD b)
260
+ DelayedIO $ \ req -> return (serverD c a b req)
261
+ )
262
+ req
263
+ fmap (routeRes,) $ readIORef cleanupRef
250
264
251
265
-- | Runs a delayed server and the resulting action.
252
266
-- Takes a continuation that lets us send a response.
@@ -258,8 +272,11 @@ runAction :: Delayed env (Handler a)
258
272
-> (RouteResult Response -> IO r )
259
273
-> (a -> RouteResult Response )
260
274
-> IO r
261
- runAction action env req respond k =
262
- runDelayed action env req >>= go >>= respond
275
+ runAction action env req respond k = do
276
+ (routeResult, cleanup) <- runDelayed action env req
277
+ resp <- go routeResult
278
+ cleanup
279
+ respond resp
263
280
where
264
281
go (Fail e) = return $ Fail e
265
282
go (FailFatal e) = return $ FailFatal e
0 commit comments