mirror of
https://github.com/urbit/shrub.git
synced 2024-12-22 10:21:31 +03:00
194 lines
5.5 KiB
Haskell
194 lines
5.5 KiB
Haskell
{-|
|
|
Interactive Event-Log Browser
|
|
|
|
TODO Handle CTRL-D
|
|
-}
|
|
|
|
module Urbit.King.EventBrowser (run) where
|
|
|
|
import Urbit.Prelude
|
|
|
|
import Data.Conduit
|
|
import Urbit.Arvo
|
|
import Urbit.Noun.Time
|
|
import Urbit.Vere.Pier.Types
|
|
|
|
import Control.Monad.Trans.Maybe (MaybeT(..))
|
|
import Urbit.EventLog.LMDB (EventLog)
|
|
|
|
import qualified Data.Conduit.Combinators as C
|
|
import qualified Urbit.EventLog.LMDB as Log
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
data Event = Event
|
|
{ num :: Word64
|
|
, mug :: Mug
|
|
, wen :: Wen
|
|
, ova :: Ev
|
|
}
|
|
deriving Show
|
|
|
|
data Input = Next | Prev | Quit | Trim | Effs | Init | Last
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
run :: HasLogFunc e => EventLog -> RIO e ()
|
|
run log = do
|
|
hSetBuffering stdin NoBuffering
|
|
hSetEcho stdin False
|
|
logInfo $ displayShow (Log.identity log)
|
|
let cycle = fromIntegral $ lifecycleLen $ Log.identity log
|
|
las <- atomically (Log.lastEv log)
|
|
loop cycle las las
|
|
where
|
|
failRead cur =
|
|
putStrLn ("ERROR: Failed to read event: " <> tshow cur)
|
|
|
|
input cyc las cur mFx = do
|
|
getInput las cur >>= \case
|
|
Next -> loop cyc las (succ cur)
|
|
Prev -> loop cyc las (pred cur)
|
|
Init -> loop cyc las 1
|
|
Last -> loop cyc las las
|
|
Quit -> pure ()
|
|
Trim -> trim cyc las cur mFx
|
|
Effs -> showEffects mFx >> input cyc las cur mFx
|
|
|
|
trim cyc las cur mFx = do
|
|
deleteFrom log las cur >>= \case
|
|
True -> loop cyc (pred cur) (pred cur)
|
|
False -> input cyc las cur mFx
|
|
|
|
loop cyc las 0 = loop cyc las 1
|
|
loop cyc las cur | cur > las = loop cyc las las
|
|
loop cyc las cur | cyc >= cur = do
|
|
putStrLn ""
|
|
putStrLn " [EVENT]"
|
|
putStrLn ""
|
|
putStrLn " Lifecycle Nock"
|
|
putStrLn ""
|
|
input cyc las cur (Just [])
|
|
|
|
loop cyc las cur = do
|
|
mEv <- peekEvent log cur
|
|
mFx <- peekEffect log cur
|
|
|
|
case mEv of
|
|
Nothing -> failRead cur
|
|
Just ev -> showEvent ev >> showEffectsTeaser mFx
|
|
|
|
input cyc las cur mFx
|
|
|
|
deleteFrom :: HasLogFunc e => EventLog -> Word64 -> Word64 -> RIO e Bool
|
|
deleteFrom log las cur = do
|
|
sure <- areYouSure
|
|
if sure then doDelete else abortDelete
|
|
pure sure
|
|
where
|
|
abortDelete = do
|
|
putStrLn "\n\n [ABORTED]\n"
|
|
putStrLn " Aborted delete, no events pruned.\n"
|
|
|
|
doDelete = do
|
|
Log.trimEvents log cur
|
|
putStrLn "\n\n [DELETED]\n"
|
|
putStrLn " It's gone forever!\n"
|
|
|
|
question =
|
|
if las == cur
|
|
then mconcat [ " This will permanently delete the last event (#"
|
|
, tshow las
|
|
, ")\n" ]
|
|
else mconcat [ " This will permanently delete all events in (#"
|
|
, tshow cur
|
|
, " - #"
|
|
, tshow las
|
|
, ")\n" ]
|
|
|
|
areYouSure = do
|
|
putStrLn "\n\n ARE YOU SURE????"
|
|
putStrLn ""
|
|
putStrLn question
|
|
putStr "(y|n) "
|
|
hFlush stdout
|
|
getChar <&> \case
|
|
'y' -> True
|
|
_ -> False
|
|
|
|
getInput :: Word64 -> Word64 -> RIO e Input
|
|
getInput las cur = do
|
|
putStr ("(" <> tshow cur <> "/" <> tshow las <> ") ")
|
|
hFlush stdout
|
|
getChar >>= \case
|
|
'j' -> pure Next
|
|
'k' -> pure Prev
|
|
'q' -> pure Quit
|
|
'f' -> pure Effs
|
|
'x' -> pure Trim
|
|
'0' -> pure Init
|
|
'G' -> pure Last
|
|
_ -> do putStrLn "\n"
|
|
putStrLn help
|
|
getInput las cur
|
|
where
|
|
help = unlines
|
|
[ " [HELP]"
|
|
, ""
|
|
, " k View the previous event"
|
|
, " j View the next event"
|
|
, " 0 View the first event"
|
|
, " G View the last event"
|
|
, " q Quit"
|
|
, " x Delete (only the last event)"
|
|
, " ? Show this help"
|
|
]
|
|
|
|
showEffectsTeaser :: Maybe FX -> RIO e ()
|
|
showEffectsTeaser Nothing = putStrLn " [No collected effects]\n"
|
|
showEffectsTeaser (Just []) = putStrLn " [No effects for this event]\n"
|
|
showEffectsTeaser (Just fx) = putStrLn $ mconcat
|
|
[ " ["
|
|
, tshow (length fx)
|
|
, " collected effects. Press 'f' to view]\n"
|
|
]
|
|
|
|
showEffects :: Maybe FX -> RIO e ()
|
|
showEffects Nothing = putStrLn " [No collected effects]\n"
|
|
showEffects (Just []) = putStrLn " [No effects for this event]\n"
|
|
showEffects (Just fx) = do
|
|
putStrLn "\n"
|
|
putStrLn " [EFFECTS]"
|
|
for_ fx $ \ef -> do
|
|
putStrLn ""
|
|
showEffect ef
|
|
putStrLn ""
|
|
|
|
showEffect :: Lenient Ef -> RIO e ()
|
|
showEffect (GoodParse ef) =
|
|
putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow ef
|
|
showEffect (FailParse n) =
|
|
putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow n
|
|
|
|
showEvent :: Event -> RIO e ()
|
|
showEvent ev = do
|
|
putStrLn "\n"
|
|
putStrLn " [EVENT]"
|
|
putStrLn ""
|
|
putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow (ova ev)
|
|
|
|
peekEffect :: HasLogFunc e => EventLog -> Word64 -> RIO e (Maybe FX)
|
|
peekEffect log eId = runMaybeT $ do
|
|
(id, bs) <- MaybeT $ runConduit (Log.streamEffectsRows log eId .| C.head)
|
|
guard (id == eId)
|
|
io $ cueBSExn bs >>= fromNounExn
|
|
|
|
peekEvent :: HasLogFunc e => EventLog -> Word64 -> RIO e (Maybe Event)
|
|
peekEvent log eId = runMaybeT $ do
|
|
octs <- MaybeT $ runConduit (Log.streamEvents log eId .| C.head)
|
|
noun <- io $ cueBSExn octs
|
|
(m,w,e) <- io $ fromNounExn noun
|
|
ovum <- fromNounExn e
|
|
pure (Event eId m w ovum)
|