{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Servant.HttpStreams.Internal where
import Prelude ()
import Prelude.Compat
import Control.DeepSeq
(NFData, force)
import Control.Exception
(IOException, SomeException (..), catch, evaluate, throwIO)
import Control.Monad
(unless)
import Control.Monad.Base
(MonadBase (..))
import Control.Monad.Codensity
(Codensity (..))
import Control.Monad.Error.Class
(MonadError (..))
import Control.Monad.IO.Class
(MonadIO (..))
import Control.Monad.Reader
(MonadReader, ReaderT, ask, runReaderT)
import Control.Monad.Trans.Class
(lift)
import Control.Monad.Trans.Except
(ExceptT, runExceptT)
import Data.Bifunctor
(bimap, first)
import Data.ByteString.Builder
(toLazyByteString)
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as BSL
import qualified Data.CaseInsensitive as CI
import Data.Foldable
(for_, toList)
import Data.Functor.Alt
(Alt (..))
import Data.Maybe
(maybeToList)
import Data.Proxy
(Proxy (..))
import Data.Sequence
(fromList)
import Data.String
(fromString)
import GHC.Generics
import Network.HTTP.Media
(renderHeader)
import Network.HTTP.Types
(Status (..), hContentType, http11, renderQuery, statusIsSuccessful)
import Servant.Client.Core
import qualified Network.Http.Client as Client
import qualified Network.Http.Types as Client
import qualified Servant.Types.SourceT as S
import qualified System.IO.Streams as Streams
data ClientEnv
= ClientEnv
{ ClientEnv -> BaseUrl
baseUrl :: BaseUrl
, ClientEnv -> Connection
connection :: Client.Connection
}
mkClientEnv :: BaseUrl -> Client.Connection -> ClientEnv
mkClientEnv :: BaseUrl -> Connection -> ClientEnv
mkClientEnv = BaseUrl -> Connection -> ClientEnv
ClientEnv
withClientEnvIO :: BaseUrl -> (ClientEnv -> IO r) -> IO r
withClientEnvIO :: BaseUrl -> (ClientEnv -> IO r) -> IO r
withClientEnvIO BaseUrl
burl ClientEnv -> IO r
k = IO Connection -> (Connection -> IO r) -> IO r
forall γ. IO Connection -> (Connection -> IO γ) -> IO γ
Client.withConnection IO Connection
open ((Connection -> IO r) -> IO r) -> (Connection -> IO r) -> IO r
forall a b. (a -> b) -> a -> b
$ \Connection
conn ->
ClientEnv -> IO r
k (BaseUrl -> Connection -> ClientEnv
mkClientEnv BaseUrl
burl Connection
conn)
where
open :: IO Connection
open = Hostname -> Port -> IO Connection
Client.openConnection (String -> Hostname
forall a. IsString a => String -> a
fromString (String -> Hostname) -> String -> Hostname
forall a b. (a -> b) -> a -> b
$ BaseUrl -> String
baseUrlHost BaseUrl
burl) (Int -> Port
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Port) -> Int -> Port
forall a b. (a -> b) -> a -> b
$ BaseUrl -> Int
baseUrlPort BaseUrl
burl)
client :: HasClient ClientM api => Proxy api -> Client ClientM api
client :: Proxy api -> Client ClientM api
client Proxy api
api = Proxy api
api Proxy api -> Proxy ClientM -> Client ClientM api
forall (m :: * -> *) api.
HasClient m api =>
Proxy api -> Proxy m -> Client m api
`clientIn` (Proxy ClientM
forall k (t :: k). Proxy t
Proxy :: Proxy ClientM)
hoistClient
:: HasClient ClientM api
=> Proxy api
-> (forall a. m a -> n a)
-> Client m api
-> Client n api
hoistClient :: Proxy api -> (forall a. m a -> n a) -> Client m api -> Client n api
hoistClient = Proxy ClientM
-> Proxy api
-> (forall a. m a -> n a)
-> Client m api
-> Client n api
forall (m :: * -> *) api (mon :: * -> *) (mon' :: * -> *).
HasClient m api =>
Proxy m
-> Proxy api
-> (forall x. mon x -> mon' x)
-> Client mon api
-> Client mon' api
hoistClientMonad (Proxy ClientM
forall k (t :: k). Proxy t
Proxy :: Proxy ClientM)
newtype ClientM a = ClientM
{ ClientM a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
unClientM :: ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a }
deriving ( a -> ClientM b -> ClientM a
(a -> b) -> ClientM a -> ClientM b
(forall a b. (a -> b) -> ClientM a -> ClientM b)
-> (forall a b. a -> ClientM b -> ClientM a) -> Functor ClientM
forall a b. a -> ClientM b -> ClientM a
forall a b. (a -> b) -> ClientM a -> ClientM b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> ClientM b -> ClientM a
$c<$ :: forall a b. a -> ClientM b -> ClientM a
fmap :: (a -> b) -> ClientM a -> ClientM b
$cfmap :: forall a b. (a -> b) -> ClientM a -> ClientM b
Functor, Functor ClientM
a -> ClientM a
Functor ClientM
-> (forall a. a -> ClientM a)
-> (forall a b. ClientM (a -> b) -> ClientM a -> ClientM b)
-> (forall a b c.
(a -> b -> c) -> ClientM a -> ClientM b -> ClientM c)
-> (forall a b. ClientM a -> ClientM b -> ClientM b)
-> (forall a b. ClientM a -> ClientM b -> ClientM a)
-> Applicative ClientM
ClientM a -> ClientM b -> ClientM b
ClientM a -> ClientM b -> ClientM a
ClientM (a -> b) -> ClientM a -> ClientM b
(a -> b -> c) -> ClientM a -> ClientM b -> ClientM c
forall a. a -> ClientM a
forall a b. ClientM a -> ClientM b -> ClientM a
forall a b. ClientM a -> ClientM b -> ClientM b
forall a b. ClientM (a -> b) -> ClientM a -> ClientM b
forall a b c. (a -> b -> c) -> ClientM a -> ClientM b -> ClientM c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: ClientM a -> ClientM b -> ClientM a
$c<* :: forall a b. ClientM a -> ClientM b -> ClientM a
*> :: ClientM a -> ClientM b -> ClientM b
$c*> :: forall a b. ClientM a -> ClientM b -> ClientM b
liftA2 :: (a -> b -> c) -> ClientM a -> ClientM b -> ClientM c
$cliftA2 :: forall a b c. (a -> b -> c) -> ClientM a -> ClientM b -> ClientM c
<*> :: ClientM (a -> b) -> ClientM a -> ClientM b
$c<*> :: forall a b. ClientM (a -> b) -> ClientM a -> ClientM b
pure :: a -> ClientM a
$cpure :: forall a. a -> ClientM a
$cp1Applicative :: Functor ClientM
Applicative, Applicative ClientM
a -> ClientM a
Applicative ClientM
-> (forall a b. ClientM a -> (a -> ClientM b) -> ClientM b)
-> (forall a b. ClientM a -> ClientM b -> ClientM b)
-> (forall a. a -> ClientM a)
-> Monad ClientM
ClientM a -> (a -> ClientM b) -> ClientM b
ClientM a -> ClientM b -> ClientM b
forall a. a -> ClientM a
forall a b. ClientM a -> ClientM b -> ClientM b
forall a b. ClientM a -> (a -> ClientM b) -> ClientM b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> ClientM a
$creturn :: forall a. a -> ClientM a
>> :: ClientM a -> ClientM b -> ClientM b
$c>> :: forall a b. ClientM a -> ClientM b -> ClientM b
>>= :: ClientM a -> (a -> ClientM b) -> ClientM b
$c>>= :: forall a b. ClientM a -> (a -> ClientM b) -> ClientM b
$cp1Monad :: Applicative ClientM
Monad, Monad ClientM
Monad ClientM -> (forall a. IO a -> ClientM a) -> MonadIO ClientM
IO a -> ClientM a
forall a. IO a -> ClientM a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: IO a -> ClientM a
$cliftIO :: forall a. IO a -> ClientM a
$cp1MonadIO :: Monad ClientM
MonadIO, (forall x. ClientM a -> Rep (ClientM a) x)
-> (forall x. Rep (ClientM a) x -> ClientM a)
-> Generic (ClientM a)
forall x. Rep (ClientM a) x -> ClientM a
forall x. ClientM a -> Rep (ClientM a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (ClientM a) x -> ClientM a
forall a x. ClientM a -> Rep (ClientM a) x
$cto :: forall a x. Rep (ClientM a) x -> ClientM a
$cfrom :: forall a x. ClientM a -> Rep (ClientM a) x
Generic
, MonadReader ClientEnv, MonadError ClientError)
instance MonadBase IO ClientM where
liftBase :: IO α -> ClientM α
liftBase = ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) α
-> ClientM α
forall a.
ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a
ClientM (ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) α
-> ClientM α)
-> (IO α
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) α)
-> IO α
-> ClientM α
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO α -> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) α
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
instance Alt ClientM where
ClientM a
a <!> :: ClientM a -> ClientM a -> ClientM a
<!> ClientM a
b = ClientM a
a ClientM a -> (ClientError -> ClientM a) -> ClientM a
forall e (m :: * -> *) a.
MonadError e m =>
m a -> (e -> m a) -> m a
`catchError` \ClientError
_ -> ClientM a
b
instance RunClient ClientM where
runRequestAcceptStatus :: Maybe [Status] -> Request -> ClientM Response
runRequestAcceptStatus = Maybe [Status] -> Request -> ClientM Response
performRequest
throwClientError :: ClientError -> ClientM a
throwClientError = ClientError -> ClientM a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError
instance RunStreamingClient ClientM where
withStreamingRequest :: Request -> (StreamingResponse -> IO a) -> ClientM a
withStreamingRequest = Request -> (StreamingResponse -> IO a) -> ClientM a
forall a. Request -> (StreamingResponse -> IO a) -> ClientM a
performWithStreamingRequest
runClientM :: NFData a => ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM :: ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM ClientM a
cm ClientEnv
env = ClientM a
-> ClientEnv
-> (Either ClientError a -> IO (Either ClientError a))
-> IO (Either ClientError a)
forall a b.
ClientM a -> ClientEnv -> (Either ClientError a -> IO b) -> IO b
withClientM ClientM a
cm ClientEnv
env (Either ClientError a -> IO (Either ClientError a)
forall a. a -> IO a
evaluate (Either ClientError a -> IO (Either ClientError a))
-> (Either ClientError a -> Either ClientError a)
-> Either ClientError a
-> IO (Either ClientError a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either ClientError a -> Either ClientError a
forall a. NFData a => a -> a
force)
withClientM :: ClientM a -> ClientEnv -> (Either ClientError a -> IO b) -> IO b
withClientM :: ClientM a -> ClientEnv -> (Either ClientError a -> IO b) -> IO b
withClientM ClientM a
cm ClientEnv
env Either ClientError a -> IO b
k =
let Codensity forall b. (Either ClientError a -> IO b) -> IO b
f = ExceptT ClientError (Codensity IO) a
-> Codensity IO (Either ClientError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT ClientError (Codensity IO) a
-> Codensity IO (Either ClientError a))
-> ExceptT ClientError (Codensity IO) a
-> Codensity IO (Either ClientError a)
forall a b. (a -> b) -> a -> b
$ (ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientEnv -> ExceptT ClientError (Codensity IO) a)
-> ClientEnv
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ExceptT ClientError (Codensity IO) a
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientEnv -> ExceptT ClientError (Codensity IO) a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ClientEnv
env (ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ExceptT ClientError (Codensity IO) a)
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ExceptT ClientError (Codensity IO) a
forall a b. (a -> b) -> a -> b
$ ClientM a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
forall a.
ClientM a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
unClientM ClientM a
cm
in (Either ClientError a -> IO b) -> IO b
forall b. (Either ClientError a -> IO b) -> IO b
f Either ClientError a -> IO b
k
performRequest :: Maybe [Status] -> Request -> ClientM Response
performRequest :: Maybe [Status] -> Request -> ClientM Response
performRequest Maybe [Status]
acceptStatus Request
req = do
ClientEnv BaseUrl
burl Connection
conn <- ClientM ClientEnv
forall r (m :: * -> *). MonadReader r m => m r
ask
let (Request
req', OutputStream Builder -> IO ()
body) = BaseUrl -> Request -> (Request, OutputStream Builder -> IO ())
requestToClientRequest BaseUrl
burl Request
req
Either ClientError Response
x <- ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response)
-> ClientM (Either ClientError Response)
forall a.
ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a
ClientM (ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response)
-> ClientM (Either ClientError Response))
-> ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response)
-> ClientM (Either ClientError Response)
forall a b. (a -> b) -> a -> b
$ ExceptT ClientError (Codensity IO) (Either ClientError Response)
-> ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (ExceptT ClientError (Codensity IO) (Either ClientError Response)
-> ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response))
-> ExceptT ClientError (Codensity IO) (Either ClientError Response)
-> ReaderT
ClientEnv
(ExceptT ClientError (Codensity IO))
(Either ClientError Response)
forall a b. (a -> b) -> a -> b
$ Codensity IO (Either ClientError Response)
-> ExceptT ClientError (Codensity IO) (Either ClientError Response)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Codensity IO (Either ClientError Response)
-> ExceptT
ClientError (Codensity IO) (Either ClientError Response))
-> Codensity IO (Either ClientError Response)
-> ExceptT ClientError (Codensity IO) (Either ClientError Response)
forall a b. (a -> b) -> a -> b
$ (forall b. (Either ClientError Response -> IO b) -> IO b)
-> Codensity IO (Either ClientError Response)
forall k (m :: k -> *) a.
(forall (b :: k). (a -> m b) -> m b) -> Codensity m a
Codensity ((forall b. (Either ClientError Response -> IO b) -> IO b)
-> Codensity IO (Either ClientError Response))
-> (forall b. (Either ClientError Response -> IO b) -> IO b)
-> Codensity IO (Either ClientError Response)
forall a b. (a -> b) -> a -> b
$ \Either ClientError Response -> IO b
k -> do
Connection -> Request -> (OutputStream Builder -> IO ()) -> IO ()
forall α.
Connection -> Request -> (OutputStream Builder -> IO α) -> IO α
Client.sendRequest Connection
conn Request
req' OutputStream Builder -> IO ()
body
Connection -> (Response -> InputStream Hostname -> IO b) -> IO b
forall β.
Connection -> (Response -> InputStream Hostname -> IO β) -> IO β
Client.receiveResponse Connection
conn ((Response -> InputStream Hostname -> IO b) -> IO b)
-> (Response -> InputStream Hostname -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \Response
res' InputStream Hostname
body' -> do
let status :: Status
status = Int -> Status
forall a. Enum a => Int -> a
toEnum (Int -> Status) -> Int -> Status
forall a b. (a -> b) -> a -> b
$ Response -> Int
Client.getStatusCode Response
res'
ByteString
lbs <- [Hostname] -> ByteString
BSL.fromChunks ([Hostname] -> ByteString) -> IO [Hostname] -> IO ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> InputStream Hostname -> IO [Hostname]
forall a. InputStream a -> IO [a]
Streams.toList InputStream Hostname
body'
let res'' :: Response
res'' = Response -> ByteString -> Response
forall body. Response -> body -> ResponseF body
clientResponseToResponse Response
res' ByteString
lbs
goodStatus :: Bool
goodStatus = case Maybe [Status]
acceptStatus of
Maybe [Status]
Nothing -> Status -> Bool
statusIsSuccessful Status
status
Just [Status]
good -> Status
status Status -> [Status] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Status]
good
if Bool
goodStatus
then Either ClientError Response -> IO b
k (Response -> Either ClientError Response
forall a b. b -> Either a b
Right Response
res'')
else Either ClientError Response -> IO b
k (ClientError -> Either ClientError Response
forall a b. a -> Either a b
Left (BaseUrl -> Request -> Response -> ClientError
mkFailureResponse BaseUrl
burl Request
req Response
res''))
(ClientError -> ClientM Response)
-> (Response -> ClientM Response)
-> Either ClientError Response
-> ClientM Response
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ClientError -> ClientM Response
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError Response -> ClientM Response
forall (f :: * -> *) a. Applicative f => a -> f a
pure Either ClientError Response
x
performWithStreamingRequest :: Request -> (StreamingResponse -> IO a) -> ClientM a
performWithStreamingRequest :: Request -> (StreamingResponse -> IO a) -> ClientM a
performWithStreamingRequest Request
req StreamingResponse -> IO a
k = do
ClientEnv BaseUrl
burl Connection
conn <- ClientM ClientEnv
forall r (m :: * -> *). MonadReader r m => m r
ask
let (Request
req', OutputStream Builder -> IO ()
body) = BaseUrl -> Request -> (Request, OutputStream Builder -> IO ())
requestToClientRequest BaseUrl
burl Request
req
ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a
forall a.
ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a
ClientM (ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a)
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
-> ClientM a
forall a b. (a -> b) -> a -> b
$ ExceptT ClientError (Codensity IO) a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (ExceptT ClientError (Codensity IO) a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a)
-> ExceptT ClientError (Codensity IO) a
-> ReaderT ClientEnv (ExceptT ClientError (Codensity IO)) a
forall a b. (a -> b) -> a -> b
$ Codensity IO a -> ExceptT ClientError (Codensity IO) a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Codensity IO a -> ExceptT ClientError (Codensity IO) a)
-> Codensity IO a -> ExceptT ClientError (Codensity IO) a
forall a b. (a -> b) -> a -> b
$ (forall b. (a -> IO b) -> IO b) -> Codensity IO a
forall k (m :: k -> *) a.
(forall (b :: k). (a -> m b) -> m b) -> Codensity m a
Codensity ((forall b. (a -> IO b) -> IO b) -> Codensity IO a)
-> (forall b. (a -> IO b) -> IO b) -> Codensity IO a
forall a b. (a -> b) -> a -> b
$ \a -> IO b
k1 -> do
Connection -> Request -> (OutputStream Builder -> IO ()) -> IO ()
forall α.
Connection -> Request -> (OutputStream Builder -> IO α) -> IO α
Client.sendRequest Connection
conn Request
req' OutputStream Builder -> IO ()
body
Connection -> (Response -> InputStream Hostname -> IO b) -> IO b
forall β.
Connection -> (Response -> InputStream Hostname -> IO β) -> IO β
Client.receiveResponseRaw Connection
conn ((Response -> InputStream Hostname -> IO b) -> IO b)
-> (Response -> InputStream Hostname -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \Response
res' InputStream Hostname
body' -> do
let status :: Status
status = Int -> Status
forall a. Enum a => Int -> a
toEnum (Int -> Status) -> Int -> Status
forall a b. (a -> b) -> a -> b
$ Response -> Int
Client.getStatusCode Response
res'
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Status -> Bool
statusIsSuccessful Status
status) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
ByteString
lbs <- [Hostname] -> ByteString
BSL.fromChunks ([Hostname] -> ByteString) -> IO [Hostname] -> IO ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> InputStream Hostname -> IO [Hostname]
forall a. InputStream a -> IO [a]
Streams.toList InputStream Hostname
body'
ClientError -> IO ()
forall e a. Exception e => e -> IO a
throwIO (ClientError -> IO ()) -> ClientError -> IO ()
forall a b. (a -> b) -> a -> b
$ BaseUrl -> Request -> Response -> ClientError
mkFailureResponse BaseUrl
burl Request
req (Response -> ByteString -> Response
forall body. Response -> body -> ResponseF body
clientResponseToResponse Response
res' ByteString
lbs)
a
x <- StreamingResponse -> IO a
k (Response -> SourceT IO Hostname -> StreamingResponse
forall body. Response -> body -> ResponseF body
clientResponseToResponse Response
res' (InputStream Hostname -> SourceT IO Hostname
forall b. InputStream b -> SourceT IO b
fromInputStream InputStream Hostname
body'))
a -> IO b
k1 a
x
mkFailureResponse :: BaseUrl -> Request -> ResponseF BSL.ByteString -> ClientError
mkFailureResponse :: BaseUrl -> Request -> Response -> ClientError
mkFailureResponse BaseUrl
burl Request
request =
RequestF () (BaseUrl, Hostname) -> Response -> ClientError
FailureResponse ((RequestBody -> ())
-> (Builder -> (BaseUrl, Hostname))
-> Request
-> RequestF () (BaseUrl, Hostname)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (() -> RequestBody -> ()
forall a b. a -> b -> a
const ()) Builder -> (BaseUrl, Hostname)
f Request
request)
where
f :: Builder -> (BaseUrl, Hostname)
f Builder
b = (BaseUrl
burl, ByteString -> Hostname
BSL.toStrict (ByteString -> Hostname) -> ByteString -> Hostname
forall a b. (a -> b) -> a -> b
$ Builder -> ByteString
toLazyByteString Builder
b)
clientResponseToResponse :: Client.Response -> body -> ResponseF body
clientResponseToResponse :: Response -> body -> ResponseF body
clientResponseToResponse Response
r body
body = Response :: forall a. Status -> Seq Header -> HttpVersion -> a -> ResponseF a
Response
{ responseStatusCode :: Status
responseStatusCode = Int -> Hostname -> Status
Status (Response -> Int
Client.getStatusCode Response
r) (Response -> Hostname
Client.getStatusMessage Response
r)
, responseBody :: body
responseBody = body
body
, responseHeaders :: Seq Header
responseHeaders = [Header] -> Seq Header
forall a. [a] -> Seq a
fromList ([Header] -> Seq Header) -> [Header] -> Seq Header
forall a b. (a -> b) -> a -> b
$ ((Hostname, Hostname) -> Header)
-> [(Hostname, Hostname)] -> [Header]
forall a b. (a -> b) -> [a] -> [b]
map ((Hostname -> CI Hostname) -> (Hostname, Hostname) -> Header
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Hostname -> CI Hostname
forall s. FoldCase s => s -> CI s
CI.mk) ([(Hostname, Hostname)] -> [Header])
-> [(Hostname, Hostname)] -> [Header]
forall a b. (a -> b) -> a -> b
$ Headers -> [(Hostname, Hostname)]
Client.retrieveHeaders (Headers -> [(Hostname, Hostname)])
-> Headers -> [(Hostname, Hostname)]
forall a b. (a -> b) -> a -> b
$ Response -> Headers
forall τ. HttpType τ => τ -> Headers
Client.getHeaders Response
r
, responseHttpVersion :: HttpVersion
responseHttpVersion = HttpVersion
http11
}
requestToClientRequest :: BaseUrl -> Request -> (Client.Request, Streams.OutputStream B.Builder -> IO ())
requestToClientRequest :: BaseUrl -> Request -> (Request, OutputStream Builder -> IO ())
requestToClientRequest BaseUrl
burl Request
r = (Request
request, OutputStream Builder -> IO ()
body)
where
request :: Request
request = RequestBuilder () -> Request
forall α. RequestBuilder α -> Request
Client.buildRequest1 (RequestBuilder () -> Request) -> RequestBuilder () -> Request
forall a b. (a -> b) -> a -> b
$ do
Method -> Hostname -> RequestBuilder ()
Client.http (Hostname -> Method
Client.Method (Hostname -> Method) -> Hostname -> Method
forall a b. (a -> b) -> a -> b
$ Request -> Hostname
forall body path. RequestF body path -> Hostname
requestMethod Request
r)
(Hostname -> RequestBuilder ()) -> Hostname -> RequestBuilder ()
forall a b. (a -> b) -> a -> b
$ String -> Hostname
forall a. IsString a => String -> a
fromString (BaseUrl -> String
baseUrlPath BaseUrl
burl)
Hostname -> Hostname -> Hostname
forall a. Semigroup a => a -> a -> a
<> ByteString -> Hostname
BSL.toStrict (Builder -> ByteString
toLazyByteString (Request -> Builder
forall body path. RequestF body path -> path
requestPath Request
r))
Hostname -> Hostname -> Hostname
forall a. Semigroup a => a -> a -> a
<> Bool -> Query -> Hostname
renderQuery Bool
True (Seq QueryItem -> Query
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Request -> Seq QueryItem
forall body path. RequestF body path -> Seq QueryItem
requestQueryString Request
r))
Hostname -> Port -> RequestBuilder ()
Client.setHostname (String -> Hostname
forall a. IsString a => String -> a
fromString (String -> Hostname) -> String -> Hostname
forall a b. (a -> b) -> a -> b
$ BaseUrl -> String
baseUrlHost BaseUrl
burl) (Int -> Port
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Port) -> Int -> Port
forall a b. (a -> b) -> a -> b
$ BaseUrl -> Int
baseUrlPort BaseUrl
burl)
[Header] -> (Header -> RequestBuilder ()) -> RequestBuilder ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (Maybe Header -> [Header]
forall a. Maybe a -> [a]
maybeToList Maybe Header
acceptHdr [Header] -> [Header] -> [Header]
forall a. [a] -> [a] -> [a]
++ Maybe Header -> [Header]
forall a. Maybe a -> [a]
maybeToList Maybe Header
contentTypeHdr [Header] -> [Header] -> [Header]
forall a. [a] -> [a] -> [a]
++ [Header]
headers) ((Header -> RequestBuilder ()) -> RequestBuilder ())
-> (Header -> RequestBuilder ()) -> RequestBuilder ()
forall a b. (a -> b) -> a -> b
$ \(CI Hostname
hn, Hostname
hv) ->
Hostname -> Hostname -> RequestBuilder ()
Client.setHeader (CI Hostname -> Hostname
forall s. CI s -> s
CI.original CI Hostname
hn) Hostname
hv
RequestBuilder ()
Client.setTransferEncoding
headers :: [Header]
headers = (Header -> Bool) -> [Header] -> [Header]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(CI Hostname
h, Hostname
_) -> CI Hostname
h CI Hostname -> CI Hostname -> Bool
forall a. Eq a => a -> a -> Bool
/= CI Hostname
"Accept" Bool -> Bool -> Bool
&& CI Hostname
h CI Hostname -> CI Hostname -> Bool
forall a. Eq a => a -> a -> Bool
/= CI Hostname
"Content-Type") ([Header] -> [Header]) -> [Header] -> [Header]
forall a b. (a -> b) -> a -> b
$
Seq Header -> [Header]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq Header -> [Header]) -> Seq Header -> [Header]
forall a b. (a -> b) -> a -> b
$ Request -> Seq Header
forall body path. RequestF body path -> Seq Header
requestHeaders Request
r
acceptHdr :: Maybe Header
acceptHdr
| [MediaType] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [MediaType]
hs = Maybe Header
forall a. Maybe a
Nothing
| Bool
otherwise = Header -> Maybe Header
forall a. a -> Maybe a
Just (CI Hostname
"Accept", [MediaType] -> Hostname
forall h. RenderHeader h => h -> Hostname
renderHeader [MediaType]
hs)
where
hs :: [MediaType]
hs = Seq MediaType -> [MediaType]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq MediaType -> [MediaType]) -> Seq MediaType -> [MediaType]
forall a b. (a -> b) -> a -> b
$ Request -> Seq MediaType
forall body path. RequestF body path -> Seq MediaType
requestAccept Request
r
convertBody :: RequestBody -> OutputStream Builder -> IO ()
convertBody RequestBody
bd OutputStream Builder
os = case RequestBody
bd of
RequestBodyLBS ByteString
body' ->
OutputStream Builder -> Maybe Builder -> IO ()
forall a. OutputStream a -> Maybe a -> IO ()
Streams.writeTo OutputStream Builder
os (Builder -> Maybe Builder
forall a. a -> Maybe a
Just (ByteString -> Builder
B.lazyByteString ByteString
body'))
RequestBodyBS Hostname
body' ->
OutputStream Builder -> Maybe Builder -> IO ()
forall a. OutputStream a -> Maybe a -> IO ()
Streams.writeTo OutputStream Builder
os (Builder -> Maybe Builder
forall a. a -> Maybe a
Just (Hostname -> Builder
B.byteString Hostname
body'))
RequestBodySource SourceIO ByteString
sourceIO ->
SourceIO ByteString -> OutputStream Builder -> IO ()
toOutputStream SourceIO ByteString
sourceIO OutputStream Builder
os
(OutputStream Builder -> IO ()
body, Maybe Header
contentTypeHdr) = case Request -> Maybe (RequestBody, MediaType)
forall body path. RequestF body path -> Maybe (body, MediaType)
requestBody Request
r of
Maybe (RequestBody, MediaType)
Nothing -> (OutputStream Builder -> IO ()
Client.emptyBody, Maybe Header
forall a. Maybe a
Nothing)
Just (RequestBody
body', MediaType
typ) -> (RequestBody -> OutputStream Builder -> IO ()
convertBody RequestBody
body', Header -> Maybe Header
forall a. a -> Maybe a
Just (CI Hostname
hContentType, MediaType -> Hostname
forall h. RenderHeader h => h -> Hostname
renderHeader MediaType
typ))
catchConnectionError :: IO a -> IO (Either ClientError a)
catchConnectionError :: IO a -> IO (Either ClientError a)
catchConnectionError IO a
action =
IO (Either ClientError a)
-> (IOException -> IO (Either ClientError a))
-> IO (Either ClientError a)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (a -> Either ClientError a
forall a b. b -> Either a b
Right (a -> Either ClientError a) -> IO a -> IO (Either ClientError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO a
action) ((IOException -> IO (Either ClientError a))
-> IO (Either ClientError a))
-> (IOException -> IO (Either ClientError a))
-> IO (Either ClientError a)
forall a b. (a -> b) -> a -> b
$ \IOException
e ->
Either ClientError a -> IO (Either ClientError a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ClientError a -> IO (Either ClientError a))
-> (SomeException -> Either ClientError a)
-> SomeException
-> IO (Either ClientError a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClientError -> Either ClientError a
forall a b. a -> Either a b
Left (ClientError -> Either ClientError a)
-> (SomeException -> ClientError)
-> SomeException
-> Either ClientError a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> ClientError
ConnectionError (SomeException -> IO (Either ClientError a))
-> SomeException -> IO (Either ClientError a)
forall a b. (a -> b) -> a -> b
$ IOException -> SomeException
forall e. Exception e => e -> SomeException
SomeException (IOException
e :: IOException)
fromInputStream :: Streams.InputStream b -> S.SourceT IO b
fromInputStream :: InputStream b -> SourceT IO b
fromInputStream InputStream b
is = (forall b. (StepT IO b -> IO b) -> IO b) -> SourceT IO b
forall (m :: * -> *) a.
(forall b. (StepT m a -> m b) -> m b) -> SourceT m a
S.SourceT ((forall b. (StepT IO b -> IO b) -> IO b) -> SourceT IO b)
-> (forall b. (StepT IO b -> IO b) -> IO b) -> SourceT IO b
forall a b. (a -> b) -> a -> b
$ \StepT IO b -> IO b
k -> StepT IO b -> IO b
k StepT IO b
loop where
loop :: StepT IO b
loop = IO (StepT IO b) -> StepT IO b
forall (m :: * -> *) a. m (StepT m a) -> StepT m a
S.Effect (IO (StepT IO b) -> StepT IO b) -> IO (StepT IO b) -> StepT IO b
forall a b. (a -> b) -> a -> b
$ StepT IO b -> (b -> StepT IO b) -> Maybe b -> StepT IO b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe StepT IO b
forall (m :: * -> *) a. StepT m a
S.Stop ((b -> StepT IO b -> StepT IO b) -> StepT IO b -> b -> StepT IO b
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> StepT IO b -> StepT IO b
forall (m :: * -> *) a. a -> StepT m a -> StepT m a
S.Yield StepT IO b
loop) (Maybe b -> StepT IO b) -> IO (Maybe b) -> IO (StepT IO b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> InputStream b -> IO (Maybe b)
forall a. InputStream a -> IO (Maybe a)
Streams.read InputStream b
is
toOutputStream :: S.SourceT IO BSL.ByteString -> Streams.OutputStream B.Builder -> IO ()
toOutputStream :: SourceIO ByteString -> OutputStream Builder -> IO ()
toOutputStream (S.SourceT forall b. (StepT IO ByteString -> IO b) -> IO b
k) OutputStream Builder
os = (StepT IO ByteString -> IO ()) -> IO ()
forall b. (StepT IO ByteString -> IO b) -> IO b
k StepT IO ByteString -> IO ()
loop where
loop :: StepT IO ByteString -> IO ()
loop StepT IO ByteString
S.Stop = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
loop (S.Error String
err) = String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
loop (S.Skip StepT IO ByteString
s) = StepT IO ByteString -> IO ()
loop StepT IO ByteString
s
loop (S.Effect IO (StepT IO ByteString)
mx) = IO (StepT IO ByteString)
mx IO (StepT IO ByteString) -> (StepT IO ByteString -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= StepT IO ByteString -> IO ()
loop
loop (S.Yield ByteString
x StepT IO ByteString
s) = Maybe Builder -> OutputStream Builder -> IO ()
forall a. Maybe a -> OutputStream a -> IO ()
Streams.write (Builder -> Maybe Builder
forall a. a -> Maybe a
Just (ByteString -> Builder
B.lazyByteString ByteString
x)) OutputStream Builder
os IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> StepT IO ByteString -> IO ()
loop StepT IO ByteString
s