module Rakka.Storage ( Storage , mkStorage -- private , getPage , putPage , getPageA , putPageA ) where import Control.Arrow.ArrowIO import Control.Concurrent.STM import Control.Monad import Control.Monad.Trans import Data.Set (Set) import Rakka.Page import Rakka.Storage.DefaultPage import Subversion.Types import System.Directory import System.FilePath import System.Log.Logger import Subversion.Repository import Text.HyperEstraier -- FIXME import Data.Encoding import Data.Encoding.UTF8 import qualified Data.ByteString.Lazy.Char8 as C8 -- FIXME logger = "Rakka.Storage" data Storage = Storage { stoIndexRevLocked :: !(TVar Bool) , stoIndexRevFile :: !FilePath , stoIndexDB :: !Database , stoRepository :: !Repository , stoMakeDraft :: !(Page -> IO Document) } mkStorage :: FilePath -> Repository -> (Page -> IO Document) -> IO Storage mkStorage lsdir repos mkDraft = do let indexDir = lsdir `combine` "index" revFile = lsdir `combine` "indexRev" revLocked <- newTVarIO False indexDB <- openIndex indexDir revFile let sto = Storage { stoIndexRevLocked = revLocked , stoIndexRevFile = revFile , stoIndexDB = indexDB , stoRepository = repos , stoMakeDraft = mkDraft } syncIndex sto return sto getPage :: MonadIO m => Storage -> PageName -> m (Maybe Page) getPage sto name = liftIO $ loadDefaultPage name -- FIXME putPage :: MonadIO m => Storage -> Maybe RevNum -> Page -> m () putPage sto oldRev page = error "FIXME: not implemented" getPageA :: ArrowIO a => Storage -> a PageName (Maybe Page) getPageA = arrIO . getPage putPageA :: ArrowIO a => Storage -> a (Maybe RevNum, Page) () putPageA = arrIO2 . putPage findAllPages :: Storage -> RevNum -> IO (Set PageName) findAllPages sto revNum = findAllDefaultPages -- FIXME -- casket を R/W モードで開く。成功したらそのまま返し、失敗したら -- indexDir と revFile を削除してから casket を R/W モードで開く。 openIndex :: FilePath -> FilePath -> IO Database openIndex indexDir revFile = do ret <- openDatabase indexDir (Writer []) case ret of Right db -> do debugM logger ("Opened an H.E. database on " ++ indexDir) return db Left err -> do warningM logger ("Failed to open an H.E. database on " ++ indexDir ++ ": " ++ show err) indexExists <- doesDirectoryExist indexDir when indexExists $ removeDirectoryRecursive indexDir revFileExists <- doesFileExist revFile when revFileExists $ removeFile revFile Right db <- openDatabase indexDir (Writer [Create []]) noticeM logger ("Created an H.E. database on " ++ indexDir) return db syncIndex :: Storage -> IO () syncIndex sto = do Just page <- getPage sto "MainPage" doc <- stoMakeDraft sto page putStrLn "*** dumping draft..." dumpDraft doc >>= C8.putStr . encodeLazy UTF8 putStrLn "*** dumped"