{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Mismi.Environment (
Env
, Region (..)
, RegionError (..)
, Debugging (..)
, getRegionFromEnv
, getDebugging
, setDebugging
, renderRegionError
, discoverAWSEnv
, discoverAWSEnvWithRegion
, discoverAWSEnvRetry
, discoverAWSEnvWithRegionRetry
, catchAuthError
, newMismiEnv
) where
import Control.Lens ((.~))
import Control.Monad.Catch (Handler (..), MonadCatch (..), MonadThrow (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.AWS (Credentials (..), Region (..))
import Control.Monad.Trans.AWS (Env, envLogger, envRegion, newEnv)
import Control.Monad.Trans.AWS (LogLevel (..), Logger, newLogger)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (ExceptT, throwE)
import Control.Retry (RetryPolicyM, constantDelay, limitRetries, recovering)
import qualified Data.Text as T
import Data.Typeable (Typeable)
import Network.AWS.Auth (AuthError (..))
import Network.AWS.Data (fromText)
import P
import System.Environment (lookupEnv)
import System.IO (IO, stderr)
data RegionError =
MissingRegion
| UnknownRegion Text
deriving (Eq, Show, Typeable)
data Debugging =
DebugEnabled Logger
| DebugDisabled
getRegionFromEnv :: (MonadIO m, MonadThrow m) => ExceptT RegionError m Region
getRegionFromEnv = do
mr <- liftIO $ lookupEnv "AWS_DEFAULT_REGION"
case mr of
Nothing ->
throwE MissingRegion
Just a ->
case fromText $ T.pack a of
Left e ->
throwE $ UnknownRegion (T.pack e)
Right r ->
pure r
getDebugging :: MonadIO m => m Debugging
getDebugging = do
d <- liftIO $ lookupEnv "AWS_DEBUG"
maybe
(return DebugDisabled)
(\s ->
case T.pack s of
"true" ->
return . DebugEnabled =<< newLogger Trace stderr
"1" ->
return . DebugEnabled =<< newLogger Trace stderr
_ ->
return DebugDisabled)
d
setDebugging :: Debugging -> Env -> Env
setDebugging d e =
case d of
DebugEnabled lgr ->
e & envLogger .~ lgr
DebugDisabled ->
e
discoverAWSEnv :: ExceptT RegionError IO Env
discoverAWSEnv =
discoverAWSEnvRetry $ limitRetries 1 <> constantDelay 200000
discoverAWSEnvWithRegion :: Region -> IO Env
discoverAWSEnvWithRegion r =
flip discoverAWSEnvWithRegionRetry r $ limitRetries 1 <> constantDelay 200000
discoverAWSEnvRetry :: RetryPolicyM IO -> ExceptT RegionError IO Env
discoverAWSEnvRetry retry = do
r <- getRegionFromEnv
lift $ discoverAWSEnvWithRegionRetry retry r
discoverAWSEnvWithRegionRetry :: RetryPolicyM IO -> Region -> IO Env
discoverAWSEnvWithRegionRetry rpol r = do
d <- getDebugging
e <- recovering rpol [(\_ -> Handler catchAuthError)] $ \_ -> newMismiEnv r Discover
pure $ setDebugging d e
newMismiEnv :: (Applicative m, MonadIO m, MonadCatch m) => Region -> Credentials -> m Env
newMismiEnv r c = do
e <- newEnv c
pure $ e & envRegion .~ r
catchAuthError :: AuthError -> IO Bool
catchAuthError (RetrievalError _) = pure True
catchAuthError (MissingFileError _) = pure True
catchAuthError _ = pure False
renderRegionError :: RegionError -> Text
renderRegionError e =
case e of
UnknownRegion r ->
"Unknown region: " <> r
MissingRegion ->
"Environment variable AWS_DEFAULT_REGION was not found"