]> gitweb @ CieloNegro.org - Rakka.git/blobdiff - Rakka/Storage/Impl.hs
merge branch origin/master
[Rakka.git] / Rakka / Storage / Impl.hs
index 1908b48165f380c1fd29b56e8772e9945ad2c7d7..55bda719f5f30190bfff48d2711ef4b63afd0593 100644 (file)
@@ -1,20 +1,37 @@
+{-# LANGUAGE
+    OverloadedStrings
+  , UnicodeSyntax
+  #-}
 module Rakka.Storage.Impl
     ( getPage'
     , putPage'
     , deletePage'
     , getDirContents'
     , startIndexManager
+
+    , getAttachment'
+    , putAttachment'
     )
     where
-
+import Control.Applicative
 import           Control.Concurrent
 import           Control.Concurrent.STM
+import           Control.Exception
 import           Control.Monad
 import           Data.Maybe
+import Data.Monoid.Unicode
 import           Data.Set (Set)
 import qualified Data.Set as S
+import Data.Text (Text)
+import qualified Data.Text as T
+import           Data.Time
+import qualified Data.Time.W3C as W3C
 import           Network.HTTP.Lucu
+import           Network.HTTP.Lucu.Utils
 import           Network.URI
+import           Prelude hiding (words)
+import Prelude.Unicode
+import           Rakka.Attachment
 import           Rakka.Page
 import           Rakka.Storage.DefaultPage
 import           Rakka.Storage.Repos
@@ -25,6 +42,7 @@ import           Subversion.Repository
 import           System.Directory
 import           System.FilePath
 import           System.IO
+import           System.IO.Unsafe
 import           System.Log.Logger
 import           Text.HyperEstraier hiding (WriteLock)
 
@@ -59,9 +77,7 @@ findAllPages repos rev = do reposPages   <- findAllPagesInRevision repos rev
 findChangedPages :: Repository -> RevNum -> RevNum -> IO (Set PageName)
 findChangedPages repos 0      newRev = findAllPages repos newRev
 findChangedPages repos oldRev newRev
-    = mapM (findChangedPagesAtRevision repos) [oldRev + 1 .. newRev]
-      >>=
-      return . S.unions
+    = liftM S.unions (mapM (findChangedPagesAtRevision repos) [oldRev + 1 .. newRev])
 
 
 getDirContents' :: Repository -> PageName -> Maybe RevNum -> IO [PageName]
@@ -76,11 +92,31 @@ getCurrentRevNum repos
     = getRepositoryFS repos >>= getYoungestRev
 
 
+getAttachment' :: Attachment a =>
+                  Repository
+               -> PageName
+               -> String
+               -> Maybe RevNum
+               -> IO (Maybe a)
+getAttachment' = loadAttachmentInRepository
+
+
+putAttachment' :: Attachment a =>
+                  Repository
+               -> Maybe String
+               -> Maybe RevNum
+               -> PageName
+               -> String
+               -> a
+               -> IO StatusCode
+putAttachment' = putAttachmentIntoRepository
+
+
 startIndexManager :: FilePath -> Repository -> (Page -> IO Document) -> IO (TChan IndexReq)
 startIndexManager lsdir repos mkDraft
     = do chan  <- newTChanIO
          index <- openIndex indexDir revFile
-         forkIO (loop chan index)
+         _     <- forkIO (loop chan index `finally` closeDatabase index)
          return chan
     where
       indexDir = lsdir </> "index"
@@ -131,8 +167,12 @@ openIndex indexDir revFile
                               $ removeFile revFile
 
                      Right index <- openDatabase indexDir (Writer [Create []])
+                     addAttrIndex index "@mdate"         SeqIndex
+                     addAttrIndex index "@type"          StrIndex
                      addAttrIndex index "@uri"           SeqIndex
                      addAttrIndex index "rakka:revision" SeqIndex
+                     addAttrIndex index "rakka:isTheme"  StrIndex
+                     addAttrIndex index "rakka:isFeed"   StrIndex
                      noticeM logger ("Created an H.E. index on " ++ indexDir)
 
                      return index
@@ -156,17 +196,50 @@ syncIndex' index revFile repos mkDraft
                mapM_ (updateIndex index repos mkDraft newRev) (S.toList pages)
 
 
-searchIndex :: Database -> Condition -> IO [(PageName, RevNum)]
+searchIndex ∷ Database → Condition → IO SearchResult
 searchIndex index cond
-    = searchDatabase index cond >>= mapM fromId
+    = do (ids, hint) ← searchDatabase' index cond
+         let (total, words) = parseHint hint
+         pages ← mapM (fromId words) ids
+         return SearchResult {
+                      srTotal = total
+                    , srPages = pages
+                    }
     where
-      fromId :: DocumentID -> IO (PageName, RevNum)
-      fromId docId
-          = do uri <- getDocURI index docId
-               rev <- getDocAttr index docId "rakka:revision"
-                      >>= return . read . fromJust
-               return (decodePageName $ uriPath uri, rev)
-
+      parseHint ∷ [(Text, Int)] → (Int, [Text])
+      parseHint xs
+          = let total = fromJust $ lookup "" xs
+                words = filter ((¬) ∘ T.null) $ map fst xs
+            in
+              (total, words)
+
+      fromId ∷ [Text] → DocumentID → IO HitPage
+      fromId words docId
+          = do uri     ← getDocURI index docId
+               rev     ← unsafeInterleaveIO $
+                         -- FIXME: use Data.Text.Read
+                         read ∘ T.unpack ∘ fromJust
+                         <$> getDocAttr index docId "rakka:revision"
+               lastMod ← unsafeInterleaveIO $
+                         zonedTimeToUTC ∘ fromJust ∘ W3C.parse ∘ T.unpack ∘ fromJust
+                         <$> getDocAttr index docId "@mdate"
+               summary ← unsafeInterleaveIO $
+                         getDocAttr index docId "rakka:summary"
+               snippet ← unsafeInterleaveIO $
+                         do doc ← getDocument index docId [NoAttributes, NoKeywords]
+                            sn  ← makeSnippet doc words 300 80 80
+                            pure (trim (≡ Boundary) $ map toFragment sn)
+               pure HitPage {
+                      hpPageName = decodePageName $ uriPath uri
+                    , hpPageRev  = rev
+                    , hpLastMod  = lastMod
+                    , hpSummary  = summary
+                    , hpSnippet  = snippet
+                    }
+      toFragment ∷ Either Text (Text, Text) -> SnippetFragment
+      toFragment (Left  ""    ) = Boundary
+      toFragment (Left  t     ) = NormalText      t
+      toFragment (Right (w, _)) = HighlightedWord w
 
 updateIndex :: Database
             -> Repository
@@ -183,11 +256,11 @@ updateIndex index repos mkDraft rev name
                      case docIdM of
                        Nothing    -> return ()
                        Just docId -> do removeDocument index docId [CleaningRemove]
-                                        infoM logger ("Removed page " ++ name ++ " from the index")
+                                        infoM logger ("Removed page " ⊕ T.unpack name ⊕ " from the index")
            Just page
                -> do draft <- mkDraft page
                      putDocument index draft [CleaningPut]
-                     infoM logger ("Indexed page " ++ name ++ " of revision " ++ show (pageRevision page))
+                     infoM logger ("Indexed page " ⊕ T.unpack name ⊕ " of revision " ⊕ show (pageRevision page))
 
 
 updateIndexRev :: FilePath -> (RevNum -> IO RevNum) -> IO ()
@@ -198,7 +271,7 @@ updateIndexRev revFile f = withFile revFile ReadWriteMode update
                     rev  <- if eof then
                                 return 0
                             else
-                                hGetLine h >>= return . read
+                                liftM read (hGetLine h)
                     rev' <- f rev
                     hSeek h AbsoluteSeek 0
                     hSetFileSize h 0