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
24 import Network.HTTP.Lucu.Utils
28 import Subversion.FileSystem
29 import Subversion.FileSystem.Revision
30 import Subversion.FileSystem.Root
31 import Subversion.Repository
32 import System.FilePath.Posix
33 import System.Log.Logger
35 logger = "Rakka.SystemConfig"
38 data SystemConfig = SystemConfig {
39 scLucuConf :: !LC.Config
40 , scRepository :: !Repository
41 , scCache :: !(TVar (Map FilePath SysConfValue))
50 | Languages (Map LanguageTag LanguageName)
54 mkSystemConfig :: LC.Config -> Repository -> IO SystemConfig
55 mkSystemConfig lc repos
56 = do cache <- newTVarIO M.empty
57 return $ SystemConfig {
59 , scRepository = repos
64 getSysConf :: MonadIO m => SystemConfig -> SysConfValue -> m SysConfValue
68 do let path = sysConfPath key
70 cache <- readTVar (scCache sc)
72 case M.lookup path cache of
73 Just val -> return val
74 Nothing -> do val <- unsafeIOToSTM (getSysConf' sc key)
75 writeTVar (scCache sc) (M.insert path val cache)
79 getSysConf' :: SystemConfig -> SysConfValue -> IO SysConfValue
81 = do let path = fromConfPath (sysConfPath key)
83 fs <- getRepositoryFS (scRepository sc)
84 rev <- getYoungestRev fs
85 value <- withRevision fs rev
86 $ do exists <- isFile path
89 -> do str <- getFileContentsLBS path
90 return $ Just $ chomp $ decodeLazy UTF8 str
96 -> do let val = unmarshalSysConf key str
97 debugM logger ("Got a config value at `" ++ path ++ "': " ++ show val)
100 -> do val <- sysConfDefault sc key
101 debugM logger ("Got no config value at `" ++ path ++ "'. Defaulting to " ++ show val)
105 getSysConfA :: ArrowIO a => SystemConfig -> SysConfValue -> a b SysConfValue
106 getSysConfA = (arrIO0 .) . getSysConf
109 fromConfPath :: FilePath -> FilePath
110 fromConfPath = combine "/config"
113 marshalStringPairs :: [(String, String)] -> String
114 marshalStringPairs = joinWith "\n" . map marshalPair'
116 marshalPair' :: (String, String) -> String
117 marshalPair' (a, b) = a ++ " " ++ b
120 unmarshalStringPairs :: String -> [(String, String)]
121 unmarshalStringPairs = catMaybes . map unmarshalPair' . lines
123 unmarshalPair' :: String -> Maybe (String, String)
124 unmarshalPair' s = case break (/= ' ') s of
125 (a, ' ':b) -> Just (a, b)
130 sysConfPath :: SysConfValue -> FilePath
131 sysConfPath (SiteName _) = "siteName"
132 sysConfPath (BaseURI _) = "baseURI"
133 sysConfPath (DefaultPage _) = "defaultPage"
134 sysConfPath (StyleSheet _) = "styleSheet"
135 sysConfPath (Languages _) = "languages"
139 marshalSysConf :: SysConfValue -> String
140 marshalSysConf (SiteName name ) = name
141 marshalSysConf (BaseURI uri ) = uriToString id uri ""
142 marshalSysConf (DefaultPage name ) = name
143 marshalSysConf (StyleSheet name ) = name
144 marshalSysConf (Languages langs) = marshalStringPairs (M.toList langs)
148 unmarshalSysConf :: SysConfValue -> String -> SysConfValue
149 unmarshalSysConf (SiteName _) name = SiteName name
150 unmarshalSysConf (BaseURI _) uri = BaseURI $ fromJust $ parseURI uri
151 unmarshalSysConf (DefaultPage _) name = DefaultPage name
152 unmarshalSysConf (StyleSheet _) name = StyleSheet name
153 unmarshalSysConf (Languages _) langs = Languages $ M.fromList $ unmarshalStringPairs langs
156 {- getting default value -}
157 sysConfDefault :: SystemConfig -> SysConfValue -> IO SysConfValue
159 sysConfDefault _ (SiteName _)
160 = return $ SiteName "Rakka"
162 sysConfDefault sc (BaseURI _)
163 = do let conf = scLucuConf sc
164 host = C8.unpack $ LC.cnfServerHost conf
165 port = case LC.cnfServerPort conf of
166 PortNumber num -> fromIntegral num
169 = "http://" ++ host ++
172 else ':' : show port) ++ "/"
174 return $ BaseURI $ fromJust $ parseURI defaultURI
176 sysConfDefault _ (DefaultPage _)
177 = return $ DefaultPage "MainPage"
179 sysConfDefault _ (StyleSheet _)
180 = return $ StyleSheet "StyleSheet/Default"
182 sysConfDefault _ (Languages _)
185 $ M.fromList [ ("en", "English" )
189 , ("fr", "Français" )
191 , ("gd", "Gàidhlig" )
193 , ("pt", "Português")