yesod-session-persist-0.0.0.2: internal/Yesod/Session/Memcache/Expiration.hs
module Yesod.Session.Memcache.Expiration
( MemcacheExpiration (..)
, noExpiration
, fromUTC
, maxTimestamp
, minTimestamp
) where
import Internal.Prelude
import Data.Fixed (Pico)
import Database.Memcache.Types qualified as Memcache
import Time (UTCTime, nominalDiffTimeToSeconds, utcTimeToPOSIXSeconds)
newtype Exceptions = InvalidExpiration Pico
deriving stock (Eq, Show)
deriving anyclass (Exception)
data MemcacheExpiration
= -- | Do not set expiration times; memache will only evict when the cache is full
NoMemcacheExpiration
| -- | Sessions will be stored in memcache with the same expiration time that we
-- send to the HTTP client, the lesser of the idle and absolute timeouts.
UseMemcacheExpiration
-- | Do not expire the session via Memcache's expiration mechanism.
--
-- Memcache will evict the session when the cache is full.
noExpiration :: Memcache.Expiration
noExpiration = 0
-- | Convert 'UTCTime' to 'Word32', with possibility of failure.
--
-- This function guards against UTCTime values that, converted to a timestamp,
-- would be too big or too small.
--
-- See 'maxTimestamp' and 'minTimestamp' for definitions of too 'big / small'.
fromUTC :: MonadThrow m => UTCTime -> m Word32
fromUTC utcTime = do
when (tooLarge || tooSmall) $ throwWithCallStack $ InvalidExpiration seconds
pure $ ceiling seconds
where
seconds = nominalDiffTimeToSeconds $ utcTimeToPOSIXSeconds utcTime
tooLarge = seconds > maxTimestamp
tooSmall = seconds < minTimestamp
-- | Minimum value that will be interpreted as a timestamp by Memcache
--
-- Values lower than this are considered to be "number of seconds" in the future
-- to expire a key / value pair. This is /not/ the interpretation we want.
--
-- See: https://github.com/dterei/memcache-hs/blob/83957ee9c4983f87447b0e7476a9a9155474dc80/Database/Memcache/Client.hs#L49-L59
--
-- This value is ~1960.
minTimestamp :: Num a => a
minTimestamp = 2592000 + 1 -- Values lower than this
-- | Check to make sure we don't overflow.
--
-- 4_294_967_295 is ~2096
maxTimestamp :: Num a => a
maxTimestamp = fromIntegral $ maxBound @Word32