snaplet-wordpress-0.1.1.0: src/Snap/Snaplet/Wordpress/Cache.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
module Snap.Snaplet.Wordpress.Cache where
import Control.Concurrent.MVar
import Data.Monoid ((<>))
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Time.Clock (getCurrentTime, diffUTCTime, UTCTime)
import Database.Redis (Redis)
import Snap
import Snap.Snaplet.Wordpress.Cache.Redis
import Snap.Snaplet.Wordpress.Cache.Types
import Snap.Snaplet.Wordpress.Types
import Snap.Snaplet.Wordpress.Utils
startReqMutexInt :: MVar (Map WPKey UTCTime) -> WPKey -> IO Bool
startReqMutexInt activeMV wpKey =
do now <- getCurrentTime
modifyMVar activeMV $ \a ->
let active = filterCurrent now a
in if Map.member wpKey active
then return (active, True)
else return (Map.insert wpKey now active, False)
where filterCurrent now = Map.filter (\v -> diffUTCTime now v < 1)
stopReqMutexInt :: MVar (Map WPKey UTCTime) -> WPKey -> IO ()
stopReqMutexInt activeMV wpKey =
modifyMVar_ activeMV $ return . Map.delete wpKey
cachingGetRetryInt :: (WordpressInt b) -> WPKey -> IO Text
cachingGetRetryInt wp = retryUnless . (cachingGetInt wp)
cachingGetErrorInt :: (WordpressInt b) -> WPKey -> IO Text
cachingGetErrorInt wp wpKey = errorUnless msg (cachingGetInt wp wpKey)
where msg = ("Could not retrieve " <> tshow wpKey)
cachingGetInt :: WordpressInt b
-> WPKey
-> IO (Maybe Text)
cachingGetInt WordpressInt{..} wpKey =
do cached <- wpCacheGet wpKey
case cached of
Just _ -> return cached
Nothing ->
do running <- startReqMutex wpKey
if running
then return Nothing
else
do o <- wpRequest wpKey
wpCacheSet wpKey o
stopReqMutex wpKey
return $ Just o
wpCacheGetInt :: RunRedis -> CacheBehavior -> WPKey -> IO (Maybe Text)
wpCacheGetInt runRedis b = runRedis . (cacheGet b) . formatKey
cacheGet :: CacheBehavior -> Text -> Redis (Maybe Text)
cacheGet NoCache _ = return Nothing
cacheGet _ key = rget key
wpCacheSetInt :: RunRedis -> CacheBehavior -> WPKey -> Text -> IO ()
wpCacheSetInt runRedis b key = void . runRedis . (cacheSet b (formatKey key))
cacheSet :: CacheBehavior -> Text -> Text -> Redis Bool
cacheSet b k v =
case b of
(CacheSeconds n) -> rsetex k n v
CacheForever -> rset k v
NoCache -> return True
wpExpireAggregatesInt :: RunRedis -> IO Bool
wpExpireAggregatesInt runRedis = runRedis expireAggregates
expireAggregates :: Redis Bool
expireAggregates = rdelstar "wordpress:posts:*"
wpExpirePostInt :: RunRedis -> WPKey -> IO Bool
wpExpirePostInt runRedis = runRedis . expire
expire :: WPKey -> Redis Bool
expire key = rdel [formatKey key] >> expireAggregates
formatKey :: WPKey -> Text
formatKey = format
where format (PostByPermalinkKey y m s) = ns "post_perma:" <> y <> "_" <> m <> "_" <> s
format (PostsKey filters) =
ns "posts:" <> T.intercalate "_" (map tshow $ Set.toAscList filters)
format (PostKey n) = ns "post:" <> tshow n
format (AuthorKey n) = ns "author:" <> tshow n
format (TaxDictKey t) = ns "tax_dict:" <> t
ns k = "wordpress:" <> k