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 <- forall e' (m :: * -> *) e a.
MonadError e' m =>
(e -> e') -> ExceptT e m a -> m a
modifyError forall a. a -> Seq a
Seq.singleton forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) result.
(MonadIO m, MonadError Text m, FromJSON result) =>
SecretsConfig -> SecretName -> m result
fetchSecret SecretsConfig
config SecretName
name
  forall a. SecretReader a -> Object -> Validation (Seq Text) a
Reader.apply SecretReader a
reader (Secret -> Object
getSecretValue Secret
s) forall a b. a -> (a -> b) -> b
& forall e c a. (e -> c) -> (a -> c) -> Validation e a -> c
validation forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError 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 =
  forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (forall (m :: * -> *) a.
(MonadIO m, MonadError (Seq Text) m) =>
SecretsConfig -> SecretName -> SecretReader a -> m a
getSecret SecretsConfig
config SecretName
name SecretReader a
reader)
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadFail m => String -> m a
fail @IO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
Text.unlines forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> [a]
toList) 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 = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT ExceptT e m a
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> e'
f) forall (f :: * -> *) a. Applicative f => a -> f a
pure