module Web.Respond.Monad (
MonadRespond(..),
RespondT,
runRespondT,
mapRespondT,
FailureHandlers(..),
unsupportedMethod,
unmatchedPath,
bodyParseFailed,
authFailed,
accessDenied,
caughtException,
unacceptableResponse
) where
import Control.Applicative
import Network.Wai
import Network.HTTP.Types.Method
import Control.Monad.Trans.Reader (ReaderT, runReaderT, mapReaderT)
import Control.Monad.Trans.Maybe (MaybeT, mapMaybeT)
import Control.Monad.Trans.Except (ExceptT, mapExceptT)
import Control.Monad.Reader.Class
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Base (MonadBase, liftBase, liftBaseDefault)
import Control.Monad.Trans.Control (MonadTransControl, StT, liftWith, restoreT, defaultLiftWith, defaultRestoreT, MonadBaseControl, StM, liftBaseWith, defaultLiftBaseWith, restoreM, defaultRestoreM, ComposeSt)
import Control.Monad.Trans.Class
import Control.Monad.Logger
import Control.Monad.Catch
import Control.Lens ((%~), makeLenses, view)
import Web.Respond.Types
class (Functor m, MonadIO m) => MonadRespond m where
respond :: Response -> m ResponseReceived
getRequest :: m Request
getHandlers :: m FailureHandlers
withHandlers :: (FailureHandlers -> FailureHandlers) -> m a -> m a
getPath :: m PathConsumer
withPath :: (PathConsumer -> PathConsumer) -> m a -> m a
instance MonadRespond m => MonadRespond (ExceptT e m) where
respond = lift . respond
getRequest = lift getRequest
getHandlers = lift getHandlers
withHandlers = mapExceptT . withHandlers
getPath = lift getPath
withPath = mapExceptT . withPath
instance MonadRespond m => MonadRespond (MaybeT m) where
respond = lift . respond
getRequest = lift getRequest
getHandlers = lift getHandlers
withHandlers = mapMaybeT . withHandlers
getPath = lift getPath
withPath = mapMaybeT . withPath
data FailureHandlers = FailureHandlers {
_unsupportedMethod :: MonadRespond m => [StdMethod] -> Method -> m ResponseReceived,
_unmatchedPath :: MonadRespond m => m ResponseReceived,
_bodyParseFailed :: (MonadRespond m, ReportableError e) => e -> m ResponseReceived,
_authFailed :: (MonadRespond m, ReportableError e) => e -> m ResponseReceived,
_accessDenied :: (MonadRespond m, ReportableError e) => e -> m ResponseReceived,
_caughtException :: (MonadRespond m, ReportableError e) => e -> m ResponseReceived,
_unacceptableResponse :: (MonadRespond m) => m ResponseReceived
}
makeLenses ''FailureHandlers
data RespondData = RespondData {
_handlers :: FailureHandlers,
_request :: Request,
_responder :: Responder,
_pathConsumer :: PathConsumer
}
makeLenses ''RespondData
newtype RespondT m a = RespondT {
unRespondT :: ReaderT RespondData m a
} deriving (Functor, Applicative, Monad, MonadReader RespondData)
instance (Functor m, MonadIO m) => MonadRespond (RespondT m) where
respond v = view responder >>= \r -> liftIO . r $ v
getRequest = view request
getHandlers = view handlers
withHandlers h = local (handlers %~ h)
getPath = view pathConsumer
withPath f = local (pathConsumer %~ f)
runRespondT :: RespondT m a -> FailureHandlers -> Request -> Responder -> m a
runRespondT (RespondT act) h req res = runReaderT act $ RespondData h req res (mkPathConsumer $ pathInfo req)
mapRespondT :: (m a -> n b) -> RespondT m a -> RespondT n b
mapRespondT f = RespondT . mapReaderT f . unRespondT
instance MonadTrans RespondT where
lift act = RespondT $ lift act
instance MonadIO m => MonadIO (RespondT m) where
liftIO act = RespondT $ liftIO act
instance MonadThrow m => MonadThrow (RespondT m) where
throwM = lift . throwM
instance MonadCatch m => MonadCatch (RespondT m) where
catch act h = RespondT $ catch (unRespondT act) (\e -> unRespondT (h e))
instance MonadBase b m => MonadBase b (RespondT m) where
liftBase = liftBaseDefault
instance MonadTransControl RespondT where
newtype StT RespondT a = StRespond { unStRespond :: StT (ReaderT RespondData) a }
liftWith = defaultLiftWith RespondT unRespondT StRespond
restoreT = defaultRestoreT RespondT unStRespond
instance MonadBaseControl b m => MonadBaseControl b (RespondT m) where
newtype StM (RespondT m) a = StMT { unStMT :: ComposeSt RespondT m a}
liftBaseWith = defaultLiftBaseWith StMT
restoreM = defaultRestoreM unStMT
instance MonadLogger m => MonadLogger (RespondT m) where
monadLoggerLog loc src level msg = lift $ monadLoggerLog loc src level msg