{-# LANGUAGE MultiParamTypeClasses #-} {-| Module : Control.ERNet.Deployment.Local.Manager Description : manager implementation using local threads and STM Copyright : (c) Michal Konecny License : BSD3 Maintainer : mik@konecny.aow.cz Stability : experimental Portability : portable A simple implementation of "Control.ERNet.Foundations.Manager.Manager", deploying all processes locally. -} module Control.ERNet.Deployment.Local.Manager ( ManagerLocal() ) where import Control.ERNet.Deployment.Local.Logger import Control.ERNet.Deployment.Local.Channel import Control.ERNet.Foundations.Protocol import Control.ERNet.Foundations.Event import qualified Control.ERNet.Foundations.Event.Logger as LG import qualified Control.ERNet.Foundations.Channel as CH import Control.ERNet.Foundations.Process import Control.ERNet.Foundations.Manager import Control.Concurrent as Concurrent import qualified Data.Map as Map newtype ManagerLocal = ManagerLocal ManagerName instance Manager ManagerLocal LoggerLocal ChannelLocal ChannelLocal ChannelLocalAnyProt ChannelLocalAnyProt where new name = do putStrLn $ "simulating the creation of network manager " ++ name return (ManagerLocal name, "ernet-local:/" ++ name) connectNeighbour (ManagerLocal name) neighbourID = do putStrLn $ "simulating the connection of neighbour " ++ neighbourID ++ " to the manager " ++ name return True runProcess (ManagerLocal name) process = do logger <- LG.new forkIO $ (erprocDeploy process) (erprocName process) [] [] (startNet logger) return logger startNet logger locationDescr [] _ processesMappings = do deployProcesses logger locationDescr "" [] [] processesMappings return () startNet _ _ _ _ _ = error $ "Control.ERNet.Deployment.ManagerLocal: startNet: Illegal attempt to kick-start a network: outermost network cannot have input sockets" expandProcess logger processNamePrefix inCHAs outCHAs -- these 4 provided by manager locationDescr inputTypesNames outputTypesNames processesMappings = do dispatcher Nothing where (outChTs, outChNs) = unzip outputTypesNames (inChTs, inChNs) = unzip inputTypesNames dispatcher maybeN2channel = do -- wait for a query: -- putStrLn $ "ERProcessNet: " ++ defName ++ ": waiting for a query on " ++ show (length resCHAs) ++ " channels" (chN, qryData) <- CH.waitForQueryMulti outCHAs -- putStrLn $ "ERProcessNet: " ++ defName ++ ": forwarding query on channel " ++ show chN n2channel <- -- number |-> internal or input channel case maybeN2channel of Nothing -> -- the first query -> plumb the subnet deployProcesses logger locationDescr processNamePrefix inCHAs inChNs processesMappings Just n2channel -> return n2channel -- pass on the query to the subnet: let fwdCHA = fst $ n2channel $ outChNs !! chN let outCHA = outCHAs !! chN let chT = outChTs !! chN forkIO $ forwardQueryAnswer outCHA fwdCHA chT qryData dispatcher (Just n2channel) forwardQueryAnswer causeCHA fwdCHA chT (causeQryId, qryAnyProt) = do argQryId <- CH.makeQueryAnyProt locationDescr causeCHA causeQryId fwdCHA qryAnyProt -- wait for answer from inside: (_, ansAnyProt) <- CH.waitForAnswerMulti causeCHA causeQryId [(fwdCHA, argQryId)] -- forward the answer out: CH.answerQueryAnyProt locationDescr False causeCHA (causeQryId, ansAnyProt) deployProcesses :: (CH.ChannelForScheduler lg sIn sOut sInAnyProt sOutAnyProt) => lg -> String -> String -> [sInAnyProt] -> [Int] -> [(ERProcess sInAnyProt sOutAnyProt, ([Int], [Int]))] -> IO (Int -> (sInAnyProt, sOutAnyProt)) deployProcesses logger locationDescr namePrefix inCHAs inChNs processesMappings = do -- create required internal channels: internalCHAs <- mapM makeNewChannel internalTypesNamesProcesses let n2channel = makeChannelMap internalCHAs -- deploy all internal processes: mapM (deployProcess n2channel) $ processesMappings return n2channel where makeNewChannel (((chN, chT), (procName, outChN))) = CH.new logger (namePrefix ++ procName) outChN chT internalTypesNamesProcesses = concat $ map getProcessChanTypesNames processesMappings where getProcessChanTypesNames (process, (inNs, outNs)) = (zip (zip outNs (erprocOutputTypes process)) $ zip (repeat $ erprocName process) [0..]) makeChannelMap internalCHAs n = case Map.lookup n n2chMap of Nothing -> error $ locationDescr ++ " deployProcess: unknown channel number: " ++ show n Just ch -> ch where n2chMap = Map.fromList $ (zip internalChNs internalCHAs) ++ (zip inChNs $ zip inCHAs (repeat errorOUT)) errorOUT = error "ManagerLocal: makeChannelMap: input channel treated as output channel" internalChNs = concat $ map (snd . snd) processesMappings deployProcess n2channel (process, (processInChNs, processOutChNs)) = do forkIO $ (erprocDeploy process) name processInCHAs processOutCHAs (expandProcess logger (name ++ ".") processInCHAs processOutCHAs) where name = namePrefix ++ erprocName process processInCHAs = map (fst . n2channel) processInChNs processOutCHAs = map (snd . n2channel) processOutChNs