module Eventloop.System.EventloopThread where import Control.DeepSeq import Control.Exception import Control.Monad import Control.Concurrent.ExceptionUtility import Control.Concurrent.MVar import Control.Concurrent.STM import Control.Concurrent.Datastructures.BlockingConcurrentQueue import Data.Maybe import Eventloop.System.Processing import Eventloop.Types.Common import Eventloop.Types.Exception import Eventloop.Types.Events import Eventloop.Types.System startEventlooping :: EventloopSystemConfiguration progstateT -> IO () startEventlooping systemConfig = handle ( \exception -> case (fromException exception) of (Just RequestShutdownException) -> throwIO RequestShutdownException _ -> throwIO (EventloopException exception) ) ( do putInBlockingConcurrentQueue inEventQueue_ Start forever $ do inEvent <- takeFromBlockingConcurrentQueue inEventQueue_ -- Take an In event processedInEvents <- processEvents "Preprocessing" systemConfig modulePreprocessors [inEvent] -- Preprocess it outEvents <- eventloopSteps eventloop progstateT_ processedInEvents -- Eventloop over the preprocessed In events processedOutEvents <- processEvents "Postprocessing" systemConfig modulePostprocessors outEvents -- Postprocess the Out events evaluatedOutEvents <- evaluate $ force processedOutEvents putAllInBlockingConcurrentQueue outEventQueue_ processedOutEvents -- Send the processed Out events to the OutRouter ) where eventloopConfig_ = eventloopConfig systemConfig eventloop = eventloopFunc eventloopConfig_ progstateT_ = progstateT eventloopConfig_ inEventQueue_ = inEventQueue eventloopConfig_ outEventQueue_ = outEventQueue eventloopConfig_ moduleConfigurations_ = moduleConfigs systemConfig modulePreprocessors = findProcessors moduleConfigurations_ preprocessorM modulePostprocessors = findProcessors moduleConfigurations_ postprocessorM findProcessors :: [EventloopModuleConfiguration] -> (EventloopModuleConfiguration -> Maybe (SharedIOConstants -> TVar SharedIOState -> IOConstants -> TVar IOState -> event -> IO [event])) -- Pre-/Postprocessor function -> [(EventloopModuleIdentifier, IOConstants, TVar IOState, (SharedIOConstants -> TVar SharedIOState -> IOConstants -> TVar IOState -> event -> IO [event]))] findProcessors moduleConfigs getProcessorFunc = moduleProcessors where moduleProcessorsM = map (\moduleConfig -> (moduleId moduleConfig, ioConstants moduleConfig, ioStateT moduleConfig, getProcessorFunc moduleConfig)) moduleConfigs moduleProcessorsJ = filter (\(_, _, _, processFuncM) -> isJust processFuncM) moduleProcessorsM moduleProcessors = map (\(id, ioConst, iostate, (Just processFunc)) -> (id, ioConst, iostate, processFunc)) moduleProcessorsJ eventloopSteps :: (progstateT -> In -> (progstateT, [Out])) {-^ eventloop function -} -> TVar progstateT -> [In] -> IO [Out] eventloopSteps eventloop progstateT inEvents = sequencedSteps >>= (return.concat) where inEventSteps = map (eventloopStep eventloop progstateT) inEvents sequencedSteps = sequence inEventSteps eventloopStep :: (progstateT -> In -> (progstateT, [Out])) {-^ eventloop function -} -> TVar progstateT -> In -> IO [Out] eventloopStep eventloop progStateT inEvent = do progState <- readTVarIO progStateT let (progState', outEvents) = eventloop progState inEvent atomically $ writeTVar progStateT progState' return outEvents