chiasma-0.2.0.0: lib/Chiasma/Monad/Stream.hs
module Chiasma.Monad.Stream where
import Conduit (ConduitT, Flush(..), runConduit, sinkList, yield, yieldMany, (.|))
import Control.Monad.Trans.Free (FreeT(..))
import qualified Data.Conduit.Combinators as Conduit (drop, take)
import Chiasma.Api.Class (TmuxApi(..))
import Chiasma.Codec.Decode (TmuxDecodeError)
import Chiasma.Data.Cmd (Cmd(..), Cmds(..))
import Chiasma.Data.TmuxError (TmuxError)
import qualified Chiasma.Data.TmuxError as TmuxError (TmuxError(ProcessFailed, DecodingFailed, CommandFailed))
import Chiasma.Data.TmuxThunk (TmuxThunk)
import Chiasma.Monad.EvalFreeT (evalFreeT)
import Chiasma.Native.StreamParse (TmuxOutputBlock)
import qualified Chiasma.Native.StreamParse as TmuxOutputBlock (TmuxOutputBlock(..))
type TmuxProg = FreeT TmuxThunk
type WriteCmd m =
ConduitT (Flush Cmd) Void m ()
type ReadOutput m =
ConduitT () TmuxOutputBlock m ()
handleProcessOutput ::
Cmds ->
(Text -> Either TmuxDecodeError a) ->
[TmuxOutputBlock] ->
Either TmuxError [a]
handleProcessOutput cs@(Cmds cmds) _ output | length output < length cmds =
Left $ TmuxError.ProcessFailed cs "tmux terminated before all commands were processed"
handleProcessOutput cmds decode output = do
readOutput <- foldl validate (Right []) output
traverse decode' readOutput
where
validate (Left err) _ = Left err
validate _ (TmuxOutputBlock.Success a) = Right a
validate _ (TmuxOutputBlock.Error a) = Left $ TmuxError.CommandFailed cmds a
decode' outputLine =
mapLeft (TmuxError.DecodingFailed cmds outputLine) . decode $ outputLine
executeCommands ::
MonadIO m =>
WriteCmd m ->
ReadOutput m ->
(Text -> Either TmuxDecodeError a) ->
Cmds ->
m (Either TmuxError [a])
executeCommands writeCmd readOutput decode cs@(Cmds cmds) = do
output <- runConduit $ do
yieldMany (Chunk <$> reverse cmds) .| writeCmd
yield Flush .| writeCmd
readOutput .| Conduit.take (length cmds) .| sinkList
return $ handleProcessOutput cs decode output
runTmuxProg ::
MonadIO m =>
TmuxProg m a ->
WriteCmd m ->
ReadOutput m ->
m (Either TmuxError a)
runTmuxProg prog writeCmd readOutput = do
runConduit $ readOutput .| Conduit.drop 1
evalFreeT (executeCommands writeCmd readOutput) def prog
runTmuxE ::
(MonadIO m, TmuxApi m api) =>
api ->
TmuxProg m a ->
m (Either TmuxError a)
runTmuxE api prog =
withTmux api (runTmuxProg prog)
runTmux ::
(MonadIO m, MonadDeepError e TmuxError m, TmuxApi m api) =>
api ->
TmuxProg m a ->
m a
runTmux api =
hoistEither <=< runTmuxE api