{-# Language InstanceSigs #-}
{-# Language LambdaCase #-}
module E.Action
(
Action(..), act,
InFP(..), InMetaFP(..), Out(..), OutMetaFP(..),
ActError(..),
ActResult(..)
) where
import Control.Monad (unless)
import Control.Monad.Except
import Control.Monad.Trans.Either
import Data.Aeson (eitherDecode)
import qualified Data.ByteString.Lazy as BSL
import Data.Either.Combinators
import Data.Either.MoreCombinators
import qualified Data.Text.IO as TIO
import System.Directory (doesFileExist)
import Data.Attoparsec.Text
import E.Encrypt
import E.Metadata
import E.Template
data Action
= ActEnc Algs InFP (Maybe InMetaFP) Out OutMetaFP
| ActDec Algs InFP InMetaFP Out
newtype InFP = InFP { unInFP :: FilePath }
deriving (Eq,Show)
data Out
= OutFP FilePath
| OutStd
newtype InMetaFP = InMetaFP { unInMetaFP :: FilePath }
deriving (Eq,Show)
newtype OutMetaFP = OutMetaFP { unOutMetaFP :: FilePath }
data ActError
= InputFileNotFound InFP
| InputMetadataFileNotFound InMetaFP
| MetadataParsingError String
| EncryptionError EError
| DecryptionError EError
deriving (Eq,Show)
data ActResult a = ActResult { runActResult :: EitherT ActError IO a }
instance Functor ActResult where
fmap f (ActResult v) = ActResult (fmap f v)
{-# INLINE fmap #-}
instance Applicative ActResult where
pure = ActResult . right
{-# INLINE pure #-}
ActResult f <*> ActResult v = ActResult (f <*> v)
{-# INLINE (<*>) #-}
instance Monad ActResult where
m >>= f = ActResult . EitherT $ do
a <- runEitherT (runActResult m)
case a of
Left l -> pure (Left l)
Right r -> runEitherT (runActResult (f r))
{-# INLINE (>>=) #-}
return = pure
{-# INLINE return #-}
instance MonadIO ActResult where
liftIO = ActResult . lift
liftIOEither :: IO (Either ActError a) -> ActResult a
liftIOEither = ActResult . EitherT
actError :: ActError -> ActResult a
actError = ActResult . left
enc :: Algs -> Maybe InMetaFP -> InFP -> ActResult (Tem, Metadata)
enc e mimfp ifp = do
m <- parseMetadataOrCreate mimfp
t <- parseTemplate ifp
ActResult (mapLeftT EncryptionError (encryptTem e m t))
dec :: Algs -> InMetaFP -> InFP -> ActResult Tem
dec e imfp ifp = do
m <- parseMetadata imfp
t <- parseTemplate ifp
ActResult (mapLeftT DecryptionError (decryptTem e m t))
parseMetadataOrCreate :: Maybe InMetaFP -> ActResult Metadata
parseMetadataOrCreate Nothing = pure mempty
parseMetadataOrCreate (Just mfp) = parseMetadata mfp
parseMetadata :: InMetaFP -> ActResult Metadata
parseMetadata mfp = do
mfpe <- liftIO . doesFileExist . unInMetaFP $ mfp
unless mfpe $ actError $ InputMetadataFileNotFound mfp
liftIOEither
(mapLeft MetadataParsingError . eitherDecode <$> BSL.readFile (unInMetaFP mfp))
parseTemplate :: InFP -> ActResult Tem
parseTemplate ifp = do
ifpe <- liftIO . doesFileExist . unInFP $ ifp
unless ifpe $ actError $ InputFileNotFound ifp
liftIOEither
(mapLeft absurd . parseOnly parseTem <$> TIO.readFile (unInFP ifp))
where
absurd _ = error "It cannot be! parseTemplate always returns Just Tem"
act :: Action -> ActResult ()
act (ActEnc e ifp mimfp out omfp) = do
(t, m) <- enc e mimfp ifp
liftIO $ do
case out of
OutFP ofp -> TIO.writeFile ofp (encode t)
OutStd -> TIO.putStrLn (encode t)
TIO.writeFile (unOutMetaFP omfp) (encode m)
act (ActDec e ifp imfp out) = do
t <- dec e imfp ifp
liftIO $
case out of
OutFP ofp -> TIO.writeFile ofp (encode t)
OutStd -> TIO.putStrLn (encode t)