module Hakyll.Core.Resource.Provider
( ResourceProvider (..)
, makeResourceProvider
, resourceExists
, resourceDigest
, resourceModified
) where
import Control.Applicative ((<$>))
import Control.Concurrent (MVar, readMVar, modifyMVar_, newMVar)
import Control.Monad ((<=<))
import Data.Word (Word8)
import Data.Map (Map)
import qualified Data.Map as M
import qualified Data.ByteString.Lazy as LB
import OpenSSL.Digest.ByteString.Lazy (digest)
import OpenSSL.Digest (MessageDigest (MD5))
import Hakyll.Core.Store
import Hakyll.Core.Resource
data ResourceProvider = ResourceProvider
{
resourceList :: [Resource]
,
resourceString :: Resource -> IO String
,
resourceLBS :: Resource -> IO LB.ByteString
,
resourceModifiedCache :: MVar (Map Resource Bool)
}
makeResourceProvider :: [Resource]
-> (Resource -> IO String)
-> (Resource -> IO LB.ByteString)
-> IO ResourceProvider
makeResourceProvider l s b = ResourceProvider l s b <$> newMVar M.empty
resourceExists :: ResourceProvider -> Resource -> Bool
resourceExists provider = flip elem $ resourceList provider
resourceDigest :: ResourceProvider -> Resource -> IO [Word8]
resourceDigest provider = digest MD5 <=< resourceLBS provider
resourceModified :: ResourceProvider -> Store -> Resource -> IO Bool
resourceModified provider store resource = do
cache <- readMVar mvar
case M.lookup resource cache of
Just m -> return m
Nothing -> do
m <- if resourceExists provider resource
then digestModified provider store resource
else return False
modifyMVar_ mvar (return . M.insert resource m)
return m
where
mvar = resourceModifiedCache provider
digestModified :: ResourceProvider -> Store -> Resource -> IO Bool
digestModified provider store resource = do
lastDigest <- storeGet store itemName identifier
newDigest <- resourceDigest provider resource
if Found newDigest == lastDigest
then return False
else do storeSet store itemName identifier newDigest
return True
where
identifier = toIdentifier resource
itemName = "Hakyll.Core.ResourceProvider.digestModified"