module AWS.Secrets
  ( getSecret,
    getSecretOrFail,
    SecretsConfig,
    SecretReader,
    SecretKey,
    SecretName,
  )
where

import AWS.Secrets.Config (SecretsConfig)
import AWS.Secrets.Fetch (fetchSecret)
import AWS.Secrets.Key (SecretKey)
import AWS.Secrets.Name (SecretName)
import AWS.Secrets.Reader (SecretReader)
import qualified AWS.Secrets.Reader as Reader
import AWS.Secrets.SecretType (Secret, getSecretValue)
import Control.Applicative (pure)
import Control.Monad ((>>=))
import Control.Monad.Except (ExceptT, MonadError, runExceptT, throwError)
import Control.Monad.Fail (fail)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Either (either)
import Data.Foldable (toList)
import Data.Function
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Validation (validation)
import System.IO (IO)

getSecret ::
  (MonadIO m, MonadError (Seq Text) m) =>
  SecretsConfig ->
  SecretName ->
  SecretReader a ->
  m a
getSecret :: forall (m :: * -> *) a.
(MonadIO m, MonadError (Seq Text) m) =>
SecretsConfig -> SecretName -> SecretReader a -> m a
getSecret SecretsConfig
config SecretName
name SecretReader a
reader = do
  Secret
s :: Secret <- (Text -> Seq Text) -> ExceptT Text m Secret -> m Secret
forall e' (m :: * -> *) e a.
MonadError e' m =>
(e -> e') -> ExceptT e m a -> m a
modifyError Text -> Seq Text
forall a. a -> Seq a
Seq.singleton (ExceptT Text m Secret -> m Secret)
-> ExceptT Text m Secret -> m Secret
forall a b. (a -> b) -> a -> b
$ SecretsConfig -> SecretName -> ExceptT Text m Secret
forall (m :: * -> *) result.
(MonadIO m, MonadError Text m, FromJSON result) =>
SecretsConfig -> SecretName -> m result
fetchSecret SecretsConfig
config SecretName
name
  SecretReader a -> Object -> Validation (Seq Text) a
forall a. SecretReader a -> Object -> Validation (Seq Text) a
Reader.apply SecretReader a
reader (Secret -> Object
getSecretValue Secret
s) Validation (Seq Text) a -> (Validation (Seq Text) a -> m a) -> m a
forall a b. a -> (a -> b) -> b
& (Seq Text -> m a) -> (a -> m a) -> Validation (Seq Text) a -> m a
forall e c a. (e -> c) -> (a -> c) -> Validation e a -> c
validation Seq Text -> m a
forall a. Seq Text -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

getSecretOrFail ::
  (MonadIO m) =>
  SecretsConfig ->
  SecretName ->
  SecretReader a ->
  m a
getSecretOrFail :: forall (m :: * -> *) a.
MonadIO m =>
SecretsConfig -> SecretName -> SecretReader a -> m a
getSecretOrFail SecretsConfig
config SecretName
name SecretReader a
reader =
  ExceptT (Seq Text) m a -> m (Either (Seq Text) a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (SecretsConfig
-> SecretName -> SecretReader a -> ExceptT (Seq Text) m a
forall (m :: * -> *) a.
(MonadIO m, MonadError (Seq Text) m) =>
SecretsConfig -> SecretName -> SecretReader a -> m a
getSecret SecretsConfig
config SecretName
name SecretReader a
reader)
    m (Either (Seq Text) a) -> (Either (Seq Text) a -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Seq Text -> m a) -> (a -> m a) -> Either (Seq Text) a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> (Seq Text -> IO a) -> Seq Text -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadFail m => String -> m a
fail @IO (String -> IO a) -> (Seq Text -> String) -> Seq Text -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack (Text -> String) -> (Seq Text -> Text) -> Seq Text -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
Text.unlines ([Text] -> Text) -> (Seq Text -> [Text]) -> Seq Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Seq Text -> [Text]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList) a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- This can be gotten from "Control.Monad.Except" after upgrading to mtl 2.3.1
modifyError :: MonadError e' m => (e -> e') -> ExceptT e m a -> m a
modifyError :: forall e' (m :: * -> *) e a.
MonadError e' m =>
(e -> e') -> ExceptT e m a -> m a
modifyError e -> e'
f ExceptT e m a
m = ExceptT e m a -> m (Either e a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT e m a
m m (Either e a) -> (Either e a -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (e -> m a) -> (a -> m a) -> Either e a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (e' -> m a
forall a. e' -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (e' -> m a) -> (e -> e') -> e -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> e'
f) a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure