与使用 Happstack 时通常一样,我一直在制作自己的服务器 monad 用于处理程序,以涵盖我的数据库和会话,以及一些错误处理。我最近发现happstack-clientsession
-Package 有很大帮助,它阻止我编写自己的解决方案。
ClientSessionT
虽然在我自己的单子中接线有点麻烦。事实证明,它没有MonadReader
orMonadError
实例,所以我不能在我的包装器 monad 中实例化它们。
这是模块的完整代码:
{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, DeriveDataTypeable, EmptyDataDecls, TemplateHaskell #-}
module Server where
import Control.Monad
import Control.Monad.Error
import Control.Monad.Reader
import Control.Monad.Trans
import Data.Data (Data, Typeable)
import Data.SafeCopy (base, deriveSafeCopy)
import Database.MongoDB as M
import Happstack.Server
import Happstack.Server.Error
import Happstack.Server.ClientSession
import System.IO.Pool
import System.IO.Error
import Web.ClientSession (getDefaultKey)
type MongoPool e = Pool e Pipe
data PonySession = PonySession -- TODO: Fill in User type when available
deriving (Ord, Read,Show, Eq, Typeable, Data)
$(deriveSafeCopy 0 'base ''PonySession)
instance ClientSession PonySession where
empty = PonySession
newtype PonyServerPartT e m a = PonyServerPart (ClientSessionT PonySession (ReaderT (MongoPool IOError) (ServerPartT (ErrorT e m))) a)
deriving (Monad, MonadIO, MonadReader (MongoPool e), MonadError e, ServerMonad, MonadPlus)
type PonyServerPart = PonyServerPartT IOError IO
runServerT s = mapServerPartT' (spUnwrapErrorT errorHandler) $ do
key <- liftIO getDefaultKey
let sessConf = (mkSessionConf key) { sessionCookieLife = MaxAge $ 60 * 60 * 24 * 7 }
pool <- liftIO mongoPool
runReaderT (runClientSessionT s sessConf) pool
where errorHandler = simpleErrorHandler . show
mongoPool :: IO (MongoPool IOError)
mongoPool = newPool fac 10
where fac = Factory {
newResource = connect $ M.host "127.0.0.1",
killResource = close,
isExpired = isClosed
}
我得到的错误很明显:源自MonadError
并且MonadReader
不起作用。但我需要那些,否则整个表演有点没用。
由于我一直无法弄清楚这些是如何完成的(并且依赖于deriving
),我想要一个涵盖这个特定问题的答案,并告诉我它是如何完成的。