clckwrks-0.13.0: Clckwrks/Acid.hs
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
module Clckwrks.Acid where
import Clckwrks.Menu.Acid (MenuState , initialMenuState)
import Clckwrks.Page.Acid (PageState , initialPageState)
import Clckwrks.ProfileData.Acid (ProfileDataState, initialProfileDataState)
import Clckwrks.URL (ClckURL)
import Control.Exception (bracket, catch, throw)
import Control.Concurrent (killThread, forkIO)
import Data.Acid (AcidState)
import Data.Acid.Local (openLocalStateFrom, createArchive, createCheckpointAndClose)
import Data.Acid.Remote (acidServer)
import Data.Maybe (fromMaybe)
import Happstack.Auth.Core.Auth (AuthState , initialAuthState)
import Happstack.Auth.Core.Profile (ProfileState , initialProfileState)
import Network (PortID(UnixSocket))
import Prelude hiding (catch)
import System.Directory (removeFile)
import System.FilePath ((</>))
import System.IO.Error (isDoesNotExistError)
data Acid = Acid
{ acidAuth :: AcidState AuthState
, acidProfile :: AcidState ProfileState
, acidProfileData :: AcidState ProfileDataState
, acidPage :: AcidState PageState
, acidMenu :: AcidState (MenuState ClckURL)
}
class GetAcidState m st where
getAcidState :: m (AcidState st)
withAcid :: Maybe FilePath -> (Acid -> IO a) -> IO a
withAcid mBasePath f =
let basePath = fromMaybe "_state" mBasePath in
initialPageState >>= \ips ->
bracket (openLocalStateFrom (basePath </> "auth") initialAuthState) (createArchiveCheckpointAndClose) $ \auth ->
bracket (openLocalStateFrom (basePath </> "profile") initialProfileState) (createArchiveCheckpointAndClose) $ \profile ->
bracket (openLocalStateFrom (basePath </> "profileData") initialProfileDataState) (createArchiveCheckpointAndClose) $ \profileData ->
bracket (openLocalStateFrom (basePath </> "page") ips) (createArchiveCheckpointAndClose) $ \page ->
bracket (openLocalStateFrom (basePath </> "menu") initialMenuState) (createArchiveCheckpointAndClose) $ \menu ->
bracket (forkIO $ tryRemoveFile (basePath </> "profileData_socket") >> acidServer profileData (UnixSocket $ basePath </> "profileData_socket"))
(\tid -> killThread tid >> tryRemoveFile (basePath </> "profileData_socket"))
(const $ f (Acid auth profile profileData page menu))
where
tryRemoveFile fp = removeFile fp `catch` (\e -> if isDoesNotExistError e then return () else throw e)
createArchiveCheckpointAndClose acid =
do createArchive acid
createCheckpointAndClose acid