mirror of
https://github.com/urbit/shrub.git
synced 2024-12-22 18:31:44 +03:00
297 lines
8.2 KiB
Haskell
297 lines
8.2 KiB
Haskell
{-|
|
|
Code for setting up the RIO environment.
|
|
-}
|
|
module Urbit.King.App
|
|
( KingEnv
|
|
, runKingEnvStderr
|
|
, runKingEnvStderrRaw
|
|
, runKingEnvLogFile
|
|
, runKingEnvNoLog
|
|
, kingEnvKillSignal
|
|
, killKingActionL
|
|
, onKillKingSigL
|
|
, HostEnv
|
|
, runHostEnv
|
|
, PierEnv
|
|
, runPierEnv
|
|
, killPierActionL
|
|
, onKillPierSigL
|
|
, HasStderrLogFunc(..)
|
|
, HasKingId(..)
|
|
, HasProcId(..)
|
|
, HasKingEnv(..)
|
|
, HasMultiEyreApi(..)
|
|
, HasHostEnv(..)
|
|
, HasPierEnv(..)
|
|
, module Urbit.King.Config
|
|
)
|
|
where
|
|
|
|
import Urbit.King.Config
|
|
import Urbit.Prelude
|
|
|
|
import RIO (logGeneric)
|
|
import System.Directory ( createDirectoryIfMissing
|
|
, getXdgDirectory
|
|
, XdgDirectory(XdgCache)
|
|
)
|
|
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(..))
|
|
|
|
|
|
-- KingEnv ---------------------------------------------------------------------
|
|
|
|
class HasKingId a where
|
|
kingIdL :: Lens' a Word16
|
|
|
|
class HasProcId a where
|
|
procIdL :: Lens' a Int32
|
|
|
|
class (HasLogFunc a, HasStderrLogFunc a, HasKingId a, HasProcId a)
|
|
=> HasKingEnv a
|
|
where
|
|
kingEnvL :: Lens' a KingEnv
|
|
|
|
data KingEnv = KingEnv
|
|
{ _kingEnvLogFunc :: !LogFunc
|
|
, _kingEnvStderrLogFunc :: !LogFunc
|
|
, _kingEnvKingId :: !Word16
|
|
, _kingEnvProcId :: !Int32
|
|
, _kingEnvKillSignal :: !(TMVar ())
|
|
}
|
|
|
|
makeLenses ''KingEnv
|
|
|
|
instance HasKingEnv KingEnv where
|
|
kingEnvL = id
|
|
|
|
instance HasLogFunc KingEnv where
|
|
logFuncL = kingEnvLogFunc
|
|
|
|
instance HasStderrLogFunc KingEnv where
|
|
stderrLogFuncL = kingEnvStderrLogFunc
|
|
|
|
instance HasProcId KingEnv where
|
|
procIdL = kingEnvProcId
|
|
|
|
instance HasKingId KingEnv where
|
|
kingIdL = kingEnvKingId
|
|
|
|
-- Running KingEnvs ------------------------------------------------------------
|
|
|
|
runKingEnvStderr :: Bool -> LogLevel -> RIO KingEnv a -> IO a
|
|
runKingEnvStderr verb lvl inner = do
|
|
logOptions <-
|
|
logOptionsHandle stderr verb
|
|
<&> setLogUseTime True
|
|
<&> setLogUseLoc False
|
|
<&> setLogMinLevel lvl
|
|
withLogFunc logOptions $ \logFunc -> runKingEnv logFunc logFunc inner
|
|
|
|
runKingEnvStderrRaw :: Bool -> LogLevel -> RIO KingEnv a -> IO a
|
|
runKingEnvStderrRaw verb lvl inner = do
|
|
logOptions <-
|
|
logOptionsHandle stderr verb
|
|
<&> setLogUseTime True
|
|
<&> setLogUseLoc False
|
|
<&> setLogMinLevel lvl
|
|
withLogFunc logOptions $ \logFunc ->
|
|
let lf = wrapCarriage logFunc
|
|
in runKingEnv lf lf inner
|
|
|
|
-- XX loses callstack
|
|
wrapCarriage :: LogFunc -> LogFunc
|
|
wrapCarriage lf = mkLogFunc $ \_ ls ll bldr ->
|
|
runRIO lf $ logGeneric ls ll (bldr <> "\r")
|
|
|
|
runKingEnvLogFile :: Bool -> LogLevel -> Maybe FilePath -> RIO KingEnv a -> IO a
|
|
runKingEnvLogFile verb lvl fileM inner = do
|
|
logFile <- case fileM of
|
|
Just f -> pure f
|
|
Nothing -> defaultLogFile
|
|
withLogFileHandle logFile $ \h -> do
|
|
logOptions <-
|
|
logOptionsHandle h verb
|
|
<&> setLogUseTime True
|
|
<&> setLogUseLoc False
|
|
<&> setLogMinLevel lvl
|
|
stderrLogOptions <-
|
|
logOptionsHandle stderr verb
|
|
<&> setLogUseTime False
|
|
<&> setLogUseLoc False
|
|
<&> setLogMinLevel lvl
|
|
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
|
|
hSetBuffering handle LineBuffering
|
|
act handle
|
|
|
|
defaultLogFile :: IO FilePath
|
|
defaultLogFile = do
|
|
logDir <- getXdgDirectory XdgCache "urbit"
|
|
createDirectoryIfMissing True logDir
|
|
logId :: Word32 <- randomIO
|
|
pure (logDir </> "king-" <> show logId <> ".log")
|
|
|
|
runKingEnvNoLog :: RIO KingEnv a -> IO a
|
|
runKingEnvNoLog act = runKingEnv mempty mempty act
|
|
|
|
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 ()))
|
|
|
|
-- HostEnv ------------------------------------------------------------------
|
|
|
|
-- 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) =>
|
|
HasHostEnv a where
|
|
hostEnvL :: Lens' a HostEnv
|
|
|
|
data HostEnv = HostEnv
|
|
{ _hostEnvKingEnv :: !KingEnv
|
|
, _hostEnvMultiEyreApi :: !MultiEyreApi
|
|
, _hostEnvPortControlApi :: !PortControlApi
|
|
}
|
|
|
|
makeLenses ''HostEnv
|
|
|
|
instance HasKingEnv HostEnv where
|
|
kingEnvL = hostEnvKingEnv
|
|
|
|
instance HasLogFunc HostEnv where
|
|
logFuncL = kingEnvL . logFuncL
|
|
|
|
instance HasStderrLogFunc HostEnv where
|
|
stderrLogFuncL = kingEnvL . stderrLogFuncL
|
|
|
|
instance HasProcId HostEnv where
|
|
procIdL = kingEnvL . procIdL
|
|
|
|
instance HasKingId HostEnv where
|
|
kingIdL = kingEnvL . kingEnvKingId
|
|
|
|
instance HasMultiEyreApi HostEnv where
|
|
multiEyreApiL = hostEnvMultiEyreApi
|
|
|
|
instance HasPortControlApi HostEnv where
|
|
portControlApiL = hostEnvPortControlApi
|
|
|
|
-- Running Running Envs --------------------------------------------------------
|
|
|
|
runHostEnv :: MultiEyreApi -> PortControlApi -> RIO HostEnv a
|
|
-> RIO KingEnv a
|
|
runHostEnv multi ports action = do
|
|
king <- ask
|
|
|
|
let hostEnv = HostEnv { _hostEnvKingEnv = king
|
|
, _hostEnvMultiEyreApi = multi
|
|
, _hostEnvPortControlApi = ports
|
|
}
|
|
|
|
io (runRIO hostEnv action)
|
|
|
|
-- PierEnv ---------------------------------------------------------------------
|
|
|
|
class (HasKingEnv a, HasHostEnv a, HasPierConfig a, HasNetworkConfig a) =>
|
|
HasPierEnv a where
|
|
pierEnvL :: Lens' a PierEnv
|
|
|
|
data PierEnv = PierEnv
|
|
{ _pierEnvHostEnv :: !HostEnv
|
|
, _pierEnvPierConfig :: !PierConfig
|
|
, _pierEnvNetworkConfig :: !NetworkConfig
|
|
, _pierEnvKillSignal :: !(TMVar ())
|
|
}
|
|
|
|
makeLenses ''PierEnv
|
|
|
|
instance HasKingEnv PierEnv where
|
|
kingEnvL = pierEnvHostEnv . kingEnvL
|
|
|
|
instance HasHostEnv PierEnv where
|
|
hostEnvL = pierEnvHostEnv
|
|
|
|
instance HasMultiEyreApi PierEnv where
|
|
multiEyreApiL = pierEnvHostEnv . multiEyreApiL
|
|
|
|
instance HasPortControlApi PierEnv where
|
|
portControlApiL = pierEnvHostEnv . portControlApiL
|
|
|
|
instance HasPierEnv PierEnv where
|
|
pierEnvL = id
|
|
|
|
instance HasKingId PierEnv where
|
|
kingIdL = kingEnvL . kingEnvKingId
|
|
|
|
instance HasStderrLogFunc PierEnv where
|
|
stderrLogFuncL = kingEnvL . stderrLogFuncL
|
|
|
|
instance HasLogFunc PierEnv where
|
|
logFuncL = kingEnvL . logFuncL
|
|
|
|
instance HasPierPath PierEnv where
|
|
pierPathL = pierEnvPierConfig . pierPathL
|
|
|
|
instance HasDryRun PierEnv where
|
|
dryRunL = pierEnvPierConfig . dryRunL
|
|
|
|
instance HasPierConfig PierEnv where
|
|
pierConfigL = pierEnvPierConfig
|
|
|
|
instance HasNetworkConfig PierEnv where
|
|
networkConfigL = pierEnvNetworkConfig
|
|
|
|
instance HasProcId PierEnv where
|
|
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 ()))
|
|
|
|
|
|
-- Running Pier Envs -----------------------------------------------------------
|
|
|
|
runPierEnv
|
|
:: PierConfig -> NetworkConfig -> TMVar () -> RIO PierEnv a -> RIO HostEnv a
|
|
runPierEnv pierConfig networkConfig vKill action = do
|
|
host <- ask
|
|
|
|
let pierEnv = PierEnv { _pierEnvHostEnv = host
|
|
, _pierEnvPierConfig = pierConfig
|
|
, _pierEnvNetworkConfig = networkConfig
|
|
, _pierEnvKillSignal = vKill
|
|
}
|
|
|
|
io (runRIO pierEnv action)
|