king: move MultiEyreApi to a new RunningEnv.

There was a TODO in runShips about how the different layers of the
RIO environment had to be changed, so that there was a layer between
KingEnv and PierEnv for things shared between individual Piers, but
which weren't used outside of any PierEnv. This addresses those
TODOs by creating RunningEnv, which for now just owns MultiEyreApi
and makes it so we don't have to pass the entire thing around
explicitly.

The IP handling stuff will go in RunningEnv in a following patch.
This commit is contained in:
Elliot Glaysher 2020-08-04 16:52:40 -04:00
parent 225d2a288b
commit d39d7246d1
4 changed files with 164 additions and 112 deletions

View File

@ -9,6 +9,8 @@ module Urbit.King.App
, kingEnvKillSignal
, killKingActionL
, onKillKingSigL
, RunningEnv
, runRunningEnv
, PierEnv
, runPierEnv
, killPierActionL
@ -17,6 +19,8 @@ module Urbit.King.App
, HasKingId(..)
, HasProcId(..)
, HasKingEnv(..)
, HasMultiEyreApi(..)
, HasRunningEnv(..)
, HasPierEnv(..)
, module Urbit.King.Config
)
@ -30,6 +34,7 @@ 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)
-- KingEnv ---------------------------------------------------------------------
@ -70,7 +75,6 @@ instance HasProcId KingEnv where
instance HasKingId KingEnv where
kingIdL = kingEnvKingId
-- Running KingEnvs ------------------------------------------------------------
runKingEnvStderr :: Bool -> RIO KingEnv a -> IO a
@ -121,14 +125,64 @@ killKingActionL :: HasKingEnv e => Getter e (STM ())
killKingActionL =
kingEnvL . kingEnvKillSignal . to (\kil -> void (tryPutTMVar kil ()))
-- RunningEnv ------------------------------------------------------------------
-- The running environment is everything in King, eyre configuration shared
-- across ships, and IP information shared across ships.
--
-- TODO: Implement that IP information for real.
class HasMultiEyreApi a where
multiEyreApiL :: Lens' a MultiEyreApi
class (HasKingEnv a, HasMultiEyreApi a) => HasRunningEnv a where
runningEnvL :: Lens' a RunningEnv
data RunningEnv = RunningEnv
{ _runningEnvKingEnv :: !KingEnv
, _runningEnvMultiEyreApi :: MultiEyreApi
}
makeLenses ''RunningEnv
instance HasKingEnv RunningEnv where
kingEnvL = runningEnvKingEnv
instance HasLogFunc RunningEnv where
logFuncL = kingEnvL . logFuncL
instance HasStderrLogFunc RunningEnv where
stderrLogFuncL = kingEnvL . stderrLogFuncL
instance HasProcId RunningEnv where
procIdL = kingEnvL . procIdL
instance HasKingId RunningEnv where
kingIdL = kingEnvL . kingEnvKingId
instance HasMultiEyreApi RunningEnv where
multiEyreApiL = runningEnvMultiEyreApi
-- Running Running Envs --------------------------------------------------------
runRunningEnv :: MultiEyreApi -> RIO RunningEnv () -> RIO KingEnv ()
runRunningEnv multi action = do
king <- ask
let runningEnv = RunningEnv { _runningEnvKingEnv = king
, _runningEnvMultiEyreApi = multi
}
io (runRIO runningEnv action)
-- PierEnv ---------------------------------------------------------------------
class (HasKingEnv a, HasPierConfig a, HasNetworkConfig a) => HasPierEnv a where
class (HasKingEnv a, HasRunningEnv a, HasPierConfig a, HasNetworkConfig a) =>
HasPierEnv a where
pierEnvL :: Lens' a PierEnv
data PierEnv = PierEnv
{ _pierEnvKingEnv :: !KingEnv
{ _pierEnvRunningEnv :: !RunningEnv
, _pierEnvPierConfig :: !PierConfig
, _pierEnvNetworkConfig :: !NetworkConfig
, _pierEnvKillSignal :: !(TMVar ())
@ -137,7 +191,13 @@ data PierEnv = PierEnv
makeLenses ''PierEnv
instance HasKingEnv PierEnv where
kingEnvL = pierEnvKingEnv
kingEnvL = pierEnvRunningEnv . kingEnvL
instance HasRunningEnv PierEnv where
runningEnvL = pierEnvRunningEnv
instance HasMultiEyreApi PierEnv where
multiEyreApiL = pierEnvRunningEnv . multiEyreApiL
instance HasPierEnv PierEnv where
pierEnvL = id
@ -180,11 +240,11 @@ killPierActionL =
-- Running Pier Envs -----------------------------------------------------------
runPierEnv
:: PierConfig -> NetworkConfig -> TMVar () -> RIO PierEnv a -> RIO KingEnv a
:: PierConfig -> NetworkConfig -> TMVar () -> RIO PierEnv a -> RIO RunningEnv a
runPierEnv pierConfig networkConfig vKill action = do
app <- ask
running <- ask
let pierEnv = PierEnv { _pierEnvKingEnv = app
let pierEnv = PierEnv { _pierEnvRunningEnv = running
, _pierEnvPierConfig = pierConfig
, _pierEnvNetworkConfig = networkConfig
, _pierEnvKillSignal = vKill

View File

@ -82,7 +82,7 @@ import Urbit.Arvo
import Urbit.King.Config
import Urbit.Vere.Dawn
import Urbit.Vere.Pier
import Urbit.Vere.Eyre.Multi (multiEyre, MultiEyreApi, MultiEyreConf(..))
import Urbit.Vere.Eyre.Multi (multiEyre, MultiEyreConf(..))
import Urbit.Vere.Pier.Types
import Urbit.Vere.Serf
import Urbit.King.App
@ -184,12 +184,11 @@ tryBootFromPill
-> Bool
-> Ship
-> LegacyBootEvent
-> MultiEyreApi
-> RIO PierEnv ()
tryBootFromPill oExit pill lite ship boot multi = do
tryBootFromPill oExit pill lite ship boot = do
mStart <- newEmptyMVar
vSlog <- logSlogs
runOrExitImmediately vSlog (bootedPier vSlog) oExit mStart multi
runOrExitImmediately vSlog (bootedPier vSlog) oExit mStart
where
bootedPier vSlog = do
view pierPathL >>= lockFile
@ -203,9 +202,8 @@ runOrExitImmediately
-> RAcquire PierEnv (Serf, Log.EventLog)
-> Bool
-> MVar ()
-> MultiEyreApi
-> RIO PierEnv ()
runOrExitImmediately vSlog getPier oExit mStart multi = do
runOrExitImmediately vSlog getPier oExit mStart = do
rwith getPier (if oExit then shutdownImmediately else runPier)
where
shutdownImmediately :: (Serf, Log.EventLog) -> RIO PierEnv ()
@ -216,19 +214,18 @@ runOrExitImmediately vSlog getPier oExit mStart multi = do
runPier :: (Serf, Log.EventLog) -> RIO PierEnv ()
runPier serfLog = do
runRAcquire (Pier.pier serfLog vSlog mStart multi)
runRAcquire (Pier.pier serfLog vSlog mStart)
tryPlayShip
:: Bool
-> Bool
-> Maybe Word64
-> MVar ()
-> MultiEyreApi
-> RIO PierEnv ()
tryPlayShip exitImmediately fullReplay playFrom mStart multi = do
tryPlayShip exitImmediately fullReplay playFrom mStart = do
when fullReplay wipeSnapshot
vSlog <- logSlogs
runOrExitImmediately vSlog (resumeShip vSlog) exitImmediately mStart multi
runOrExitImmediately vSlog (resumeShip vSlog) exitImmediately mStart
where
wipeSnapshot = do
shipPath <- view pierPathL
@ -444,7 +441,7 @@ validateNounVal inpVal = do
--------------------------------------------------------------------------------
pillFrom :: CLI.PillSource -> RIO KingEnv Pill
pillFrom :: CLI.PillSource -> RIO RunningEnv Pill
pillFrom = \case
CLI.PillSourceFile pillPath -> do
logDebug $ display $ "boot: reading pill from " ++ (pack pillPath :: Text)
@ -475,41 +472,44 @@ newShip CLI.New{..} opts = do
-}
multi <- multiEyre (MultiEyreConf Nothing Nothing True)
case nBootType of
CLI.BootComet -> do
pill <- pillFrom nPillSource
putStrLn "boot: retrieving list of stars currently accepting comets"
starList <- dawnCometList
putStrLn ("boot: " ++ (tshow $ length starList) ++
" star(s) currently accepting comets")
putStrLn "boot: mining a comet"
eny <- io $ Sys.randomIO
let seed = mineComet (Set.fromList starList) eny
putStrLn ("boot: found comet " ++ renderShip (sShip seed))
bootFromSeed multi pill seed
CLI.BootFake name -> do
pill <- pillFrom nPillSource
ship <- shipFrom name
runTryBootFromPill multi pill name ship (Fake ship)
CLI.BootFromKeyfile keyFile -> do
text <- readFileUtf8 keyFile
asAtom <- case cordToUW (Cord $ T.strip text) of
Nothing -> error "Couldn't parse keyfile. Hint: keyfiles start with 0w?"
Just (UW a) -> pure a
asNoun <- cueExn asAtom
seed :: Seed <- case fromNoun asNoun of
Nothing -> error "Keyfile does not seem to contain a seed."
Just s -> pure s
pill <- pillFrom nPillSource
bootFromSeed multi pill seed
-- here we are with a king env, and we now need a multi env.
runRunningEnv multi go
where
shipFrom :: Text -> RIO KingEnv Ship
go :: RIO RunningEnv ()
go = case nBootType of
CLI.BootComet -> do
pill <- pillFrom nPillSource
putStrLn "boot: retrieving list of stars currently accepting comets"
starList <- dawnCometList
putStrLn ("boot: " ++ (tshow $ length starList) ++
" star(s) currently accepting comets")
putStrLn "boot: mining a comet"
eny <- io $ Sys.randomIO
let seed = mineComet (Set.fromList starList) eny
putStrLn ("boot: found comet " ++ renderShip (sShip seed))
bootFromSeed pill seed
CLI.BootFake name -> do
pill <- pillFrom nPillSource
ship <- shipFrom name
runTryBootFromPill pill name ship (Fake ship)
CLI.BootFromKeyfile keyFile -> do
text <- readFileUtf8 keyFile
asAtom <- case cordToUW (Cord $ T.strip text) of
Nothing -> error "Couldn't parse keyfile. Hint: keyfiles start with 0w?"
Just (UW a) -> pure a
asNoun <- cueExn asAtom
seed :: Seed <- case fromNoun asNoun of
Nothing -> error "Keyfile does not seem to contain a seed."
Just s -> pure s
pill <- pillFrom nPillSource
bootFromSeed pill seed
shipFrom :: Text -> RIO RunningEnv Ship
shipFrom name = case Ob.parsePatp name of
Left x -> error "Invalid ship name"
Right p -> pure $ Ship $ fromIntegral $ Ob.fromPatp p
@ -519,7 +519,7 @@ newShip CLI.New{..} opts = do
Just x -> x
Nothing -> "./" <> unpack name
nameFromShip :: Ship -> RIO KingEnv Text
nameFromShip :: Ship -> RIO RunningEnv Text
nameFromShip s = name
where
nameWithSig = Ob.renderPatp $ Ob.patp $ fromIntegral s
@ -527,8 +527,8 @@ newShip CLI.New{..} opts = do
Nothing -> error "Urbit.ob didn't produce string with ~"
Just x -> pure x
bootFromSeed :: MultiEyreApi -> Pill -> Seed -> RIO KingEnv ()
bootFromSeed multi pill seed = do
bootFromSeed :: Pill -> Seed -> RIO RunningEnv ()
bootFromSeed pill seed = do
ethReturn <- dawnVent seed
case ethReturn of
@ -536,19 +536,22 @@ newShip CLI.New{..} opts = do
Right dawn -> do
let ship = sShip $ dSeed dawn
name <- nameFromShip ship
runTryBootFromPill multi pill name ship (Dawn dawn)
runTryBootFromPill pill name ship (Dawn dawn)
-- Now that we have all the information for running an application with a
-- PierConfig, do so.
runTryBootFromPill multi pill name ship bootEvent = do
vKill <- view kingEnvKillSignal
runTryBootFromPill :: Pill -> Text -> Ship -> LegacyBootEvent
-> RIO RunningEnv ()
runTryBootFromPill pill name ship bootEvent = do
env <- ask
let vKill = (env ^. kingEnvL) ^. kingEnvKillSignal
let pierConfig = toPierConfig (pierPath name) opts
let networkConfig = toNetworkConfig opts
runPierEnv pierConfig networkConfig vKill $
tryBootFromPill True pill nLite ship bootEvent multi
tryBootFromPill True pill nLite ship bootEvent
------ tryBootFromPill (CLI.oExit opts) pill nLite flags ship bootEvent
runShipEnv :: CLI.Run -> CLI.Opts -> TMVar () -> RIO PierEnv a -> RIO KingEnv a
runShipEnv :: CLI.Run -> CLI.Opts -> TMVar () -> RIO PierEnv a -> RIO RunningEnv a
runShipEnv (CLI.Run pierPath) opts vKill act = do
runPierEnv pierConfig netConfig vKill act
where
@ -556,8 +559,8 @@ runShipEnv (CLI.Run pierPath) opts vKill act = do
netConfig = toNetworkConfig opts
runShip
:: CLI.Run -> CLI.Opts -> Bool -> MultiEyreApi -> RIO PierEnv ()
runShip (CLI.Run pierPath) opts daemon multi = do
:: CLI.Run -> CLI.Opts -> Bool -> RIO PierEnv ()
runShip (CLI.Run pierPath) opts daemon = do
mStart <- newEmptyMVar
if daemon
then runPier mStart
@ -580,7 +583,6 @@ runShip (CLI.Run pierPath) opts daemon multi = do
(CLI.oFullReplay opts)
(CLI.oDryFrom opts)
mStart
multi
startBrowser :: HasLogFunc e => FilePath -> RIO e ()
@ -674,15 +676,15 @@ main = do
TODO Use logging system instead of printing.
-}
runShipRestarting
:: CLI.Run -> CLI.Opts -> MultiEyreApi -> RIO KingEnv ()
runShipRestarting r o multi = do
:: CLI.Run -> CLI.Opts -> RIO RunningEnv ()
runShipRestarting r o = do
let pier = pack (CLI.rPierPath r)
loop = runShipRestarting r o multi
loop = runShipRestarting r o
onKill <- view onKillKingSigL
vKillPier <- newEmptyTMVarIO
tid <- asyncBound $ runShipEnv r o vKillPier $ runShip r o True multi
tid <- asyncBound $ runShipEnv r o vKillPier $ runShip r o True
let onShipExit = Left <$> waitCatchSTM tid
onKillRequ = Right <$> onKill
@ -707,10 +709,12 @@ runShipRestarting r o multi = do
TODO This is messy and shared a lot of logic with `runShipRestarting`.
-}
runShipNoRestart
:: CLI.Run -> CLI.Opts -> Bool -> MultiEyreApi -> RIO KingEnv ()
runShipNoRestart r o d multi = do
vKill <- view kingEnvKillSignal -- killing ship same as killing king
tid <- asyncBound (runShipEnv r o vKill $ runShip r o d multi)
:: CLI.Run -> CLI.Opts -> Bool -> RIO RunningEnv ()
runShipNoRestart r o d = do
-- killing ship same as killing king
env <- ask
let vKill = (env ^. kingEnvL) ^. kingEnvKillSignal
tid <- asyncBound (runShipEnv r o vKill $ runShip r o d)
onKill <- view onKillKingSigL
let pier = pack (CLI.rPierPath r)
@ -740,31 +744,21 @@ runShips CLI.KingOpts {..} ships = do
-- a king-wide option.
}
{-
TODO Need to rework RIO environment to fix this. Should have a
bunch of nested contexts:
- King has started. King has Id. Logging available.
- In running environment. MultiEyre and global config available.
- In pier environment: pier path and config available.
- In running ship environment: serf state, event queue available.
-}
multi <- multiEyre meConf
go multi ships
runRunningEnv multi (go ships)
where
go :: MultiEyreApi -> [(CLI.Run, CLI.Opts, Bool)] -> RIO KingEnv ()
go me = \case
go :: [(CLI.Run, CLI.Opts, Bool)] -> RIO RunningEnv ()
go = \case
[] -> pure ()
[rod] -> runSingleShip rod me
ships -> runMultipleShips (ships <&> \(r, o, _) -> (r, o)) me
[rod] -> runSingleShip rod
ships -> runMultipleShips (ships <&> \(r, o, _) -> (r, o))
-- TODO Duplicated logic.
runSingleShip :: (CLI.Run, CLI.Opts, Bool) -> MultiEyreApi -> RIO KingEnv ()
runSingleShip (r, o, d) multi = do
shipThread <- async (runShipNoRestart r o d multi)
runSingleShip :: (CLI.Run, CLI.Opts, Bool) -> RIO RunningEnv ()
runSingleShip (r, o, d) = do
shipThread <- async (runShipNoRestart r o d)
{-
Wait for the ship to go down.
@ -784,10 +778,10 @@ runSingleShip (r, o, d) multi = do
pure ()
runMultipleShips :: [(CLI.Run, CLI.Opts)] -> MultiEyreApi -> RIO KingEnv ()
runMultipleShips ships multi = do
runMultipleShips :: [(CLI.Run, CLI.Opts)] -> RIO RunningEnv ()
runMultipleShips ships = do
shipThreads <- for ships $ \(r, o) -> do
async (runShipRestarting r o multi)
async (runShipRestarting r o)
{-
Since `spin` never returns, this will run until the main

View File

@ -11,7 +11,7 @@ where
import Urbit.Prelude hiding (Builder)
import Urbit.Arvo hiding (ServerId, reqUrl, secure)
import Urbit.King.App (HasKingId(..), HasPierEnv(..))
import Urbit.King.App (HasKingId(..), HasMultiEyreApi(..), HasPierEnv(..))
import Urbit.King.Config
import Urbit.Vere.Eyre.Multi
import Urbit.Vere.Eyre.PortsFile
@ -170,16 +170,18 @@ execRespActs (Drv v) who reqId ev = readMVar v >>= \case
atomically (routeRespAct who (sLiveReqs sv) reqId act)
startServ
:: (HasPierConfig e, HasLogFunc e, HasNetworkConfig e)
=> MultiEyreApi
-> Ship
:: (HasPierConfig e, HasLogFunc e, HasMultiEyreApi e, HasNetworkConfig e)
=> Ship
-> Bool
-> HttpServerConf
-> (EvErr -> STM ())
-> RIO e Serv
startServ multi who isFake conf plan = do
startServ who isFake conf plan = do
logDebug (displayShow ("EYRE", "startServ"))
env <- ask
let multi = env ^. multiEyreApiL
let vLive = meaLive multi
srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32)
@ -281,16 +283,15 @@ _bornFailed env _ = runRIO env $ do
pure () -- TODO What should this do?
eyre'
:: HasPierEnv e
=> MultiEyreApi
-> Ship
:: (HasPierEnv e, HasMultiEyreApi e)
=> Ship
-> Bool
-> RIO e ([Ev], RAcquire e (DriverApi HttpServerEf))
eyre' multi who isFake = do
eyre' who isFake = do
ventQ :: TQueue EvErr <- newTQueueIO
env <- ask
let (bornEvs, startDriver) = eyre env multi who (writeTQueue ventQ) isFake
let (bornEvs, startDriver) = eyre env who (writeTQueue ventQ) isFake
let runDriver = do
diOnEffect <- startDriver
@ -315,14 +316,14 @@ eyre
:: forall e
. (HasPierEnv e)
=> e
-> MultiEyreApi
-> Ship
-> (EvErr -> STM ())
-> Bool
-> ([Ev], RAcquire e (HttpServerEf -> IO ()))
eyre env multi who plan isFake = (initialEvents, runHttpServer)
eyre env who plan isFake = (initialEvents, runHttpServer)
where
king = fromIntegral (env ^. kingIdL)
multi = env ^. multiEyreApiL
initialEvents :: [Ev]
initialEvents = [bornEv king]
@ -343,7 +344,7 @@ eyre env multi who plan isFake = (initialEvents, runHttpServer)
restart :: Drv -> HttpServerConf -> RIO e Serv
restart (Drv var) conf = do
logDebug "Restarting http server"
let startAct = startServ multi who isFake conf plan
let startAct = startServ who isFake conf plan
res <- fromEither =<< restartService var startAct kill
logDebug "Done restating http server"
pure res

View File

@ -30,7 +30,6 @@ import Urbit.EventLog.LMDB (EventLog)
import Urbit.King.API (TermConn)
import Urbit.Noun.Time (Wen)
import Urbit.TermSize (TermSize(..))
import Urbit.Vere.Eyre.Multi (MultiEyreApi)
import Urbit.Vere.Serf (Serf)
import qualified Data.Text as T
@ -260,9 +259,8 @@ pier
:: (Serf, EventLog)
-> TVar (Text -> IO ())
-> MVar ()
-> MultiEyreApi
-> RAcquire PierEnv ()
pier (serf, log) vSlog startedSig multi = do
pier (serf, log) vSlog startedSig = do
let logId = Log.identity log :: LogIdentity
let ship = who logId :: Ship
@ -311,7 +309,7 @@ pier (serf, log) vSlog startedSig multi = do
let err = atomically . Term.trace muxed . (<> "\r\n")
let siz = TermSize { tsWide = 80, tsTall = 24 }
let fak = isFake logId
drivers env multi ship fak compute (siz, muxed) err sigint
drivers env ship fak compute (siz, muxed) err sigint
scrySig <- newEmptyTMVarIO
onKill <- view onKillPierSigL
@ -412,7 +410,6 @@ data Drivers = Drivers
drivers
:: HasPierEnv e
=> e
-> MultiEyreApi
-> Ship
-> Bool
-> (RunReq -> STM ())
@ -420,11 +417,11 @@ drivers
-> (Text -> RIO e ())
-> IO ()
-> RAcquire e ([Ev], RAcquire e Drivers)
drivers env multi who isFake plan termSys stderr serfSIGINT = do
drivers env who isFake plan termSys stderr serfSIGINT = do
(behnBorn, runBehn) <- rio Behn.behn'
(termBorn, runTerm) <- rio (Term.term' termSys serfSIGINT)
(amesBorn, runAmes) <- rio (Ames.ames' who isFake stderr)
(httpBorn, runEyre) <- rio (Eyre.eyre' multi who isFake)
(httpBorn, runEyre) <- rio (Eyre.eyre' who isFake)
(clayBorn, runClay) <- rio Clay.clay'
(irisBorn, runIris) <- rio Iris.client'