{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} -- Module : Network.AWS.Response -- Copyright : (c) 2013-2014 Brendan Hay -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or -- you can obtain it at http://mozilla.org/MPL/2.0/. -- Maintainer : Brendan Hay -- Stability : experimental -- Portability : non-portable (GHC extensions) module Network.AWS.Response ( -- * Responses nullResponse , headerResponse , xmlResponse , xmlHeaderResponse , jsonResponse , jsonHeaderResponse , bodyResponse ) where import Control.Applicative import Control.Monad import Control.Monad.IO.Class import Control.Monad.Trans.Resource import Data.Aeson import Data.Bifunctor import qualified Data.ByteString.Lazy as LBS import Data.Conduit import qualified Data.Conduit.Binary as Conduit import Data.Monoid import Network.AWS.Data (LazyByteString, FromXML(..), decodeXML, build) import Network.AWS.Types import Network.HTTP.Client hiding (Request, Response) import Network.HTTP.Types import Text.XML (Node) nullResponse :: (MonadResource m, AWSService (Sv a)) => Rs a -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) nullResponse rs _ = receive $ \_ _ bdy -> liftResourceT (bdy $$+- return (Right rs)) {-# INLINE nullResponse #-} headerResponse :: (MonadResource m, AWSService (Sv a)) => (ResponseHeaders -> Either String (Rs a)) -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) headerResponse f = deserialise (const (Right ())) (const . f) {-# INLINE headerResponse #-} xmlResponse :: (MonadResource m, AWSService (Sv a), FromXML (Rs a)) => Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) xmlResponse = deserialise (decodeXML >=> parseXML) (const Right) {-# INLINE xmlResponse #-} xmlHeaderResponse :: (MonadResource m, AWSService (Sv a)) => (ResponseHeaders -> [Node] -> Either String (Rs a)) -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) xmlHeaderResponse = deserialise decodeXML {-# INLINE xmlHeaderResponse #-} jsonResponse :: (MonadResource m, AWSService (Sv a), FromJSON (Rs a)) => Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) jsonResponse = deserialise eitherDecode' (const Right) {-# INLINE jsonResponse #-} jsonHeaderResponse :: (MonadResource m, AWSService (Sv a)) => (ResponseHeaders -> Object -> Either String (Rs a)) -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) jsonHeaderResponse = deserialise eitherDecode' {-# INLINE jsonHeaderResponse #-} bodyResponse :: (MonadResource m, AWSService (Sv a)) => (ResponseHeaders -> ResponseBody -> Either String (Rs a)) -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) bodyResponse f _ = receive $ \a hs bdy -> return (SerializerError a `first` f hs bdy) {-# INLINE bodyResponse #-} deserialise :: (AWSService (Sv a), MonadResource m) => (LazyByteString -> Either String b) -> (ResponseHeaders -> b -> Either String (Rs a)) -> Logger -> Request a -> Either HttpException ClientResponse -> m (Response' a) deserialise g f l = receive $ \a hs bdy -> do lbs <- sinkLbs bdy liftIO $ l Trace ("[Client Response Body]\n" <> build lbs) return $! case g lbs of Left e -> Left (SerializerError a e) Right o -> case f hs o of Left e -> Left (SerializerError a e) Right x -> Right x {-# INLINE deserialise #-} receive :: forall m a. (MonadResource m, AWSService (Sv a)) => (Abbrev -> ResponseHeaders -> ResponseBody -> m (Response a)) -> Request a -> Either HttpException ClientResponse -> m (Response' a) receive f = const (either (return . Left . HttpError) success) where success rs = do let s = responseStatus rs bdy = responseBody rs hs = responseHeaders rs case _svcHandle svc s of Just g -> Left . g <$> sinkLbs bdy Nothing -> do x <- f (_svcAbbrev svc) hs bdy case x of Left e -> return (Left e) Right y -> return $! Right (s, y) svc = service :: Service (Sv a) {-# INLINE receive #-} sinkLbs :: MonadResource m => ResponseBody -> m LBS.ByteString sinkLbs bdy = liftResourceT (bdy $$+- Conduit.sinkLbs) {-# INLINE sinkLbs #-}