------------------------------------------------------------------------------- -- | -- Module : Heartbeat.hs -- Copyright : (c) Tobias Schoofs -- License : LGPL -- Stability : experimental -- Portability: non-portable -- -- Heartbeat ------------------------------------------------------------------------------- module Heartbeat where import Network.Mom.Patterns.Types (Msec) import Data.Time.Clock import Control.Concurrent.MVar ------------------------------------------------------------------------- -- Tolerance for foreign heartbeat - -- Period until disconnect = tolerance * heartbeat period ------------------------------------------------------------------------- tolerance :: Int tolerance = 10 ------------------------------------------------------------------------- -- Helper to check for expiration of a period ------------------------------------------------------------------------- hbPeriodReached :: MVar UTCTime -> Msec -> IO Bool hbPeriodReached m tmo = modifyMVar m $ \t -> do now <- getCurrentTime if t `timeAdd` tmo <= now then return (now `timeAdd` tmo, True ) else return ( t, False) ------------------------------------------------------------------------ -- Heartbeat descriptor ------------------------------------------------------------------------ data Heartbeat = Heart { hbNextMe :: UTCTime, hbNextHe :: UTCTime, hbPeriod :: Msec } ------------------------------------------------------------------------ -- Create a new heartbeat descriptor ------------------------------------------------------------------------ newHeartbeat :: Msec -> IO Heartbeat newHeartbeat period = do now <- getCurrentTime return Heart { hbNextHe = timeAdd now (tolerance * period), hbNextMe = timeAdd now period, hbPeriod = period} ------------------------------------------------------------------------ -- Update heartbeat descriptor -- - my next heartbeat ------------------------------------------------------------------------ updMe :: UTCTime -> Heartbeat -> Heartbeat updMe now hb = hb {hbNextMe = now `timeAdd` (hbPeriod hb)} ------------------------------------------------------------------------ -- - his next heartbeat ------------------------------------------------------------------------ updHim :: UTCTime -> Heartbeat -> Heartbeat updHim now hb = hb {hbNextHe = timeAdd now $ tolerance * (hbPeriod hb)} ------------------------------------------------------------------------ -- Check me, him ------------------------------------------------------------------------ checkMe :: UTCTime -> Heartbeat -> Bool checkMe now hb | now <= hbNextMe hb = False | otherwise = True alive :: UTCTime -> Heartbeat -> Bool alive now hb | now <= hbNextHe hb = True | otherwise = False ----------------------------------------------------------------------- -- Adding period to time ----------------------------------------------------------------------- timeAdd :: UTCTime -> Msec -> UTCTime timeAdd t p = ms2nominal p `addUTCTime` t ----------------------------------------------------------------------- -- Convert milliseconds to seconds ----------------------------------------------------------------------- ms2nominal :: Msec -> NominalDiffTime ms2nominal m = fromIntegral m / (1000::NominalDiffTime)