packages feed

eventloop-0.5.0.0: src/Eventloop/System/EventloopThread.hs

module Eventloop.System.EventloopThread where

import Control.Exception
import Control.Monad
import Control.Concurrent.ExceptionUtility
import Control.Concurrent.MVar
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
    = do
        putInBlockingConcurrentQueue inEventQueue_ Start
        forever $ do
          inEvent <- takeFromBlockingConcurrentQueue inEventQueue_ -- Take an In event
          processedInEvents <- processEvents "Preprocessing" systemConfig modulePreprocessors [inEvent] -- Preprocess it
          outEvents <- eventloopSteps eventloop progstateM_ processedInEvents  -- Eventloop over the preprocessed In events
          processedOutEvents <- processEvents "Postprocessing" systemConfig modulePostprocessors outEvents -- Postprocess the Out events
          putAllInBlockingConcurrentQueue outEventQueue_ processedOutEvents -- Send the processed Out events to the OutRouter
    where
        eventloopConfig_ = eventloopConfig systemConfig
        eventloop = eventloopFunc eventloopConfig_
        progstateM_ = progstateM eventloopConfig_
        inEventQueue_ = inEventQueue eventloopConfig_
        outEventQueue_ = outEventQueue eventloopConfig_
        moduleConfigurations_ = moduleConfigs systemConfig
        modulePreprocessors = findProcessors moduleConfigurations_ preprocessorM
        modulePostprocessors = findProcessors moduleConfigurations_ postprocessorM

        
findProcessors :: [EventloopModuleConfiguration]
               -> (EventloopModuleConfiguration -> Maybe (SharedIOState -> IOState -> event -> IO (SharedIOState, IOState, [event]))) -- Pre-/Postprocessor function
               -> [(EventloopModuleIdentifier, MVar IOState, (SharedIOState -> IOState -> event -> IO (SharedIOState, IOState, [event])))]
findProcessors moduleConfigs getProcessorFunc
    = moduleProcessors
    where
        moduleProcessorsM = map (\moduleConfig -> (moduleId moduleConfig, iostateM moduleConfig, getProcessorFunc moduleConfig)) moduleConfigs
        moduleProcessorsJ = filter (\(_, _, processFuncM) -> isJust processFuncM) moduleProcessorsM
        moduleProcessors = map (\(id, iostate, (Just processFunc)) -> (id, iostate, processFunc)) moduleProcessorsJ

        
eventloopSteps :: (progstateT -> In -> (progstateT, [Out])) {-| eventloop function -}
               -> MVar progstateT
               -> [In]
               -> IO [Out]
eventloopSteps eventloop progstateM inEvents
    =  sequencedSteps >>= (return.concat)
    where
        inEventSteps = map (eventloopStep eventloop progstateM) inEvents
        sequencedSteps = sequence inEventSteps
    
        
eventloopStep :: (progstateT -> In -> (progstateT, [Out])) {-| eventloop function -}
              -> MVar progstateT
              -> In
              -> IO [Out]
eventloopStep eventloop progstateM inEvent
    = catch
        ( uninterruptibleUpdateResourceAndCalculate
            ( takeMVar progstateM
            )
            ( \progstate' ->
                putMVar progstateM progstate'
            )
            ( \progstate ->
                return (eventloop progstate inEvent)
            )
        )
        ( \exception ->
            throwIO (EventloopException exception)
        )
      >>= return.snd