module Amazonka.Send
  ( send,
    sendEither,
    paginate,
    paginateEither,
    await,
    awaitEither,
    sendUnsigned,
    sendUnsignedEither,
  )
where

import Amazonka.Core (AWSPager, AWSRequest, AWSResponse, Error)
import Amazonka.Env (Env, Env' (..))
import qualified Amazonka.HTTP as HTTP
import qualified Amazonka.Pager as Pager
import Amazonka.Prelude
import qualified Amazonka.Waiter as Waiter
import qualified Control.Exception as Exception
import Data.Conduit (ConduitM)
import qualified Data.Conduit as Conduit
import Data.Typeable (Typeable)
import qualified Network.HTTP.Client as Client

-- | Send a request, returning the associated response if successful.
--
-- See 'send'.
sendEither ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env ->
  a ->
  m (Either Error (AWSResponse a))
sendEither :: forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> m (Either Error (AWSResponse a))
sendEither Env
env =
  (Either Error (Response (AWSResponse a))
 -> Either Error (AWSResponse a))
-> m (Either Error (Response (AWSResponse a)))
-> m (Either Error (AWSResponse a))
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Response (AWSResponse a) -> AWSResponse a)
-> Either Error (Response (AWSResponse a))
-> Either Error (AWSResponse a)
forall b c a. (b -> c) -> Either a b -> Either a c
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Response (AWSResponse a) -> AWSResponse a
forall body. Response body -> body
Client.responseBody) (m (Either Error (Response (AWSResponse a)))
 -> m (Either Error (AWSResponse a)))
-> (a -> m (Either Error (Response (AWSResponse a))))
-> a
-> m (Either Error (AWSResponse a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> a -> m (Either Error (Response (AWSResponse a)))
forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a), Foldable withAuth) =>
Env' withAuth
-> a -> m (Either Error (ClientResponse (AWSResponse a)))
HTTP.retryRequest Env
env

-- | Send a request, returning the associated response if successful.
--
-- Errors are thrown in 'IO'.
--
-- See 'sendEither'.
send ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env ->
  a ->
  m (AWSResponse a)
send :: forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> m (AWSResponse a)
send Env
env =
  Env -> a -> m (Either Error (AWSResponse a))
forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> m (Either Error (AWSResponse a))
sendEither Env
env (a -> m (Either Error (AWSResponse a)))
-> (Either Error (AWSResponse a) -> m (AWSResponse a))
-> a
-> m (AWSResponse a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Either Error (AWSResponse a) -> m (AWSResponse a)
forall (m :: * -> *) a. MonadIO m => Either Error a -> m a
hoistEither

-- | Make a request without signing it. You will almost never need to
-- do this, but some authentication methods
-- (e.g. @sts:AssumeRoleWithWebIdentity@ and @sso:GetRoleCredentials@)
-- require you to exchange a token using an unsigned
-- request. Amazonka's support for these authentication methods calls
-- 'sendUnsigned', and we re-export these functions in case you need
-- to support similar authentication methods in your code.
--
-- See 'sendUnsigned'.
sendUnsignedEither ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env' withAuth ->
  a ->
  m (Either Error (AWSResponse a))
sendUnsignedEither :: forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env' withAuth -> a -> m (Either Error (AWSResponse a))
sendUnsignedEither Env' withAuth
env =
  (Either Error (Response (AWSResponse a))
 -> Either Error (AWSResponse a))
-> m (Either Error (Response (AWSResponse a)))
-> m (Either Error (AWSResponse a))
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Response (AWSResponse a) -> AWSResponse a)
-> Either Error (Response (AWSResponse a))
-> Either Error (AWSResponse a)
forall b c a. (b -> c) -> Either a b -> Either a c
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Response (AWSResponse a) -> AWSResponse a
forall body. Response body -> body
Client.responseBody) (m (Either Error (Response (AWSResponse a)))
 -> m (Either Error (AWSResponse a)))
-> (a -> m (Either Error (Response (AWSResponse a))))
-> a
-> m (Either Error (AWSResponse a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env' Proxy -> a -> m (Either Error (Response (AWSResponse a)))
forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a), Foldable withAuth) =>
Env' withAuth
-> a -> m (Either Error (ClientResponse (AWSResponse a)))
HTTP.retryRequest (Env' withAuth
env {auth = Proxy})

-- | Make an unsigned request, returning the associated response if successful.
--
-- Errors are thrown in 'IO'.
--
-- See 'sendUnsignedEither'.
sendUnsigned ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env' withAuth ->
  a ->
  m (AWSResponse a)
sendUnsigned :: forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env' withAuth -> a -> m (AWSResponse a)
sendUnsigned Env' withAuth
env =
  Env' withAuth -> a -> m (Either Error (AWSResponse a))
forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env' withAuth -> a -> m (Either Error (AWSResponse a))
sendUnsignedEither Env' withAuth
env (a -> m (Either Error (AWSResponse a)))
-> (Either Error (AWSResponse a) -> m (AWSResponse a))
-> a
-> m (AWSResponse a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Either Error (AWSResponse a) -> m (AWSResponse a)
forall (m :: * -> *) a. MonadIO m => Either Error a -> m a
hoistEither

-- | Repeatedly send a request, automatically setting markers and performing pagination.
--
-- Exits on the first encountered error.
--
-- See 'paginate'.
paginateEither ::
  ( MonadResource m,
    AWSPager a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env ->
  a ->
  ConduitM () (AWSResponse a) m (Either Error ())
paginateEither :: forall (m :: * -> *) a.
(MonadResource m, AWSPager a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> ConduitM () (AWSResponse a) m (Either Error ())
paginateEither Env
env = a -> ConduitT () (AWSResponse a) m (Either Error ())
go
  where
    go :: a -> ConduitT () (AWSResponse a) m (Either Error ())
go a
rq =
      m (Either Error (AWSResponse a))
-> ConduitT () (AWSResponse a) m (Either Error (AWSResponse a))
forall (m :: * -> *) a.
Monad m =>
m a -> ConduitT () (AWSResponse a) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Env -> a -> m (Either Error (AWSResponse a))
forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> m (Either Error (AWSResponse a))
sendEither Env
env a
rq) ConduitT () (AWSResponse a) m (Either Error (AWSResponse a))
-> (Either Error (AWSResponse a)
    -> ConduitT () (AWSResponse a) m (Either Error ()))
-> ConduitT () (AWSResponse a) m (Either Error ())
forall a b.
ConduitT () (AWSResponse a) m a
-> (a -> ConduitT () (AWSResponse a) m b)
-> ConduitT () (AWSResponse a) m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Left Error
err -> Either Error () -> ConduitT () (AWSResponse a) m (Either Error ())
forall a. a -> ConduitT () (AWSResponse a) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Error -> Either Error ()
forall a b. a -> Either a b
Left Error
err)
        Right AWSResponse a
rs -> do
          AWSResponse a -> ConduitT () (AWSResponse a) m ()
forall (m :: * -> *) o i. Monad m => o -> ConduitT i o m ()
Conduit.yield AWSResponse a
rs
          ConduitT () (AWSResponse a) m (Either Error ())
-> (a -> ConduitT () (AWSResponse a) m (Either Error ()))
-> Maybe a
-> ConduitT () (AWSResponse a) m (Either Error ())
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Either Error () -> ConduitT () (AWSResponse a) m (Either Error ())
forall a. a -> ConduitT () (AWSResponse a) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (() -> Either Error ()
forall a b. b -> Either a b
Right ())) a -> ConduitT () (AWSResponse a) m (Either Error ())
go (a -> AWSResponse a -> Maybe a
forall a. AWSPager a => a -> AWSResponse a -> Maybe a
Pager.page a
rq AWSResponse a
rs)

-- | Repeatedly send a request, automatically setting markers and performing pagination.
-- Exits on the first encountered error.
--
-- Errors are thrown in 'IO'.
--
-- See 'paginateEither'.
paginate ::
  ( MonadResource m,
    AWSPager a,
    Typeable a,
    Typeable (AWSResponse a)
  ) =>
  Env ->
  a ->
  ConduitM () (AWSResponse a) m ()
paginate :: forall (m :: * -> *) a.
(MonadResource m, AWSPager a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> ConduitM () (AWSResponse a) m ()
paginate Env
env =
  Env -> a -> ConduitT () (AWSResponse a) m (Either Error ())
forall (m :: * -> *) a.
(MonadResource m, AWSPager a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> ConduitM () (AWSResponse a) m (Either Error ())
paginateEither Env
env (a -> ConduitT () (AWSResponse a) m (Either Error ()))
-> (Either Error () -> ConduitT () (AWSResponse a) m ())
-> a
-> ConduitT () (AWSResponse a) m ()
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Either Error () -> ConduitT () (AWSResponse a) m ()
forall (m :: * -> *) a. MonadIO m => Either Error a -> m a
hoistEither

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- See 'await'.
awaitEither ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a
  ) =>
  Env ->
  Waiter.Wait a ->
  a ->
  m (Either Error Waiter.Accept)
awaitEither :: forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a) =>
Env -> Wait a -> a -> m (Either Error Accept)
awaitEither = Env -> Wait a -> a -> m (Either Error Accept)
forall (m :: * -> *) a (withAuth :: * -> *).
(MonadResource m, AWSRequest a, Typeable a, Foldable withAuth) =>
Env' withAuth -> Wait a -> a -> m (Either Error Accept)
HTTP.awaitRequest

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- Errors are thrown in 'IO'.
--
-- See 'awaitEither'.
await ::
  ( MonadResource m,
    AWSRequest a,
    Typeable a
  ) =>
  Env ->
  Waiter.Wait a ->
  a ->
  m Waiter.Accept
await :: forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a) =>
Env -> Wait a -> a -> m Accept
await Env
env Wait a
wait =
  Env -> Wait a -> a -> m (Either Error Accept)
forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a) =>
Env -> Wait a -> a -> m (Either Error Accept)
awaitEither Env
env Wait a
wait (a -> m (Either Error Accept))
-> (Either Error Accept -> m Accept) -> a -> m Accept
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Either Error Accept -> m Accept
forall (m :: * -> *) a. MonadIO m => Either Error a -> m a
hoistEither

hoistEither :: MonadIO m => Either Error a -> m a
hoistEither :: forall (m :: * -> *) a. MonadIO m => Either Error a -> m a
hoistEither = (Error -> m a) -> (a -> m a) -> Either Error 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) -> (Error -> IO a) -> Error -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Error -> IO a
forall e a. Exception e => e -> IO a
Exception.throwIO) a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure