urbit/pkg/hs/urbit-king/lib/Urbit/King/App.hs

279 lines
7.6 KiB
Haskell
Raw Normal View History

2020-01-23 07:16:09 +03:00
{-|
Code for setting up the RIO environment.
-}
module Urbit.King.App
2020-05-13 22:35:57 +03:00
( KingEnv
, runKingEnvStderr
, runKingEnvLogFile
, runKingEnvNoLog
, kingEnvKillSignal
, killKingActionL
, onKillKingSigL
2020-08-13 17:19:35 +03:00
, HostEnv
, runHostEnv
2020-05-13 22:35:57 +03:00
, PierEnv
, runPierEnv
, killPierActionL
, onKillPierSigL
2020-05-13 22:35:57 +03:00
, HasStderrLogFunc(..)
, HasKingId(..)
, HasProcId(..)
2020-05-22 21:12:28 +03:00
, HasKingEnv(..)
, HasMultiEyreApi(..)
2020-08-13 17:19:35 +03:00
, HasHostEnv(..)
2020-05-22 21:12:28 +03:00
, HasPierEnv(..)
, module Urbit.King.Config
2020-05-13 22:35:57 +03:00
)
where
import Urbit.King.Config
import Urbit.Prelude
2020-08-15 05:25:07 +03:00
import System.Directory ( createDirectoryIfMissing
, getXdgDirectory
, XdgDirectory(XdgCache)
2020-08-15 05:25:07 +03:00
)
2020-05-13 22:35:57 +03:00
import System.Posix.Internals (c_getpid)
import System.Posix.Types (CPid(..))
import System.Random (randomIO)
import Urbit.King.App.Class (HasStderrLogFunc(..))
import Urbit.Vere.Eyre.Multi (MultiEyreApi)
import Urbit.Vere.Ports (PortControlApi, HasPortControlApi(..))
2020-05-22 21:12:28 +03:00
2020-08-15 05:25:07 +03:00
2020-05-22 21:12:28 +03:00
-- KingEnv ---------------------------------------------------------------------
2020-05-13 22:35:57 +03:00
class HasKingId a where
kingIdL :: Lens' a Word16
2020-05-22 21:12:28 +03:00
class HasProcId a where
procIdL :: Lens' a Int32
2020-05-13 22:35:57 +03:00
2020-05-22 21:12:28 +03:00
class (HasLogFunc a, HasStderrLogFunc a, HasKingId a, HasProcId a)
=> HasKingEnv a
where
kingEnvL :: Lens' a KingEnv
2020-05-13 22:35:57 +03:00
data KingEnv = KingEnv
{ _kingEnvLogFunc :: !LogFunc
, _kingEnvStderrLogFunc :: !LogFunc
, _kingEnvKingId :: !Word16
, _kingEnvProcId :: !Int32
, _kingEnvKillSignal :: !(TMVar ())
2020-05-13 22:35:57 +03:00
}
makeLenses ''KingEnv
2020-02-04 04:27:16 +03:00
2020-05-22 21:12:28 +03:00
instance HasKingEnv KingEnv where
kingEnvL = id
2020-05-13 22:35:57 +03:00
instance HasLogFunc KingEnv where
logFuncL = kingEnvLogFunc
2020-02-04 04:27:16 +03:00
2020-05-13 22:35:57 +03:00
instance HasStderrLogFunc KingEnv where
stderrLogFuncL = kingEnvStderrLogFunc
2020-05-13 22:35:57 +03:00
instance HasProcId KingEnv where
procIdL = kingEnvProcId
2020-05-13 22:35:57 +03:00
instance HasKingId KingEnv where
kingIdL = kingEnvKingId
2020-05-13 22:35:57 +03:00
-- Running KingEnvs ------------------------------------------------------------
runKingEnvStderr :: Bool -> LogLevel -> RIO KingEnv a -> IO a
runKingEnvStderr verb lvl inner = do
2020-05-13 22:35:57 +03:00
logOptions <-
logOptionsHandle stderr verb
<&> setLogUseTime True
<&> setLogUseLoc False
<&> setLogMinLevel lvl
2020-05-13 22:35:57 +03:00
withLogFunc logOptions $ \logFunc -> runKingEnv logFunc logFunc inner
2020-02-04 04:27:16 +03:00
runKingEnvLogFile :: Bool -> LogLevel -> Maybe FilePath -> RIO KingEnv a -> IO a
runKingEnvLogFile verb lvl fileM inner = do
2020-08-15 05:25:07 +03:00
logFile <- case fileM of
Just f -> pure f
Nothing -> defaultLogFile
withLogFileHandle logFile $ \h -> do
logOptions <-
logOptionsHandle h verb
<&> setLogUseTime True
<&> setLogUseLoc False
<&> setLogMinLevel lvl
2020-08-15 05:25:07 +03:00
stderrLogOptions <-
logOptionsHandle stderr verb
<&> setLogUseTime False
<&> setLogUseLoc False
<&> setLogMinLevel lvl
2020-08-15 05:25:07 +03:00
withLogFunc stderrLogOptions $ \stderrLogFunc -> withLogFunc logOptions
$ \logFunc -> runKingEnv logFunc stderrLogFunc inner
withLogFileHandle :: FilePath -> (Handle -> IO a) -> IO a
withLogFileHandle f act =
withFile f AppendMode $ \handle -> do
2020-05-13 22:35:57 +03:00
hSetBuffering handle LineBuffering
act handle
2020-08-15 05:25:07 +03:00
defaultLogFile :: IO FilePath
defaultLogFile = do
logDir <- getXdgDirectory XdgCache "urbit"
2020-08-15 05:25:07 +03:00
createDirectoryIfMissing True logDir
2020-12-05 01:19:03 +03:00
logId :: Word32 <- randomIO
pure (logDir </> "king-" <> show logId <> ".log")
2020-08-15 05:25:07 +03:00
2020-05-13 22:35:57 +03:00
runKingEnvNoLog :: RIO KingEnv a -> IO a
2020-08-15 05:25:07 +03:00
runKingEnvNoLog act = runKingEnv mempty mempty act
2020-05-13 22:35:57 +03:00
runKingEnv :: LogFunc -> LogFunc -> RIO KingEnv a -> IO a
runKingEnv logFunc stderr action = do
kid <- randomIO
CPid pid <- c_getpid
kil <- newEmptyTMVarIO
runRIO (KingEnv logFunc stderr kid pid kil) action
-- KingEnv Utils ---------------------------------------------------------------
onKillKingSigL :: HasKingEnv e => Getter e (STM ())
onKillKingSigL = kingEnvL . kingEnvKillSignal . to readTMVar
killKingActionL :: HasKingEnv e => Getter e (STM ())
killKingActionL =
kingEnvL . kingEnvKillSignal . to (\kil -> void (tryPutTMVar kil ()))
2020-05-13 22:35:57 +03:00
2020-08-13 17:19:35 +03:00
-- HostEnv ------------------------------------------------------------------
2020-08-14 17:23:39 +03:00
-- The host environment is everything in King, eyre configuration shared
-- across ships, and nat punching data.
class HasMultiEyreApi a where
multiEyreApiL :: Lens' a MultiEyreApi
class (HasKingEnv a, HasMultiEyreApi a, HasPortControlApi a) =>
2020-08-13 17:19:35 +03:00
HasHostEnv a where
hostEnvL :: Lens' a HostEnv
2020-08-13 17:19:35 +03:00
data HostEnv = HostEnv
{ _hostEnvKingEnv :: !KingEnv
, _hostEnvMultiEyreApi :: !MultiEyreApi
, _hostEnvPortControlApi :: !PortControlApi
}
2020-08-13 17:19:35 +03:00
makeLenses ''HostEnv
2020-08-13 17:19:35 +03:00
instance HasKingEnv HostEnv where
kingEnvL = hostEnvKingEnv
2020-08-13 17:19:35 +03:00
instance HasLogFunc HostEnv where
logFuncL = kingEnvL . logFuncL
2020-08-13 17:19:35 +03:00
instance HasStderrLogFunc HostEnv where
stderrLogFuncL = kingEnvL . stderrLogFuncL
2020-08-13 17:19:35 +03:00
instance HasProcId HostEnv where
procIdL = kingEnvL . procIdL
2020-08-13 17:19:35 +03:00
instance HasKingId HostEnv where
kingIdL = kingEnvL . kingEnvKingId
2020-08-13 17:19:35 +03:00
instance HasMultiEyreApi HostEnv where
multiEyreApiL = hostEnvMultiEyreApi
2020-08-13 17:19:35 +03:00
instance HasPortControlApi HostEnv where
portControlApiL = hostEnvPortControlApi
-- Running Running Envs --------------------------------------------------------
runHostEnv :: MultiEyreApi -> PortControlApi -> RIO HostEnv a
-> RIO KingEnv a
2020-08-13 17:19:35 +03:00
runHostEnv multi ports action = do
king <- ask
2020-08-13 17:19:35 +03:00
let hostEnv = HostEnv { _hostEnvKingEnv = king
2020-09-27 01:55:10 +03:00
, _hostEnvMultiEyreApi = multi
, _hostEnvPortControlApi = ports
}
2020-08-13 17:19:35 +03:00
io (runRIO hostEnv action)
2020-05-13 22:35:57 +03:00
-- PierEnv ---------------------------------------------------------------------
2020-08-13 17:19:35 +03:00
class (HasKingEnv a, HasHostEnv a, HasPierConfig a, HasNetworkConfig a) =>
HasPierEnv a where
2020-05-22 21:12:28 +03:00
pierEnvL :: Lens' a PierEnv
2020-05-13 22:35:57 +03:00
data PierEnv = PierEnv
2020-08-14 17:23:39 +03:00
{ _pierEnvHostEnv :: !HostEnv
2020-05-13 22:35:57 +03:00
, _pierEnvPierConfig :: !PierConfig
, _pierEnvNetworkConfig :: !NetworkConfig
, _pierEnvKillSignal :: !(TMVar ())
2020-05-13 22:35:57 +03:00
}
makeLenses ''PierEnv
2020-05-22 21:12:28 +03:00
instance HasKingEnv PierEnv where
2020-08-13 17:19:35 +03:00
kingEnvL = pierEnvHostEnv . kingEnvL
2020-08-13 17:19:35 +03:00
instance HasHostEnv PierEnv where
hostEnvL = pierEnvHostEnv
instance HasMultiEyreApi PierEnv where
2020-08-13 17:19:35 +03:00
multiEyreApiL = pierEnvHostEnv . multiEyreApiL
2020-05-22 21:12:28 +03:00
instance HasPortControlApi PierEnv where
2020-08-13 17:19:35 +03:00
portControlApiL = pierEnvHostEnv . portControlApiL
2020-05-22 21:12:28 +03:00
instance HasPierEnv PierEnv where
pierEnvL = id
instance HasKingId PierEnv where
kingIdL = kingEnvL . kingEnvKingId
2020-05-13 22:35:57 +03:00
instance HasStderrLogFunc PierEnv where
2020-05-22 21:12:28 +03:00
stderrLogFuncL = kingEnvL . stderrLogFuncL
2020-05-13 22:35:57 +03:00
instance HasLogFunc PierEnv where
2020-05-22 21:12:28 +03:00
logFuncL = kingEnvL . logFuncL
instance HasPierPath PierEnv where
pierPathL = pierEnvPierConfig . pierPathL
instance HasDryRun PierEnv where
dryRunL = pierEnvPierConfig . dryRunL
2020-05-13 22:35:57 +03:00
instance HasPierConfig PierEnv where
pierConfigL = pierEnvPierConfig
2020-05-13 22:35:57 +03:00
instance HasNetworkConfig PierEnv where
networkConfigL = pierEnvNetworkConfig
2020-05-13 22:35:57 +03:00
instance HasProcId PierEnv where
2020-05-22 21:12:28 +03:00
procIdL = kingEnvL . kingEnvProcId
-- PierEnv Utils ---------------------------------------------------------------
onKillPierSigL :: HasPierEnv e => Getter e (STM ())
onKillPierSigL = pierEnvL . pierEnvKillSignal . to readTMVar
killPierActionL :: HasPierEnv e => Getter e (STM ())
killPierActionL =
pierEnvL . pierEnvKillSignal . to (\kil -> void (tryPutTMVar kil ()))
2020-05-13 22:35:57 +03:00
-- Running Pier Envs -----------------------------------------------------------
runPierEnv
2020-08-13 17:19:35 +03:00
:: PierConfig -> NetworkConfig -> TMVar () -> RIO PierEnv a -> RIO HostEnv a
runPierEnv pierConfig networkConfig vKill action = do
2020-08-14 17:23:39 +03:00
host <- ask
2020-08-14 17:23:39 +03:00
let pierEnv = PierEnv { _pierEnvHostEnv = host
2020-05-13 22:35:57 +03:00
, _pierEnvPierConfig = pierConfig
, _pierEnvNetworkConfig = networkConfig
, _pierEnvKillSignal = vKill
}
2020-05-13 22:35:57 +03:00
io (runRIO pierEnv action)