I've read Happstack crashcourse. My web server has almost exact way described in the section Passing multiple AcidState handles around transparently
Problem I have is that, I have value which is non-acidic, but want to access within the Happstack application. Specifically speaking, "PushManager" from push-notify-general library,
What I wanted is:
data Acid = Acid
{ acidCountState :: AcidState CountState
, acidGreetingState :: AcidState GreetingState
, acidPushManager :: AcidState PushManager
}
I couldn't make this work, because 1) PushManager use so many data types internally, and it is not realistic/robust to make underlying data type SafeCopy compatible by calling $(deriveSafeCopy ...). 2) PushManager not only contains simple value, but also function which is SafeCopy compatible.
Other thing I tried is to "Acid" data declaration to carry not only AcidState, but also non-AcidState data. By looking at the definition of runApp, "Acid" is just used for Reading, so I thought that rewriting with State monad may be able to achive my need. - but it turns out that it was not so simple. My tentative code is:
{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving,
TemplateHaskell, TypeFamilies, DeriveDataTypeable,
FlexibleContexts, ScopedTypeVariables,
NamedFieldPuns, DeriveFunctor, StandaloneDeriving, OverloadedStrings #-}
import Control.Applicative ( Applicative, Alternative, (<$>))
import Control.Monad ( MonadPlus )
import Control.Monad.State.Strict ( MonadState, StateT, get, put, evalStateT )
import Control.Monad.Trans ( MonadIO )
import Data.Acid
import Data.Data ( Data, Typeable )
import Happstack.Server
newtype Simple a = Simple { unSimple :: a }
deriving (Show)
data CountState = CountState { count :: Integer }
deriving (Eq, Ord, Data, Typeable, Show)
-- This data is equivalent to the one previously called "Acid"
data States = States {
simpleState :: Simple Int
, acidCountState :: AcidState CountState
}
initialStates :: States
initialStates = States { simpleState = Simple 1, acidCountState = undefined }
newtype App a = App { unApp :: ServerPartT (StateT States IO) a }
deriving ( Functor, Alternative, Applicative, Monad
, MonadPlus, MonadIO, HasRqData, ServerMonad
, WebMonad Response, FilterMonad Response
, Happstack, MonadState States )
class HasSimple m st where
getSimple :: m (Simple st)
putSimple :: (Simple st) -> m ()
instance HasSimple App Int where
getSimple = simpleState <$> get
putSimple input = do
whole <- get
put $ whole {simpleState = input}
simpleQuery :: ( Functor m
, HasSimple m a
, MonadIO m
, Show a
) =>
m a
simpleQuery = do
(Simple a) <- getSimple
return a
simpleUpdate :: ( Functor m
, HasSimple m a
, MonadIO m
, Show a
) =>
a
-> m ()
simpleUpdate a = putSimple (Simple a)
runApp :: States -> App a -> ServerPartT IO a
runApp states (App sp) = do
mapServerPartT (flip evalStateT states) sp
rootDir :: App Response
rootDir = do
intVal <- simpleQuery
let newIntVal :: Int
newIntVal = intVal + 1
simpleUpdate newIntVal
ok $ toResponse $ ("hello number:" ++ (show newIntVal))
main :: IO ()
main = do
simpleHTTP nullConf $ runApp initialStates rootDir
It compiled, but every time web page is requested, the page display same number. Looking at my code again, and I felt that evalStateT in runApp is wrong, because it never use updated state value.
Now, I am reading mapServerPartT and ServerPartT, but that is too complex. Appreciate if anybody can answer the title line: "How to carry non-Acidic value in Happstack?"