module Eventloop.System.OutRouterThread where import Control.Exception import Control.Monad import Control.Concurrent import Control.Concurrent.Datastructures.BlockingConcurrentQueue import Eventloop.OutRouter import Eventloop.Types.Common import Eventloop.Types.Events import Eventloop.Types.Exception import Eventloop.Types.System {- | Grab an outEvent from the outEventQueue and route it to the correct module sender if any. If there isn't one, throw a NoOutRouteException. The router will continue until it: - Comes across a Stop outEvent: Raises a RequestShutdownException - Raises an exception - Receives an exception (Only possibility is ShutdownException) In all cases, a Stop outEvent is sent to all module senders. -} startOutRouting :: EventloopSystemConfiguration progstateT -> IO () startOutRouting systemConfig = catch (forever $ do outEvent <- takeFromBlockingConcurrentQueue outEventQueue_ case outEvent of Stop -> throwIO RequestShutdownException _ -> outRouteOne moduleIdsSenderQueues outEvent ) (\exception -> do outRouteBroadcastStop moduleIdsSenderQueues throwIO (exception :: SomeException) ) where moduleIdsSenderQueues = outRoutes (moduleConfigs systemConfig) outEventQueue_ = outEventQueue (eventloopConfig systemConfig) outRoutes :: [EventloopModuleConfiguration] -> [(EventloopModuleIdentifier, SenderEventQueue)] outRoutes [] = [] outRoutes (moduleConfig:mcs) = case (senderConfigM moduleConfig) of Nothing -> outRoutes mcs (Just moduleSenderConfig) -> (moduleId moduleConfig, senderEventQueue moduleSenderConfig):(outRoutes mcs) outRouteOne :: [(EventloopModuleIdentifier, SenderEventQueue)] -> Out -> IO () outRouteOne targetIdsSenderQueues outEvent = case targetSenderQueueM of Nothing -> throwIO (NoOutRouteException outEvent) (Just targetSenderQueue) -> putInBlockingConcurrentQueue targetSenderQueue outEvent where targetModuleIdentifier = routeOutEvent outEvent targetSenderQueueM = lookup targetModuleIdentifier targetIdsSenderQueues outRouteBroadcastStop :: [(EventloopModuleIdentifier, SenderEventQueue)] -> IO () outRouteBroadcastStop [] = return () outRouteBroadcastStop targetIdsSenderQueues = mapM_ broadcastAction (map snd targetIdsSenderQueues) where broadcastAction targetSenderQueue = putInBlockingConcurrentQueue targetSenderQueue Stop