@@ -1,24 +1,32 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE DeriveFunctor #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE TypeOperators #-}
5{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE KindSignatures #-}
6{-# LANGUAGE KindSignatures #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE RecordWildCards #-}
9{-# LANGUAGE RecordWildCards #-}
8{-# LANGUAGE StandaloneDeriving #-}
10{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE TupleSections #-}
11{-# LANGUAGE TupleSections #-}
12+{-# LANGUAGE TypeFamilies #-}
13+{-# LANGUAGE TypeOperators #-}
14+{-# LANGUAGE UndecidableInstances #-}
10module Servant.Server.Internal.RoutingApplication where
15module Servant.Server.Internal.RoutingApplication where
12−import Control.Exception (finally)
13import Control.Monad (ap, liftM)
17import Control.Monad (ap, liftM)
14−import Control.Monad.Trans (MonadIO(..))
18+import Control.Monad.Base (MonadBase (..))
15−import Data.IORef (newIORef, readIORef, IORef, atomicModifyIORef)
19+import Control.Monad.Catch (MonadThrow (..))
20+import Control.Monad.Reader (MonadReader (..), ReaderT, runReaderT)
21+import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
22+import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..), MonadTransControl (..),
23+ defaultLiftBaseWith, defaultRestoreM)
24+import Control.Monad.Trans.Resource (MonadResource (..), ResourceT, runResourceT)
16−import Network.Wai (Application, Request,
25+import Network.Wai (Application, Request, Response, ResponseReceived)
17− Response, ResponseReceived)
18import Prelude ()
26import Prelude ()
19import Prelude.Compat
27import Prelude.Compat
20−import Servant.Server.Internal.ServantErr
21import Servant.Server.Internal.Handler
28import Servant.Server.Internal.Handler
29+import Servant.Server.Internal.ServantErr
23type RoutingApplication =
31type RoutingApplication =
24 Request -- ^ the request, the field 'pathInfo' may be modified by url routing
32 Request -- ^ the request, the field 'pathInfo' may be modified by url routing
@@ -32,6 +40,58 @@ data RouteResult a =
32 | Route !a
40 | Route !a
33 deriving (Eq, Show, Read, Functor)
41 deriving (Eq, Show, Read, Functor)
43+instance Applicative RouteResult where
47+instance Monad RouteResult where
50+ Fail e >>= _ = Fail e
51+ FailFatal e >>= _ = FailFatal e
53+newtype RouteResultT m a = RouteResultT { runRouteResultT :: m (RouteResult a) }
56+-- As we write these instances, we get instances for `DelayedIO` with GND.
57+instance MonadTrans RouteResultT where
58+ lift = RouteResultT . liftM Route
60+instance (Functor m, Monad m) => Applicative (RouteResultT m) where
64+instance Monad m => Monad (RouteResultT m) where
65+ return = RouteResultT . return . Route
66+ m >>= k = RouteResultT $ do
67+ a <- runRouteResultT m
69+ Fail e -> return $ Fail e
70+ FailFatal e -> return $ FailFatal e
71+ Route b -> runRouteResultT (k b)
73+instance MonadIO m => MonadIO (RouteResultT m) where
74+ liftIO = lift . liftIO
76+instance MonadBase b m => MonadBase b (RouteResultT m) where
77+ liftBase = lift . liftBase
79+instance MonadBaseControl b m => MonadBaseControl b (RouteResultT m) where
80+ type StM (RouteResultT m) a = ComposeSt RouteResultT m a
81+ liftBaseWith = defaultLiftBaseWith
82+ restoreM = defaultRestoreM
84+instance MonadTransControl RouteResultT where
85+ type StT RouteResultT a = RouteResult a
86+ liftWith f = RouteResultT $ liftM return $ f $ runRouteResultT
87+ restoreT = RouteResultT
89+instance MonadThrow m => MonadThrow (RouteResultT m) where
90+ throwM = lift . throwM
92+-- instance MonadCatch m => MonadCatch (RouteResultT m) where
93+-- instance MonadError ServantErr (RouteResultT m) where
35toApplication :: RoutingApplication -> Application
95toApplication :: RoutingApplication -> Application
36toApplication ra request respond = ra request routingRespond
96toApplication ra request respond = ra request routingRespond
@@ -115,53 +175,30 @@ instance Functor (Delayed env) where
116 } -- Note [Existential Record Update]
176 } -- Note [Existential Record Update]
118−-- | A mutable cleanup action
119−newtype CleanupRef = CleanupRef (IORef (IO ()))
121−newCleanupRef :: IO CleanupRef
122−newCleanupRef = CleanupRef <$> newIORef (return ())
124−-- | Add a clean up action to a 'CleanupRef'
125−addCleanup' :: IO () -> CleanupRef -> IO ()
126−addCleanup' act (CleanupRef ref) = atomicModifyIORef ref (\act' -> (act' >> act, ()))
128−addCleanup :: IO () -> DelayedIO ()
129−addCleanup act = DelayedIO $ \_req cleanupRef ->
130− addCleanup' act cleanupRef >> return (Route ())
132−-- | Run all the clean up actions registered in
134−runCleanup :: CleanupRef -> IO ()
135−runCleanup (CleanupRef ref) = do
136− act <- readIORef ref
139-- | Computations used in a 'Delayed' can depend on the
178-- | Computations used in a 'Delayed' can depend on the
140-- incoming 'Request', may perform 'IO, and result in a
179-- incoming 'Request', may perform 'IO, and result in a
141-- 'RouteResult, meaning they can either suceed, fail
180-- 'RouteResult, meaning they can either suceed, fail
142-- (with the possibility to recover), or fail fatally.
181-- (with the possibility to recover), or fail fatally.
144−newtype DelayedIO a = DelayedIO { runDelayedIO :: Request -> CleanupRef -> IO (RouteResult a) }
183+newtype DelayedIO a = DelayedIO { runDelayedIO' :: ReaderT Request (ResourceT (RouteResultT IO)) a }
146−instance Functor DelayedIO where
185+ ( Functor, Applicative, Monad
147− fmap = liftM
186+ , MonadIO, MonadReader Request
149−instance Applicative DelayedIO where
192+returnRouteResult :: RouteResult a -> DelayedIO a
150− pure = return
193+returnRouteResult x = DelayedIO $ lift . lift $ RouteResultT . return $ x
153−instance Monad DelayedIO where
195+instance MonadBaseControl IO DelayedIO where
154− return x = DelayedIO (\_req _cleanup -> return (Route x))
196+ type StM DelayedIO a = StM (ReaderT Request (ResourceT (RouteResultT IO))) a
155− DelayedIO m >>= f =
197+ liftBaseWith f = DelayedIO $ liftBaseWith $ \g -> f (g . runDelayedIO')
156− DelayedIO $ \ req cl -> do
198+ restoreM = DelayedIO . restoreM
159− Fail e -> return $ Fail e
160− FailFatal e -> return $ FailFatal e
161− Route a -> runDelayedIO (f a) req cl
163−instance MonadIO DelayedIO where
200+runDelayedIO :: DelayedIO a -> Request -> IO (RouteResult a)
164− liftIO m = DelayedIO (\_req _cl -> Route <$> m)
201+runDelayedIO m req = runRouteResultT $ runResourceT $ runReaderT (runDelayedIO' m) req
166-- | A 'Delayed' without any stored checks.
203-- | A 'Delayed' without any stored checks.
167emptyDelayed :: RouteResult a -> Delayed env a
204emptyDelayed :: RouteResult a -> Delayed env a
@@ -172,15 +209,17 @@ emptyDelayed result =
173-- | Fail with the option to recover.
210-- | Fail with the option to recover.
174delayedFail :: ServantErr -> DelayedIO a
211delayedFail :: ServantErr -> DelayedIO a
175−delayedFail err = DelayedIO (\_req _cleanup -> return $ Fail err)
212+delayedFail err = returnRouteResult $ Fail err
177-- | Fail fatally, i.e., without any option to recover.
214-- | Fail fatally, i.e., without any option to recover.
178delayedFailFatal :: ServantErr -> DelayedIO a
215delayedFailFatal :: ServantErr -> DelayedIO a
179−delayedFailFatal err = DelayedIO (\_req _cleanup -> return $ FailFatal err)
216+delayedFailFatal err = returnRouteResult $ FailFatal err
181-- | Gain access to the incoming request.
218-- | Gain access to the incoming request.
182withRequest :: (Request -> DelayedIO a) -> DelayedIO a
219withRequest :: (Request -> DelayedIO a) -> DelayedIO a
183−withRequest f = DelayedIO (\ req cl -> runDelayedIO (f req) req cl)
220+withRequest f = do
185-- | Add a capture to the end of the capture block.
224-- | Add a capture to the end of the capture block.
186addCapture :: Delayed env (a -> b)
225addCapture :: Delayed env (a -> b)
@@ -264,18 +303,17 @@ passToServer Delayed{..} x =
264runDelayed :: Delayed env a
303runDelayed :: Delayed env a
266 -> Request
305 -> Request
268 -> IO (RouteResult a)
306 -> IO (RouteResult a)
269−runDelayed Delayed{..} env req cleanupRef =
307+runDelayed Delayed{..} env req =
270 runDelayedIO
308 runDelayedIO
271 (do c <- capturesD env
309 (do c <- capturesD env
273 a <- authD
311 a <- authD
274 b <- bodyD
312 b <- bodyD
275− DelayedIO $ \ r _cleanup -> return (serverD c a b r)
313+ r <- ask
314+ returnRouteResult (serverD c a b r)
280-- | Runs a delayed server and the resulting action.
318-- | Runs a delayed server and the resulting action.
281-- Takes a continuation that lets us send a response.
319-- Takes a continuation that lets us send a response.
@@ -288,10 +326,7 @@ runAction :: Delayed env (Handler a)
288 -> (a -> RouteResult Response)
326 -> (a -> RouteResult Response)
290runAction action env req respond k = do
328runAction action env req respond k = do
291− cleanupRef <- newCleanupRef
292− (runDelayed action env req cleanupRef >>= go >>= respond)
329+ runDelayed action env req >>= go >>= respond
293− `finally` runCleanup cleanupRef
296 go (Fail e) = return $ Fail e
331 go (Fail e) = return $ Fail e
297 go (FailFatal e) = return $ FailFatal e
332 go (FailFatal e) = return $ FailFatal e