keter/Keter/AppManager.hs

128 lines
4.6 KiB
Haskell
Raw Normal View History

2013-07-25 20:58:54 +04:00
{-# LANGUAGE RecordWildCards #-}
2013-07-25 18:35:16 +04:00
-- | Used for management of applications.
module Keter.AppManager
( -- * Types
AppManager
, AppId (..)
, Action (..)
, AppInput (..)
-- * Actions
, perform
, getAllApps
-- * Initialize
, initialize
) where
import Control.Applicative
2013-07-25 20:58:54 +04:00
import Control.Concurrent (forkIO)
2013-07-25 18:35:16 +04:00
import Control.Concurrent.STM
2013-07-25 20:58:54 +04:00
import qualified Control.Exception as E
import Control.Monad (void)
2013-07-25 18:35:16 +04:00
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (mapMaybe)
import Data.Set (Set)
import qualified Data.Set as Set
import Keter.Types
data AppManager = AppManager
{ apps :: TVar (Map AppId (TVar AppState))
}
data AppId = AIBuiltin | AINamed Appname
deriving (Eq, Ord)
data AppState = ASRunning RunningApp
2013-07-25 20:58:54 +04:00
| ASStarting !(Maybe RunningApp) (TVar (Maybe Action)) -- ^ the next one to try
2013-07-25 18:35:16 +04:00
data RunningApp = RunningApp
data AppInput = AIBundle | AIData !BundleConfig
data Action = Reload AppInput | Terminate
initialize :: IO AppManager
initialize = AppManager
<$> newTVarIO Map.empty
getAllApps :: AppManager -> IO (Set Appname)
getAllApps AppManager {..} = atomically $ do
m <- readTVar apps
return $ Set.fromList $ mapMaybe toAppName $ Map.keys m
where
toAppName AIBuiltin = Nothing
toAppName (AINamed x) = Just x
perform :: AppManager -> AppId -> Action -> IO ()
2013-07-25 20:58:54 +04:00
perform am@AppManager {..} aid action = E.mask_ $ do
launchWorker' <- atomically $ do
2013-07-25 18:35:16 +04:00
m <- readTVar apps
2013-07-25 20:58:54 +04:00
case Map.lookup aid m of
2013-07-25 18:35:16 +04:00
Just tstate -> do
state <- readTVar tstate
case state of
ASStarting mcurrent tmnext -> do
2013-07-25 20:58:54 +04:00
writeTVar tmnext $ Just action
2013-07-25 18:35:16 +04:00
-- use the previous worker, so nothing to do
2013-07-25 20:58:54 +04:00
return noWorker
2013-07-25 18:35:16 +04:00
ASRunning runningApp -> do
tmnext <- newTVar Nothing
writeTVar tstate $ ASStarting (Just runningApp) tmnext
2013-07-25 20:58:54 +04:00
return $ launchWorker am tstate action
2013-07-25 18:35:16 +04:00
Nothing -> do
case action of
Reload _ -> do
tmnext <- newTVar Nothing
tstate <- newTVar $ ASStarting Nothing tmnext
writeTVar apps $ Map.insert aid tstate m
2013-07-25 20:58:54 +04:00
return $ launchWorker am tstate action
Terminate -> return noWorker
2013-07-25 18:35:16 +04:00
launchWorker'
where
2013-07-25 20:58:54 +04:00
noWorker = return ()
launchWorker :: AppManager
-> TVar AppState
-> Action
-> IO ()
launchWorker AppManager {..} tstate action = void $ forkIO $ do
return () -- FIXME
2013-07-25 18:35:16 +04:00
{- FIXME
rest <-
case Map.lookup appname appMap of
Just (app, _time) -> do
App.reload app
etime <- liftIO $ modificationTime <$> getFileStatus (F.encodeString bundle)
let time = either (P.const 0) id etime
return (Map.insert appname (app, time) appMap, return ())
Nothing -> do
mlogger <- do
let dirout = kconfigDir </> "log" </> fromText ("app-" ++ appname)
direrr = dirout </> "err"
erlog <- liftIO $ LogFile.openRotatingLog
(F.encodeString dirout)
LogFile.defaultMaxTotal
case erlog of
Left e -> do
$logEx e
return Nothing
Right rlog -> return (Just rlog)
let logger = fromMaybe LogFile.dummy mlogger
(app, rest) <- App.start
tf
muid
processTracker
hostman
plugins
logger
appname
bundle
(removeApp appname)
etime <- liftIO $ modificationTime <$> getFileStatus (F.encodeString bundle)
let time = either (P.const 0) id etime
let appMap' = Map.insert appname (app, time) appMap
return (appMap', rest)
rest
-}