1 module Rakka.SystemConfig
5 , mkSystemConfig -- private
12 import Control.Arrow.ArrowIO
13 import Control.Concurrent.STM
14 import Control.Monad.Trans
15 import qualified Data.ByteString.Char8 as C8
17 import Data.Encoding.UTF8
19 import qualified Data.Map as M
21 import GHC.Conc (unsafeIOToSTM)
23 import qualified Network.HTTP.Lucu.Config as LC
26 import Subversion.FileSystem
27 import Subversion.FileSystem.Revision
28 import Subversion.FileSystem.Root
29 import Subversion.Repository
30 import System.FilePath.Posix
31 import System.Log.Logger
33 logger = "Rakka.SystemConfig"
36 data SystemConfig = SystemConfig {
37 scLucuConf :: !LC.Config
38 , scRepository :: !Repository
39 , scCache :: !(TVar (Map FilePath SysConfValue))
51 mkSystemConfig :: LC.Config -> Repository -> IO SystemConfig
52 mkSystemConfig lc repos
53 = do cache <- newTVarIO M.empty
54 return $ SystemConfig {
56 , scRepository = repos
61 getSysConf :: MonadIO m => SystemConfig -> SysConfValue -> m SysConfValue
65 do let path = sysConfPath key
67 cache <- readTVar (scCache sc)
69 case M.lookup path cache of
70 Just val -> return val
71 Nothing -> do val <- unsafeIOToSTM (getSysConf' sc key)
72 writeTVar (scCache sc) (M.insert path val cache)
76 getSysConf' :: SystemConfig -> SysConfValue -> IO SysConfValue
78 = do let path = fromConfPath (sysConfPath key)
80 fs <- getRepositoryFS (scRepository sc)
81 rev <- getYoungestRev fs
82 value <- withRevision fs rev
83 $ do exists <- isFile path
86 -> do str <- getFileContentsLBS path
87 return $ Just $ chomp $ decodeLazy UTF8 str
93 -> do let val = unmarshalSysConf key str
94 debugM logger ("Got a config value at `" ++ path ++ "': " ++ show val)
97 -> do val <- sysConfDefault sc key
98 debugM logger ("Got no config value at `" ++ path ++ "'. Defaulting to " ++ show val)
102 getSysConfA :: ArrowIO a => SystemConfig -> SysConfValue -> a b SysConfValue
103 getSysConfA = (arrIO0 .) . getSysConf
106 fromConfPath :: FilePath -> FilePath
107 fromConfPath = combine "/config"
111 sysConfPath :: SysConfValue -> FilePath
112 sysConfPath (SiteName _) = "siteName"
113 sysConfPath (BaseURI _) = "baseURI"
114 sysConfPath (DefaultPage _) = "defaultPage"
115 sysConfPath (StyleSheet _) = "styleSheet"
119 marshalSysConf :: SysConfValue -> String
120 marshalSysConf (SiteName name) = name
121 marshalSysConf (BaseURI uri ) = uriToString id uri ""
122 marshalSysConf (DefaultPage name) = name
123 marshalSysConf (StyleSheet name) = name
127 unmarshalSysConf :: SysConfValue -> String -> SysConfValue
128 unmarshalSysConf (SiteName _) name = SiteName name
129 unmarshalSysConf (BaseURI _) uri = BaseURI $ fromJust $ parseURI uri
130 unmarshalSysConf (DefaultPage _) name = DefaultPage name
131 unmarshalSysConf (StyleSheet _) name = StyleSheet name
134 {- getting default value -}
135 sysConfDefault :: SystemConfig -> SysConfValue -> IO SysConfValue
137 sysConfDefault _ (SiteName _)
138 = return $ SiteName "Rakka"
140 sysConfDefault sc (BaseURI _)
141 = do let conf = scLucuConf sc
142 host = C8.unpack $ LC.cnfServerHost conf
143 port = case LC.cnfServerPort conf of
144 PortNumber num -> fromIntegral num
147 = "http://" ++ host ++
150 else ':' : show port) ++ "/"
152 return $ BaseURI $ fromJust $ parseURI defaultURI
154 sysConfDefault _ (DefaultPage _)
155 = return $ DefaultPage "MainPage"
157 sysConfDefault _ (StyleSheet _)
158 = return $ StyleSheet "StyleSheet/Default"