2020-05-27 02:01:03 +03:00
|
|
|
{-# OPTIONS_GHC -Wwarn #-}
|
|
|
|
|
2020-01-23 07:16:09 +03:00
|
|
|
{-|
|
|
|
|
Top-Level Pier Management
|
|
|
|
|
|
|
|
This is the code that starts the IO drivers and deals with
|
|
|
|
communication between the serf, the log, and the IO drivers.
|
|
|
|
-}
|
2020-01-24 08:28:38 +03:00
|
|
|
module Urbit.Vere.Pier
|
2020-05-27 02:01:03 +03:00
|
|
|
( booted
|
|
|
|
, runSerf
|
|
|
|
, resumed
|
|
|
|
, getSnapshot
|
|
|
|
, pier
|
|
|
|
, runPersist
|
|
|
|
, runCompute
|
|
|
|
, generateBootSeq
|
|
|
|
)
|
|
|
|
where
|
2019-05-30 23:19:26 +03:00
|
|
|
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Prelude
|
2019-07-24 04:34:16 +03:00
|
|
|
|
2019-09-17 21:19:53 +03:00
|
|
|
import RIO.Directory
|
2019-08-01 08:48:08 +03:00
|
|
|
import System.Random
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Arvo
|
|
|
|
import Urbit.King.Config
|
|
|
|
import Urbit.Vere.Pier.Types
|
2020-01-25 03:20:13 +03:00
|
|
|
import Control.Monad.Trans.Maybe
|
2020-01-24 08:28:38 +03:00
|
|
|
|
|
|
|
import Data.Text (append)
|
|
|
|
import System.Posix.Files (ownerModes, setFileMode)
|
2020-02-04 04:27:16 +03:00
|
|
|
import Urbit.King.App (HasConfigDir(..), HasStderrLogFunc(..))
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Vere.Ames (ames)
|
|
|
|
import Urbit.Vere.Behn (behn)
|
|
|
|
import Urbit.Vere.Clay (clay)
|
|
|
|
import Urbit.Vere.Http.Client (client)
|
|
|
|
import Urbit.Vere.Http.Server (serv)
|
|
|
|
import Urbit.Vere.Log (EventLog)
|
2020-05-27 02:01:03 +03:00
|
|
|
import Urbit.Vere.Serf (Serf, SerfState(..))
|
|
|
|
import Data.Conduit
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2020-02-15 11:21:55 +03:00
|
|
|
import qualified System.Entropy as Ent
|
|
|
|
import qualified Urbit.King.API as King
|
|
|
|
import qualified Urbit.Time as Time
|
|
|
|
import qualified Urbit.Vere.Log as Log
|
|
|
|
import qualified Urbit.Vere.Serf as Serf
|
|
|
|
import qualified Urbit.Vere.Term as Term
|
|
|
|
import qualified Urbit.Vere.Term.API as Term
|
|
|
|
import qualified Urbit.Vere.Term.Demux as Term
|
|
|
|
import qualified Urbit.Vere.Term.Render as Term
|
2020-05-27 02:01:03 +03:00
|
|
|
import qualified Data.Conduit.Combinators as CC
|
2019-05-30 23:19:26 +03:00
|
|
|
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
--------------------------------------------------------------------------------
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
setupPierDirectory :: FilePath -> RIO e ()
|
2019-08-15 05:42:48 +03:00
|
|
|
setupPierDirectory shipPath = do
|
2019-07-21 04:29:39 +03:00
|
|
|
for_ ["put", "get", "log", "chk"] $ \seg -> do
|
2019-08-28 14:45:49 +03:00
|
|
|
let pax = shipPath <> "/.urb/" <> seg
|
2019-09-17 21:19:53 +03:00
|
|
|
createDirectoryIfMissing True pax
|
2019-08-28 14:45:49 +03:00
|
|
|
io $ setFileMode pax ownerModes
|
2019-07-21 04:29:39 +03:00
|
|
|
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-07-21 22:56:18 +03:00
|
|
|
-- Load pill into boot sequence. -----------------------------------------------
|
2019-07-16 03:01:45 +03:00
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
genEntropy :: RIO e Word512
|
2020-01-23 12:22:30 +03:00
|
|
|
genEntropy = fromIntegral . bytesAtom <$> io (Ent.getEntropy 64)
|
2019-07-16 03:01:45 +03:00
|
|
|
|
2019-10-03 21:31:15 +03:00
|
|
|
generateBootSeq :: Ship -> Pill -> Bool -> LegacyBootEvent -> RIO e BootSeq
|
|
|
|
generateBootSeq ship Pill{..} lite boot = do
|
2019-07-16 03:01:45 +03:00
|
|
|
ent <- genEntropy
|
2019-10-16 23:38:46 +03:00
|
|
|
let ovums = preKern ent <> pKernelOvums <> postKern <> pUserspaceOvums
|
2019-07-16 03:01:45 +03:00
|
|
|
pure $ BootSeq ident pBootFormulas ovums
|
|
|
|
where
|
2019-10-02 00:44:14 +03:00
|
|
|
ident = LogIdentity ship isFake (fromIntegral $ length pBootFormulas)
|
2019-08-30 04:29:22 +03:00
|
|
|
preKern ent = [ EvBlip $ BlipEvArvo $ ArvoEvWhom () ship
|
2019-08-14 03:52:59 +03:00
|
|
|
, EvBlip $ BlipEvArvo $ ArvoEvWack () ent
|
2019-07-16 03:01:45 +03:00
|
|
|
]
|
2019-10-16 23:38:46 +03:00
|
|
|
postKern = [ EvBlip $ BlipEvTerm $ TermEvBoot (1,()) lite boot ]
|
2019-10-02 00:44:14 +03:00
|
|
|
isFake = case boot of
|
|
|
|
Fake _ -> True
|
|
|
|
_ -> False
|
2019-07-16 03:01:45 +03:00
|
|
|
|
|
|
|
|
2019-07-21 22:56:18 +03:00
|
|
|
-- Write a batch of jobs into the event log ------------------------------------
|
2019-07-19 03:52:53 +03:00
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
writeJobs :: EventLog -> Vector Job -> RIO e ()
|
2019-07-19 03:52:53 +03:00
|
|
|
writeJobs log !jobs = do
|
|
|
|
expect <- Log.nextEv log
|
|
|
|
events <- fmap fromList $ traverse fromJob (zip [expect..] $ toList jobs)
|
|
|
|
Log.appendEvents log events
|
2019-07-17 08:32:36 +03:00
|
|
|
where
|
2019-08-28 14:45:49 +03:00
|
|
|
fromJob :: (EventId, Job) -> RIO e ByteString
|
2019-07-21 04:29:39 +03:00
|
|
|
fromJob (expectedId, job) = do
|
2019-08-28 14:45:49 +03:00
|
|
|
unless (expectedId == jobId job) $
|
|
|
|
error $ show ("bad job id!", expectedId, jobId job)
|
2019-07-21 22:56:18 +03:00
|
|
|
pure $ jamBS $ jobPayload job
|
2019-07-21 04:29:39 +03:00
|
|
|
|
|
|
|
jobPayload :: Job -> Noun
|
|
|
|
jobPayload (RunNok (LifeCyc _ m n)) = toNoun (m, n)
|
|
|
|
jobPayload (DoWork (Work _ m d o)) = toNoun (m, d, o)
|
2019-07-19 03:52:53 +03:00
|
|
|
|
2019-06-29 04:46:33 +03:00
|
|
|
|
2019-07-21 22:56:18 +03:00
|
|
|
-- Boot a new ship. ------------------------------------------------------------
|
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
runSerf :: HasLogFunc e => FilePath -> [Serf.Flag] -> RAcquire e Serf
|
|
|
|
runSerf pax fax = fst <$> Serf.withSerf config
|
|
|
|
where
|
|
|
|
config = Serf.Config
|
|
|
|
{ scSerf = "urbit-worker"
|
|
|
|
, scPier = pax
|
|
|
|
, scFlag = fax
|
|
|
|
, scSlog = \slog -> print ("slog", slog) -- TODO error "TODO: slog"
|
|
|
|
, scStdr = \stdr -> print ("stdr", stdr) -- TODO error "TODO: stdr"
|
|
|
|
, scDead = pure () -- error "TODO: dead"
|
|
|
|
}
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
bootSeqJobs :: Time.Wen -> BootSeq -> [Job]
|
|
|
|
bootSeqJobs now (BootSeq ident nocks ovums) = zipWith ($) bootSeqFns [1 ..]
|
|
|
|
where
|
|
|
|
wen :: EventId -> Time.Wen
|
|
|
|
wen off = Time.addGap now ((fromIntegral off - 1) ^. from Time.microSecs)
|
|
|
|
|
|
|
|
bootSeqFns :: [EventId -> Job]
|
|
|
|
bootSeqFns = fmap muckNock nocks <> fmap muckOvum ovums
|
|
|
|
where
|
|
|
|
muckNock nok eId = RunNok $ LifeCyc eId 0 nok
|
|
|
|
muckOvum ov eId = DoWork $ Work eId 0 (wen eId) ov
|
|
|
|
|
|
|
|
{-
|
|
|
|
loop :: [Job] -> SerfState -> Maybe (ProgressBar ()) -> [BootSeqFn]
|
|
|
|
-> RIO e ([Job], SerfState)
|
|
|
|
loop acc ss pb = \case
|
|
|
|
[] -> do
|
|
|
|
pb <- logStderr (updateProgressBar 0 bootMsg pb)
|
|
|
|
pure (reverse acc, ss)
|
|
|
|
x:xs -> do
|
|
|
|
wen <- io Time.now
|
|
|
|
job <- pure $ x (ssNextEv ss) (ssLastMug ss) wen
|
|
|
|
pb <- logStderr (updateProgressBar (1 + length xs) bootMsg pb)
|
|
|
|
(job, ss) <- bootJob serf job
|
|
|
|
loop (job:acc) ss pb xs
|
|
|
|
-}
|
|
|
|
|
|
|
|
bootNewShip
|
|
|
|
:: (HasPierConfig e, HasStderrLogFunc e, HasLogFunc e)
|
|
|
|
=> Pill
|
|
|
|
-> Bool
|
|
|
|
-> [Serf.Flag]
|
|
|
|
-> Ship
|
|
|
|
-> LegacyBootEvent
|
|
|
|
-> RIO e ()
|
|
|
|
bootNewShip pill lite flags ship bootEv = do
|
|
|
|
seq@(BootSeq ident x y) <- generateBootSeq ship pill lite bootEv
|
|
|
|
logTrace "BootSeq Computed"
|
2019-08-15 05:42:48 +03:00
|
|
|
|
2019-12-17 17:31:50 +03:00
|
|
|
pierPath <- view pierPathL
|
2019-10-18 01:32:06 +03:00
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
liftRIO (setupPierDirectory pierPath)
|
2020-05-27 02:01:03 +03:00
|
|
|
logTrace "Directory setup."
|
2019-08-15 05:42:48 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
rwith (Log.new (pierPath <> "/.urb/log") ident) $ \log -> do
|
|
|
|
logTrace "Event log initialized."
|
|
|
|
jobs <- (\now -> bootSeqJobs now seq) <$> io Time.now
|
|
|
|
writeJobs log (fromList jobs)
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
logTrace "Finsihed populating event log with boot sequence"
|
2019-08-15 05:42:48 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
booted :: (HasPierConfig e, HasStderrLogFunc e, HasLogFunc e)
|
|
|
|
=> Pill -> Bool -> [Serf.Flag] -> Ship -> LegacyBootEvent
|
|
|
|
-> RAcquire e (Serf, EventLog)
|
|
|
|
booted pill lite flags ship boot = do
|
|
|
|
rio $ bootNewShip pill lite flags ship boot
|
|
|
|
resumed Nothing flags
|
2019-07-21 22:56:18 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Resume an existing ship. ----------------------------------------------------
|
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
resumed
|
|
|
|
:: (HasStderrLogFunc e, HasPierConfig e, HasLogFunc e)
|
|
|
|
=> Maybe Word64
|
|
|
|
-> [Serf.Flag]
|
|
|
|
-> RAcquire e (Serf, EventLog)
|
|
|
|
resumed replayUntil flags = do
|
|
|
|
rio $ logTrace "Resuming ship"
|
|
|
|
top <- view pierPathL
|
|
|
|
tap <- fmap (fromMaybe top) $ rio $ runMaybeT $ do
|
|
|
|
ev <- MaybeT (pure replayUntil)
|
|
|
|
MaybeT (getSnapshot top ev)
|
2020-02-06 02:20:32 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
rio $ logTrace $ display @Text ("pier: " <> pack top)
|
|
|
|
rio $ logTrace $ display @Text ("running serf in: " <> pack tap)
|
2020-02-06 02:20:32 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
log <- Log.existing (top <> "/.urb/log")
|
|
|
|
serf <- runSerf tap flags
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
rio $ do
|
|
|
|
logTrace "Replaying events"
|
|
|
|
Serf.execReplay serf log replayUntil
|
|
|
|
logTrace "Taking snapshot"
|
|
|
|
Serf.execSnapshot serf
|
|
|
|
logTrace "Shuting down the serf"
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
pure (serf, log)
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2020-01-25 03:20:13 +03:00
|
|
|
getSnapshot :: forall e. FilePath -> Word64 -> RIO e (Maybe FilePath)
|
2020-01-11 01:07:29 +03:00
|
|
|
getSnapshot top last = do
|
2020-01-25 03:20:13 +03:00
|
|
|
lastSnapshot <- lastMay <$> listReplays
|
|
|
|
pure (replayToPath <$> lastSnapshot)
|
|
|
|
where
|
|
|
|
replayDir = top </> ".partial-replay"
|
|
|
|
replayToPath eId = replayDir </> show eId
|
|
|
|
|
|
|
|
listReplays :: RIO e [Word64]
|
|
|
|
listReplays = do
|
|
|
|
createDirectoryIfMissing True replayDir
|
|
|
|
snapshotNums <- mapMaybe readMay <$> listDirectory replayDir
|
|
|
|
pure $ sort (filter (<= fromIntegral last) snapshotNums)
|
2020-01-11 01:07:29 +03:00
|
|
|
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2019-06-29 04:46:33 +03:00
|
|
|
-- Run Pier --------------------------------------------------------------------
|
|
|
|
|
2019-09-18 09:59:07 +03:00
|
|
|
acquireWorker :: RIO e () -> RAcquire e (Async ())
|
2019-09-18 20:55:21 +03:00
|
|
|
acquireWorker act = mkRAcquire (async act) cancel
|
2019-09-18 09:59:07 +03:00
|
|
|
|
2019-12-17 19:55:10 +03:00
|
|
|
pier :: ∀e. (HasConfigDir e, HasLogFunc e, HasNetworkConfig e, HasPierConfig e)
|
2020-05-27 02:01:03 +03:00
|
|
|
=> (Serf, EventLog)
|
|
|
|
-> TVar (Text -> IO ())
|
2020-01-11 03:39:31 +03:00
|
|
|
-> MVar ()
|
2019-08-28 14:45:49 +03:00
|
|
|
-> RAcquire e ()
|
2020-05-27 02:01:03 +03:00
|
|
|
pier (serf, log) vStderr mStart = do
|
2019-09-18 08:22:19 +03:00
|
|
|
computeQ <- newTQueueIO
|
|
|
|
persistQ <- newTQueueIO
|
|
|
|
executeQ <- newTQueueIO
|
|
|
|
saveM <- newEmptyTMVarIO
|
|
|
|
shutdownM <- newEmptyTMVarIO
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-12-17 21:06:20 +03:00
|
|
|
kapi ← King.kingAPI
|
|
|
|
|
|
|
|
termApiQ <- atomically $ do
|
|
|
|
q <- newTQueue
|
|
|
|
writeTVar (King.kTermConn kapi) (Just $ writeTQueue q)
|
|
|
|
pure q
|
2019-12-17 19:55:10 +03:00
|
|
|
|
2019-09-10 23:31:18 +03:00
|
|
|
let shutdownEvent = putTMVar shutdownM ()
|
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
inst <- io (KingId . UV . fromIntegral <$> randomIO @Word16)
|
2019-08-01 08:48:08 +03:00
|
|
|
|
2019-12-17 14:29:58 +03:00
|
|
|
-- (sz, local) <- Term.localClient
|
2019-09-18 09:17:54 +03:00
|
|
|
|
2019-12-17 21:06:20 +03:00
|
|
|
-- (waitExternalTerm, termServPort) <- Term.termServer
|
2019-09-18 09:59:07 +03:00
|
|
|
|
|
|
|
(demux, muxed) <- atomically $ do
|
2019-09-18 09:17:54 +03:00
|
|
|
res <- Term.mkDemux
|
2019-12-17 14:29:58 +03:00
|
|
|
-- Term.addDemux local res
|
2019-09-18 09:59:07 +03:00
|
|
|
pure (res, Term.useDemux res)
|
|
|
|
|
2019-12-17 21:06:20 +03:00
|
|
|
-- rio $ logInfo $ display $
|
|
|
|
-- "TERMSERV Terminal Server running on port: " <> tshow termServPort
|
2019-09-18 09:59:07 +03:00
|
|
|
|
2019-12-17 21:06:20 +03:00
|
|
|
acquireWorker $ forever $ do
|
2019-09-18 12:11:18 +03:00
|
|
|
logTrace "TERMSERV Waiting for external terminal."
|
2019-12-17 21:06:20 +03:00
|
|
|
atomically $ do
|
|
|
|
ext <- Term.connClient <$> readTQueue termApiQ
|
|
|
|
Term.addDemux ext demux
|
|
|
|
logTrace "TERMSERV External terminal connected."
|
2019-09-18 09:17:54 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
atomically $ writeTVar vStderr (atomically . Term.trace muxed)
|
2019-09-04 01:17:20 +03:00
|
|
|
|
2019-10-09 02:18:52 +03:00
|
|
|
let logId = Log.identity log
|
|
|
|
let ship = who logId
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2019-10-12 00:05:25 +03:00
|
|
|
-- Our call above to set the logging function which echos errors from the
|
|
|
|
-- Serf doesn't have the appended \r\n because those \r\n s are added in
|
|
|
|
-- the c serf code. Logging output from our haskell process must manually
|
|
|
|
-- add them.
|
|
|
|
let showErr = atomically . Term.trace muxed . (flip append "\r\n")
|
2019-08-01 05:34:14 +03:00
|
|
|
let (bootEvents, startDrivers) =
|
2019-10-18 01:32:06 +03:00
|
|
|
drivers inst ship (isFake logId)
|
2019-09-18 09:17:54 +03:00
|
|
|
(writeTQueue computeQ)
|
|
|
|
shutdownEvent
|
2020-02-15 11:21:55 +03:00
|
|
|
(Term.TSize{tsWide=80, tsTall=24}, muxed)
|
2019-10-12 00:05:25 +03:00
|
|
|
showErr
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2019-09-10 23:31:18 +03:00
|
|
|
io $ atomically $ for_ bootEvents (writeTQueue computeQ)
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
let stubErrCallback = \_ -> pure ()
|
|
|
|
|
2019-08-01 08:16:02 +03:00
|
|
|
tExe <- startDrivers >>= router (readTQueue executeQ)
|
2019-08-01 05:34:14 +03:00
|
|
|
tDisk <- runPersist log persistQ (writeTQueue executeQ)
|
2020-05-27 02:01:03 +03:00
|
|
|
tCpu <- runCompute serf
|
|
|
|
((,stubErrCallback) <$> readTQueue computeQ)
|
2019-09-18 07:41:31 +03:00
|
|
|
(takeTMVar saveM)
|
|
|
|
(takeTMVar shutdownM)
|
2019-09-18 09:17:54 +03:00
|
|
|
(Term.spin muxed)
|
|
|
|
(Term.stopSpin muxed)
|
2019-09-18 07:41:31 +03:00
|
|
|
(writeTQueue persistQ)
|
2019-07-20 06:00:23 +03:00
|
|
|
|
2019-09-10 23:31:18 +03:00
|
|
|
tSaveSignal <- saveSignalThread saveM
|
2019-09-06 22:59:56 +03:00
|
|
|
|
2020-01-11 03:39:31 +03:00
|
|
|
putMVar mStart ()
|
|
|
|
|
2019-08-01 08:16:02 +03:00
|
|
|
-- Wait for something to die.
|
2019-07-20 06:00:23 +03:00
|
|
|
|
2019-08-01 08:16:02 +03:00
|
|
|
let ded = asum [ death "effect thread" tExe
|
|
|
|
, death "persist thread" tDisk
|
|
|
|
, death "compute thread" tCpu
|
|
|
|
]
|
|
|
|
|
|
|
|
atomically ded >>= \case
|
2019-08-28 14:45:49 +03:00
|
|
|
Left (txt, exn) -> logError $ displayShow ("Somthing died", txt, exn)
|
|
|
|
Right tag -> logError $ displayShow ("something simply exited", tag)
|
2019-08-01 08:16:02 +03:00
|
|
|
|
2019-09-20 01:40:23 +03:00
|
|
|
atomically $ (Term.spin muxed) (Just "shutdown")
|
|
|
|
|
|
|
|
|
2019-08-01 08:16:02 +03:00
|
|
|
death :: Text -> Async () -> STM (Either (Text, SomeException) Text)
|
|
|
|
death tag tid = do
|
|
|
|
waitCatchSTM tid <&> \case
|
|
|
|
Left exn -> Left (tag, exn)
|
|
|
|
Right () -> Right tag
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2019-09-10 23:31:18 +03:00
|
|
|
saveSignalThread :: TMVar () -> RAcquire e (Async ())
|
|
|
|
saveSignalThread tm = mkRAcquire start cancel
|
2019-09-06 22:59:56 +03:00
|
|
|
where
|
|
|
|
start = async $ forever $ do
|
|
|
|
threadDelay (120 * 1000000) -- 120 seconds
|
2019-09-10 23:31:18 +03:00
|
|
|
atomically $ putTMVar tm ()
|
2019-09-06 22:59:56 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2019-08-01 05:34:14 +03:00
|
|
|
-- Start All Drivers -----------------------------------------------------------
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2019-08-29 03:26:59 +03:00
|
|
|
data Drivers e = Drivers
|
|
|
|
{ dAmes :: EffCb e AmesEf
|
|
|
|
, dBehn :: EffCb e BehnEf
|
|
|
|
, dHttpClient :: EffCb e HttpClientEf
|
|
|
|
, dHttpServer :: EffCb e HttpServerEf
|
|
|
|
, dNewt :: EffCb e NewtEf
|
|
|
|
, dSync :: EffCb e SyncEf
|
|
|
|
, dTerm :: EffCb e TermEf
|
2019-08-01 05:34:14 +03:00
|
|
|
}
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2019-10-22 21:25:04 +03:00
|
|
|
drivers :: (HasLogFunc e, HasNetworkConfig e, HasPierConfig e)
|
2019-10-18 01:32:06 +03:00
|
|
|
=> KingId -> Ship -> Bool -> (Ev -> STM ())
|
2019-10-09 02:18:52 +03:00
|
|
|
-> STM()
|
2020-02-15 11:21:55 +03:00
|
|
|
-> (Term.TSize, Term.Client)
|
2019-10-12 00:05:25 +03:00
|
|
|
-> (Text -> RIO e ())
|
2019-08-29 03:26:59 +03:00
|
|
|
-> ([Ev], RAcquire e (Drivers e))
|
2019-10-18 01:32:06 +03:00
|
|
|
drivers inst who isFake plan shutdownSTM termSys stderr =
|
2019-08-01 05:34:14 +03:00
|
|
|
(initialEvents, runDrivers)
|
|
|
|
where
|
|
|
|
(behnBorn, runBehn) = behn inst plan
|
2019-10-18 01:32:06 +03:00
|
|
|
(amesBorn, runAmes) = ames inst who isFake plan stderr
|
2019-12-20 00:20:31 +03:00
|
|
|
(httpBorn, runHttp) = serv inst plan isFake
|
2019-10-18 00:06:25 +03:00
|
|
|
(clayBorn, runClay) = clay inst plan
|
2019-09-05 23:09:45 +03:00
|
|
|
(irisBorn, runIris) = client inst plan
|
2019-10-18 00:06:25 +03:00
|
|
|
(termBorn, runTerm) = Term.term termSys shutdownSTM inst plan
|
2019-09-10 23:14:43 +03:00
|
|
|
initialEvents = mconcat [behnBorn, clayBorn, amesBorn, httpBorn,
|
|
|
|
termBorn, irisBorn]
|
2019-08-01 05:34:14 +03:00
|
|
|
runDrivers = do
|
2019-10-09 01:01:16 +03:00
|
|
|
dNewt <- runAmes
|
2019-08-29 03:26:59 +03:00
|
|
|
dBehn <- liftAcquire $ runBehn
|
2019-08-01 08:16:02 +03:00
|
|
|
dAmes <- pure $ const $ pure ()
|
2019-09-05 23:09:45 +03:00
|
|
|
dHttpClient <- runIris
|
2019-08-08 01:24:02 +03:00
|
|
|
dHttpServer <- runHttp
|
2019-09-10 23:14:43 +03:00
|
|
|
dSync <- runClay
|
2019-09-03 21:02:54 +03:00
|
|
|
dTerm <- runTerm
|
2019-08-01 05:34:14 +03:00
|
|
|
pure (Drivers{..})
|
|
|
|
|
|
|
|
|
|
|
|
-- Route Effects to Drivers ----------------------------------------------------
|
|
|
|
|
2019-08-29 03:26:59 +03:00
|
|
|
router :: HasLogFunc e => STM FX -> Drivers e -> RAcquire e (Async ())
|
2019-08-28 14:45:49 +03:00
|
|
|
router waitFx Drivers{..} =
|
|
|
|
mkRAcquire start cancel
|
2019-08-01 05:34:14 +03:00
|
|
|
where
|
|
|
|
start = async $ forever $ do
|
|
|
|
fx <- atomically waitFx
|
2019-08-01 08:16:02 +03:00
|
|
|
for_ fx $ \ef -> do
|
2019-08-28 14:45:49 +03:00
|
|
|
logEffect ef
|
2019-08-01 08:16:02 +03:00
|
|
|
case ef of
|
|
|
|
GoodParse (EfVega _ _) -> error "TODO"
|
|
|
|
GoodParse (EfExit _ _) -> error "TODO"
|
|
|
|
GoodParse (EfVane (VEAmes ef)) -> dAmes ef
|
|
|
|
GoodParse (EfVane (VEBehn ef)) -> dBehn ef
|
|
|
|
GoodParse (EfVane (VEBoat ef)) -> dSync ef
|
|
|
|
GoodParse (EfVane (VEClay ef)) -> dSync ef
|
|
|
|
GoodParse (EfVane (VEHttpClient ef)) -> dHttpClient ef
|
|
|
|
GoodParse (EfVane (VEHttpServer ef)) -> dHttpServer ef
|
|
|
|
GoodParse (EfVane (VENewt ef)) -> dNewt ef
|
|
|
|
GoodParse (EfVane (VESync ef)) -> dSync ef
|
|
|
|
GoodParse (EfVane (VETerm ef)) -> dTerm ef
|
2019-08-28 14:45:49 +03:00
|
|
|
FailParse n -> logError
|
|
|
|
$ display
|
|
|
|
$ pack @Text (ppShow n)
|
2019-07-21 22:56:18 +03:00
|
|
|
|
2019-08-01 05:34:14 +03:00
|
|
|
|
|
|
|
-- Compute Thread --------------------------------------------------------------
|
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
logEvent :: HasLogFunc e => Ev -> RIO e ()
|
|
|
|
logEvent ev =
|
|
|
|
logDebug $ display $ "[EVENT]\n" <> pretty
|
|
|
|
where
|
|
|
|
pretty :: Text
|
|
|
|
pretty = pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow ev
|
|
|
|
|
|
|
|
logEffect :: HasLogFunc e => Lenient Ef -> RIO e ()
|
|
|
|
logEffect ef =
|
|
|
|
logDebug $ display $ "[EFFECT]\n" <> pretty ef
|
|
|
|
where
|
|
|
|
pretty :: Lenient Ef -> Text
|
|
|
|
pretty = \case
|
|
|
|
GoodParse e -> pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow e
|
|
|
|
FailParse n -> pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow n
|
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
data ComputeRequest
|
|
|
|
= CREvent (Ev, Serf.RunError -> IO ())
|
|
|
|
| CRSave ()
|
|
|
|
| CRShutdown ()
|
|
|
|
|
|
|
|
runCompute
|
|
|
|
:: forall e
|
|
|
|
. HasLogFunc e
|
|
|
|
=> Serf
|
|
|
|
-> STM (Ev, Serf.RunError -> IO ())
|
|
|
|
-> STM ()
|
|
|
|
-> STM ()
|
|
|
|
-> (Maybe Text -> STM ())
|
|
|
|
-> STM ()
|
|
|
|
-> ((Job, FX) -> STM ())
|
|
|
|
-> RAcquire e (Async ())
|
|
|
|
runCompute serf getEvent getSaveSignal getShutdownSignal showSpinner hideSpinner putResult = do
|
|
|
|
mkRAcquire (async $ newRunCompute serf config) cancel
|
|
|
|
where
|
|
|
|
config = ComputeConfig
|
|
|
|
{ ccOnWork = getEvent
|
|
|
|
, ccOnKill = getShutdownSignal
|
|
|
|
, ccOnSave = getSaveSignal
|
|
|
|
, ccPutResult = putResult
|
|
|
|
, ccShowSpinner = showSpinner
|
|
|
|
, ccHideSpinner = hideSpinner
|
|
|
|
}
|
|
|
|
|
|
|
|
-- data RunOutput = RunOutput EventId Mug Wen (Either Noun Ev) [Ef]
|
|
|
|
-- data Work = Work EventId Mug Wen Ev
|
|
|
|
|
|
|
|
{-
|
|
|
|
data ComputeRequest
|
|
|
|
= CREvent Ev (Serf.RunError -> IO ())
|
|
|
|
| CRSave ()
|
|
|
|
| CRShutdown ()
|
|
|
|
deriving (Eq, Show)
|
|
|
|
-}
|
|
|
|
|
|
|
|
{-
|
|
|
|
TODO Pack and Peek
|
|
|
|
-}
|
|
|
|
ipcSource
|
|
|
|
:: forall e
|
|
|
|
. HasLogFunc e
|
|
|
|
=> STM (Ev, Serf.RunError -> IO ())
|
|
|
|
-> STM ()
|
|
|
|
-> STM ()
|
|
|
|
-> ConduitT () Serf.RunInput (RIO e) ()
|
|
|
|
ipcSource onEvent onSave onKill = loop
|
|
|
|
where
|
|
|
|
loop :: ConduitT () Serf.RunInput (RIO e) ()
|
|
|
|
loop = do
|
|
|
|
lift $ logTrace "ipcSource waiting for work request."
|
|
|
|
let down = CRShutdown <$> onKill
|
|
|
|
let save = CRSave <$> onSave
|
|
|
|
let work = CREvent <$> onEvent
|
|
|
|
atomically (down <|> save <|> work) >>= \case
|
|
|
|
CRShutdown () -> do
|
|
|
|
pure ()
|
|
|
|
CRSave () -> do
|
|
|
|
lift $ logTrace "ipcSource: requesting snapshot"
|
|
|
|
yield Serf.RunSnap
|
|
|
|
loop
|
|
|
|
CREvent (ev, cb) -> do
|
|
|
|
lift $ logTrace "ipcSource: requesting work"
|
|
|
|
yield (Serf.RunWork ev cb)
|
|
|
|
loop
|
|
|
|
|
|
|
|
fromRightErr :: Either a b -> IO b
|
|
|
|
fromRightErr (Left l) = error "unexpected Left value"
|
|
|
|
fromRightErr (Right r) = pure r
|
|
|
|
|
|
|
|
data ComputeConfig = ComputeConfig
|
|
|
|
{ ccOnWork :: STM (Ev, Serf.RunError -> IO ())
|
|
|
|
, ccOnKill :: STM ()
|
|
|
|
, ccOnSave :: STM ()
|
|
|
|
, ccPutResult :: (Job, FX) -> STM ()
|
|
|
|
, ccShowSpinner :: Maybe Text -> STM ()
|
|
|
|
, ccHideSpinner :: STM ()
|
|
|
|
}
|
|
|
|
|
|
|
|
newRunCompute
|
|
|
|
:: forall e . HasLogFunc e => Serf.Serf -> ComputeConfig -> RIO e ()
|
|
|
|
newRunCompute serf ComputeConfig {..} = do
|
|
|
|
logTrace "newRunCompute"
|
|
|
|
runConduit
|
|
|
|
$ ipcSource ccOnWork ccOnSave ccOnKill
|
|
|
|
.| Serf.running serf (atomically . onStatusChange)
|
|
|
|
.| sendResults
|
|
|
|
where
|
|
|
|
sendResults :: ConduitT Serf.RunOutput Void (RIO e) ()
|
|
|
|
sendResults = await >>= \case
|
|
|
|
Nothing -> pure ()
|
|
|
|
Just (Serf.RunOutput e m w nounEv fx) -> do
|
|
|
|
lift $ logTrace "newRunCompute: Got play result"
|
|
|
|
ev <- io $ fromRightErr nounEv -- TODO
|
|
|
|
let job :: Job = DoWork $ Work e m w ev
|
|
|
|
atomically (ccPutResult ((job, GoodParse <$> fx))) -- TODO GoodParse
|
|
|
|
sendResults
|
|
|
|
|
|
|
|
onStatusChange :: Maybe Serf.RunInput -> STM ()
|
|
|
|
onStatusChange = \case
|
|
|
|
Nothing -> ccHideSpinner
|
|
|
|
Just (Serf.RunWork ev _) -> ccShowSpinner (getSpinnerNameForEvent ev)
|
|
|
|
_ -> pure ()
|
|
|
|
|
|
|
|
|
|
|
|
{-
|
|
|
|
FIND ME
|
|
|
|
|
|
|
|
send event
|
|
|
|
push event
|
|
|
|
start spinner
|
|
|
|
hook for when event starts running
|
|
|
|
hook for when no event is running
|
|
|
|
send another event
|
|
|
|
first event is done
|
|
|
|
push to persistQ
|
|
|
|
update spinner to event #2
|
|
|
|
second event is done
|
|
|
|
push to executeQ
|
|
|
|
remove spinner
|
|
|
|
-}
|
2019-07-21 22:56:18 +03:00
|
|
|
|
|
|
|
|
2019-07-20 06:00:23 +03:00
|
|
|
-- Persist Thread --------------------------------------------------------------
|
|
|
|
|
|
|
|
data PersistExn = BadEventId EventId EventId
|
|
|
|
deriving Show
|
|
|
|
|
|
|
|
instance Exception PersistExn where
|
|
|
|
displayException (BadEventId expected got) =
|
|
|
|
unlines [ "Out-of-order event id send to persist thread."
|
|
|
|
, "\tExpected " <> show expected <> " but got " <> show got
|
|
|
|
]
|
|
|
|
|
2019-10-18 02:10:53 +03:00
|
|
|
runPersist :: ∀e. (HasPierConfig e, HasLogFunc e)
|
2019-09-17 23:37:41 +03:00
|
|
|
=> EventLog
|
2019-08-01 05:34:14 +03:00
|
|
|
-> TQueue (Job, FX)
|
|
|
|
-> (FX -> STM ())
|
2019-08-28 14:45:49 +03:00
|
|
|
-> RAcquire e (Async ())
|
2019-08-01 05:34:14 +03:00
|
|
|
runPersist log inpQ out =
|
2019-09-17 23:37:41 +03:00
|
|
|
mkRAcquire runThread cancel
|
2019-07-20 06:00:23 +03:00
|
|
|
where
|
2019-08-28 14:45:49 +03:00
|
|
|
runThread :: RIO e (Async ())
|
2019-10-18 02:10:53 +03:00
|
|
|
runThread = asyncBound $ do
|
2019-12-17 17:31:50 +03:00
|
|
|
dryRun <- view dryRunL
|
2019-10-18 02:10:53 +03:00
|
|
|
forever $ do
|
|
|
|
writs <- atomically getBatchFromQueue
|
|
|
|
unless dryRun $ do
|
|
|
|
events <- validateJobsAndGetBytes (toNullable writs)
|
|
|
|
Log.appendEvents log events
|
|
|
|
atomically $ for_ writs $ \(_,fx) -> out fx
|
2019-07-20 06:00:23 +03:00
|
|
|
|
2019-08-28 14:45:49 +03:00
|
|
|
validateJobsAndGetBytes :: [(Job, FX)] -> RIO e (Vector ByteString)
|
2019-08-01 05:34:14 +03:00
|
|
|
validateJobsAndGetBytes writs = do
|
2019-07-20 06:00:23 +03:00
|
|
|
expect <- Log.nextEv log
|
|
|
|
fmap fromList
|
|
|
|
$ for (zip [expect..] writs)
|
2019-08-01 05:34:14 +03:00
|
|
|
$ \(expectedId, (j, fx)) -> do
|
|
|
|
unless (expectedId == jobId j) $
|
|
|
|
throwIO (BadEventId expectedId (jobId j))
|
|
|
|
case j of
|
|
|
|
RunNok _ ->
|
|
|
|
error "This shouldn't happen here!"
|
|
|
|
DoWork (Work eId mug wen ev) ->
|
|
|
|
pure $ jamBS $ toNoun (mug, wen, ev)
|
|
|
|
|
|
|
|
getBatchFromQueue :: STM (NonNull [(Job, FX)])
|
2019-07-20 06:00:23 +03:00
|
|
|
getBatchFromQueue =
|
|
|
|
readTQueue inpQ >>= go . singleton
|
|
|
|
where
|
|
|
|
go acc =
|
|
|
|
tryReadTQueue inpQ >>= \case
|
|
|
|
Nothing -> pure (reverse acc)
|
|
|
|
Just item -> go (item <| acc)
|