{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction, FlexibleContexts, MultiParamTypeClasses, ScopedTypeVariables, DeriveDataTypeable, DeriveGeneric #-} module EZCouch.Time where import Prelude () import ClassyPrelude.Conduit import System.Locale import Data.Time import qualified Network.HTTP.Types as HTTP import Control.Monad.Reader import EZCouch.Types import EZCouch.Action -- | Current time according to server. This function doesn't actually emit any -- requests to the server, calculating the value from a deviation of local time -- from server time determined at the beginning of the EZCouch session. readTime :: MonadAction m => m UTCTime readTime = do (_, _, deviation) <- ask localTime <- liftIO $ getCurrentTime return $ addUTCTime deviation localTime getHeadersTime ((name, value) : tail) | name == HTTP.hDate = case toTime value of Just time -> return time Nothing -> throwIO $ ParsingException $ "Couldn't parse date: `" ++ decodeUtf8 value ++ "`" | otherwise = getHeadersTime tail getHeadersTime _ = throwIO $ ResponseException "No date header in response" toTime = parseTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S %Z" . unpack . asText . decodeUtf8 getTimeDeviation :: MonadAction m => m NominalDiffTime getTimeDeviation = do dbTime <- getResponseHeaders HTTP.methodGet mempty mempty mempty >>= getHeadersTime localTime <- liftIO $ getCurrentTime return $ diffUTCTime dbTime localTime withTimeDeviation :: (MonadAction m) => NominalDiffTime -> m a -> m a withTimeDeviation timeDeviation = local (\(settings, manager, _) -> (settings, manager, timeDeviation))