@@ -16,6 +16,8 @@ module Servant.Client.Core.Internal.HasClient where
16import Prelude ()
16import Prelude ()
17import Prelude.Compat
17import Prelude.Compat
19+import Control.Concurrent.MVar
20+ (modifyMVar, newMVar)
19import qualified Data.ByteString as BS
21import qualified Data.ByteString as BS
20import qualified Data.ByteString.Lazy as BL
22import qualified Data.ByteString.Lazy as BL
21import Data.Foldable
23import Data.Foldable
@@ -36,13 +38,14 @@ import qualified Network.HTTP.Types as H
36import Servant.API
38import Servant.API
37 ((:<|>) ((:<|>)), (:>), AuthProtect, BasicAuth, BasicAuthData,
39 ((:<|>) ((:<|>)), (:>), AuthProtect, BasicAuth, BasicAuthData,
38 BuildHeadersTo (..), Capture', CaptureAll, Description,
40 BuildHeadersTo (..), Capture', CaptureAll, Description,
39− EmptyAPI, FramingUnrender (..), FromSourceIO (..), Header',
41+ EmptyAPI, FramingRender (..), FramingUnrender (..),
42+ FromSourceIO (..), Header', Headers (..), HttpVersion,
40− Headers (..), HttpVersion, IsSecure, MimeRender (mimeRender),
43+ IsSecure, MimeRender (mimeRender),
41 MimeUnrender (mimeUnrender), NoContent (NoContent), QueryFlag,
44 MimeUnrender (mimeUnrender), NoContent (NoContent), QueryFlag,
42 QueryParam', QueryParams, Raw, ReflectMethod (..), RemoteHost,
45 QueryParam', QueryParams, Raw, ReflectMethod (..), RemoteHost,
43 ReqBody', SBoolI, Stream, StreamBody', Summary, ToHttpApiData,
46 ReqBody', SBoolI, Stream, StreamBody', Summary, ToHttpApiData,
44− Vault, Verb, WithNamedContext, contentType, getHeadersHList,
47+ ToSourceIO (..), Vault, Verb, WithNamedContext, contentType,
45− getResponse, toQueryParam, toUrlPiece)
48+ getHeadersHList, getResponse, toQueryParam, toUrlPiece)
46import Servant.API.ContentTypes
49import Servant.API.ContentTypes
47 (contentTypes)
50 (contentTypes)
48import Servant.API.Modifiers
51import Servant.API.Modifiers
@@ -538,7 +541,7 @@ instance (MimeRender ct a, HasClient m api)
538 hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
541 hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
541− ( HasClient m api
544+ ( HasClient m api, MimeRender ctype chunk, FramingRender framing, ToSourceIO chunk a
542 ) => HasClient m (StreamBody' mods framing ctype a :> api)
545 ) => HasClient m (StreamBody' mods framing ctype a :> api)
@@ -547,7 +550,39 @@ instance
547 hoistClientMonad pm _ f cl = \a ->
550 hoistClientMonad pm _ f cl = \a ->
548 hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
551 hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
550− clientWithRoute _pm Proxy _req _body = error "HasClient @StreamBody"
553+ clientWithRoute pm Proxy req body
554+ = clientWithRoute pm (Proxy :: Proxy api)
555+ $ setRequestBody (RequestBodyStreamChunked givesPopper) (contentType ctypeP) req
557+ ctypeP = Proxy :: Proxy ctype
558+ framingP = Proxy :: Proxy framing
560+ sourceIO = framingRender
562+ (mimeRender ctypeP :: chunk -> BL.ByteString)
566+ givesPopper :: (IO BS.ByteString -> IO ()) -> IO ()
567+ givesPopper needsPopper = S.unSourceT sourceIO $ \step0 -> do
568+ ref <- newMVar step0
570+ -- Note sure we need locking, but it's feels safer.
571+ let popper :: IO BS.ByteString
572+ popper = modifyMVar ref nextBs
576+ nextBs S.Stop = return (S.Stop, BS.empty)
577+ nextBs (S.Error err) = fail err
578+ nextBs (S.Skip s) = nextBs s
579+ nextBs (S.Effect ms) = ms >>= nextBs
580+ nextBs (S.Yield lbs s) = case BL.toChunks lbs of
582+ (x:xs) | BS.null x -> nextBs step'
583+ | otherwise -> return (step', x)
585+ step' = S.Yield (BL.fromChunks xs) s
552-- | Make the querying function append @path@ to the request path.
587-- | Make the querying function append @path@ to the request path.
553instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where
588instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where