servant-auth-token-0.5.2.0: example/leveldb/src/Monad.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Monad(
ServerEnv(..)
, ServerM
, newServerEnv
, runServerM
, runServerMIO
, AuthM(..)
, runAuth
) where
import Control.Monad.Base
import Control.Monad.Catch (MonadCatch, MonadThrow)
import Control.Monad.Except
import Control.Monad.Logger
import Control.Monad.Reader
import Control.Monad.Trans.Control
import Data.Acid
import Data.Monoid
import Data.Text (unpack)
import Database.LevelDB.MonadResource
import Servant.Server
import Servant.Server.Auth.Token.Config
import Servant.Server.Auth.Token.LevelDB
import Servant.Server.Auth.Token.Model
import Config
-- | Server private environment
data ServerEnv = ServerEnv {
-- | Configuration used to create the server
envConfig :: !ServerConfig
-- | Configuration of auth server
, envAuthConfig :: !AuthConfig
-- | DB state
, envDB :: !LevelDBEnv
}
-- | Create new server environment
newServerEnv :: MonadIO m => ServerConfig -> m ServerEnv
newServerEnv cfg = do
let authConfig = defaultAuthConfig
dbEnv <- liftIO . runResourceT $ do
db <- open (unpack $ serverDbPath cfg) defaultOptions { createIfMissing = True }
dbEnv <- newLevelDBEnv db defaultReadOptions defaultWriteOptions
-- ensure default admin if missing one
_ <- runLevelDBBackendT authConfig dbEnv $ ensureAdmin 17 "admin" "123456" "admin@localhost"
return dbEnv
let env = ServerEnv {
envConfig = cfg
, envAuthConfig = authConfig
, envDB = dbEnv
}
return env
-- | Server monad that holds internal environment
newtype ServerM a = ServerM { unServerM :: ReaderT ServerEnv (LoggingT Handler) a }
deriving (Functor, Applicative, Monad, MonadIO, MonadBase IO, MonadReader ServerEnv
, MonadLogger, MonadLoggerIO, MonadThrow, MonadCatch, MonadError ServantErr)
newtype StMServerM a = StMServerM { unStMServerM :: StM (ReaderT ServerEnv (LoggingT Handler)) a }
instance MonadBaseControl IO ServerM where
type StM ServerM a = StMServerM a
liftBaseWith f = ServerM $ liftBaseWith $ \q -> f (fmap StMServerM . q . unServerM)
restoreM = ServerM . restoreM . unStMServerM
-- | Lift servant monad to server monad
liftHandler :: Handler a -> ServerM a
liftHandler = ServerM . lift . lift
-- | Execution of 'ServerM'
runServerM :: ServerEnv -> ServerM a -> Handler a
runServerM e = runStdoutLoggingT . flip runReaderT e . unServerM
-- | Execution of 'ServerM' in IO monad
runServerMIO :: ServerEnv -> ServerM a -> IO a
runServerMIO env m = do
ea <- runHandler $ runServerM env m
case ea of
Left e -> fail $ "runServerMIO: " <> show e
Right a -> return a
-- | Special monad for authorisation actions
newtype AuthM a = AuthM { unAuthM :: LevelDBBackendT IO a }
deriving (Functor, Applicative, Monad, MonadIO, MonadError ServantErr, HasAuthConfig, HasStorage)
-- | Execution of authorisation actions that require 'AuthHandler' context
runAuth :: AuthM a -> ServerM a
runAuth m = do
cfg <- asks envAuthConfig
db <- asks envDB
liftHandler $ Handler . ExceptT $ runLevelDBBackendT cfg db $ unAuthM m