{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} module Snap.Internal.Http.Server.Date ( getDateString , getLogDateString ) where ------------------------------------------------------------------------------ import Control.Exception (mask_) import Control.Monad (when) import Data.ByteString (ByteString) import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Foreign.C.Types (CTime) import System.IO.Unsafe (unsafePerformIO) import System.PosixCompat.Time (epochTime) ------------------------------------------------------------------------------ import Snap.Internal.Http.Types (formatHttpTime, formatLogTime) ------------------------------------------------------------------------------ data DateState = DateState { _cachedDateString :: !(IORef ByteString) , _cachedLogString :: !(IORef ByteString) , _lastFetchTime :: !(IORef CTime) } ------------------------------------------------------------------------------ dateState :: DateState dateState = unsafePerformIO $ do (s1, s2, date) <- fetchTime bs1 <- newIORef $! s1 bs2 <- newIORef $! s2 dt <- newIORef $! date return $! DateState bs1 bs2 dt {-# NOINLINE dateState #-} ------------------------------------------------------------------------------ fetchTime :: IO (ByteString,ByteString,CTime) fetchTime = do !now <- epochTime !t1 <- formatHttpTime now !t2 <- formatLogTime now let !out = (t1, t2, now) return out ------------------------------------------------------------------------------ updateState :: DateState -> IO () updateState (DateState dateString logString time) = do (s1, s2, now) <- fetchTime writeIORef dateString $! s1 writeIORef logString $! s2 writeIORef time $! now return $! () ------------------------------------------------------------------------------ ensureFreshDate :: IO () ensureFreshDate = mask_ $ do now <- epochTime old <- readIORef $ _lastFetchTime dateState when (now > old) $! updateState dateState ------------------------------------------------------------------------------ getDateString :: IO ByteString getDateString = mask_ $ do ensureFreshDate readIORef $ _cachedDateString dateState ------------------------------------------------------------------------------ getLogDateString :: IO ByteString getLogDateString = mask_ $ do ensureFreshDate readIORef $ _cachedLogString dateState