module Eventloop.Module.Timer.Timer
( setupTimerModuleConfiguration
, timerModuleIdentifier
, timerInitializer
, timerEventRetriever
, timerEventSender
, timerTeardown
) where
import Control.Concurrent.Datastructures.BlockingConcurrentQueue
import Control.Concurrent.STM
import Control.Concurrent.Timer
import Control.Concurrent.Suspend.Lifted
import Data.Maybe
import Data.List
import Eventloop.Module.Timer.Types
import Eventloop.Types.Common
import Eventloop.Types.Events
import Eventloop.Types.System
setupTimerModuleConfiguration :: EventloopSetupModuleConfiguration
setupTimerModuleConfiguration = ( EventloopSetupModuleConfiguration
timerModuleIdentifier
(Just timerInitializer)
(Just timerEventRetriever)
Nothing
Nothing
(Just timerEventSender)
(Just timerTeardown)
)
timerModuleIdentifier :: EventloopModuleIdentifier
timerModuleIdentifier = "timer"
timerInitializer :: Initializer
timerInitializer sharedConst sharedIO
= do
inQueue <- createBlockingConcurrentQueue
return (sharedConst, sharedIO, TimerConstants inQueue, TimerState [] [])
timerEventRetriever :: EventRetriever
timerEventRetriever sharedConst sharedIOT ioConst ioStateT
= do
inTicks <- takeAllFromBlockingConcurrentQueue inQueue
ioState <- readTVarIO ioStateT
let
toStop = map (\(Tick id) -> id) inTicks
startedTimers_ = startedTimers ioState
sequence $ map (haltTimer startedTimers_) toStop
atomically $ do
ioState' <- readTVar ioStateT
let
startedTimers_' = startedTimers ioState'
startedTimers_'' = foldl unregisterTimer startedTimers_' toStop
writeTVar ioStateT (ioState'{startedTimers = startedTimers_'})
return (map InTimer inTicks)
where
inQueue = tickInQueue ioConst
timerEventSender :: EventSender
timerEventSender _ _ _ _ Stop = return ()
timerEventSender sharedConst sharedIOT ioConst ioStateT (OutTimer a)
= timerEventSender' ioStateT tickBuffer a
where
tickBuffer = tickInQueue ioConst
timerEventSender' :: TVar IOState -> TickBuffer -> TimerOut -> IO ()
timerEventSender' ioStateT tickBuffer (SetTimer id delay)
= do
startedTimer <- startTimer tickBuffer id delay (oneShotStart)
atomically $ do
ioState <- readTVar ioStateT
let
startedTimers_' = registerTimer (startedTimers ioState) startedTimer
writeTVar ioStateT ioState{startedTimers=startedTimers_'}
timerEventSender' ioStateT tickBuffer (SetIntervalTimer id delay)
= do
startedTimer <- startTimer tickBuffer id delay (repeatedStart)
atomically $ do
ioState <- readTVar ioStateT
let
startedITimers_' = registerTimer (startedIntervalTimers ioState) startedTimer
writeTVar ioStateT ioState{startedIntervalTimers=startedITimers_'}
timerEventSender' ioStateT tickBuffer (UnsetTimer id)
= do
ioState <- readTVarIO ioStateT
let
startedTimers_ = startedTimers ioState
startedITimers_ = startedIntervalTimers ioState
haltTimer startedTimers_ id
haltTimer startedITimers_ id
atomically $ do
ioState' <- readTVar ioStateT
let
startedTimers_' = startedTimers ioState'
startedITimers_' = startedIntervalTimers ioState'
writeTVar ioStateT ioState'{ startedTimers = startedTimers_'
, startedIntervalTimers = startedITimers_'
}
timerTeardown :: Teardown
timerTeardown sharedConst sharedIO ioConst ioState
= do
let
allStartedTimers = (startedTimers ioState) ++ (startedIntervalTimers ioState)
allStartedIds = map fst allStartedTimers
sequence_ $ map (haltTimer allStartedTimers) allStartedIds
return sharedIO
registerTimer :: [StartedTimer] -> StartedTimer -> [StartedTimer]
registerTimer startedTimers startedTimer
= startedTimers ++ [startedTimer]
startTimer :: TickBuffer -> TimerId -> MicroSecondDelay -> TimerStartFunction -> IO StartedTimer
startTimer incTickBuff id delay startFunc
= do
timer <- newTimer
startFunc timer (tick id incTickBuff) ((usDelay.fromIntegral) delay)
return (id, timer)
unregisterTimer :: [StartedTimer] -> TimerId -> [StartedTimer]
unregisterTimer startedTimers id
= filter (\(id', _) -> id /= id') startedTimers
haltTimer :: [StartedTimer] -> TimerId -> IO ()
haltTimer startedTimers id
= do
let
startedTimerM = findStartedTimer startedTimers id
stopAction (Just (_, timer)) = stopTimer timer
stopAction Nothing = return ()
stopAction startedTimerM
findStartedTimer :: [StartedTimer] -> TimerId -> Maybe StartedTimer
findStartedTimer startedTimers id = find (\(id', timer) -> id == id') startedTimers
tick :: TimerId -> TickBuffer -> IO ()
tick id tickBuffer = putInBlockingConcurrentQueue tickBuffer (Tick id)