{-# OPTIONS_GHC -fno-warn-orphans #-} module Servant.Streaming.Client.Internal where import Control.Monad import Control.Monad.Trans.Resource (ResourceT, getInternalState, runInternalState, runResourceT) import qualified Data.ByteString as BS import Data.IORef import Data.Proxy (Proxy (Proxy)) import qualified Network.HTTP.Media as M import Servant.API hiding (Stream) import Servant.Client.Core import Servant.Streaming import Streaming import qualified Streaming.Prelude as S instance (HasClient m subapi, RunClient m) => HasClient m (StreamBodyMonad contentTypes n :> subapi) where type Client m (StreamBodyMonad contentTypes n :> subapi) = (M.MediaType, Stream (Of BS.ByteString) (ResourceT IO) ()) -> Client m subapi clientWithRoute pm _ req (mtype, body) = clientWithRoute pm (Proxy :: Proxy subapi) req { requestBody = Just (RequestBodyStreamChunked body', mtype) } where body' :: (IO BS.ByteString -> IO ()) -> IO () body' write = runResourceT $ do ref <- liftIO $ newIORef body is <- getInternalState let popper :: IO BS.ByteString popper = do rsrc <- readIORef ref mres <- runInternalState (S.uncons rsrc) is case mres of Nothing -> return BS.empty Just (bs, str) | BS.null bs -> writeIORef ref str >> popper | otherwise -> writeIORef ref str >> return bs liftIO $ write popper hoistClientMonad pm _ f cl = \a -> hoistClientMonad pm (Proxy :: Proxy subapi) f (cl a) instance (RunClient m ) => HasClient m (StreamResponse verb status contentTypes) where type Client m (StreamResponse verb status contentTypes) = m (Stream (Of BS.ByteString) (ResourceT IO) ()) clientWithRoute _ _ req = do respStream <- runStreamingResponse <$> streamingRequest req let stream' = respStream responseBody return $ toStream stream' where toStream :: IO BS.ByteString -> Stream (Of BS.ByteString) (ResourceT IO) () toStream read' = do bs <- liftIO read' liftIO $ print bs unless (BS.null bs) $ do S.yield bs toStream read' hoistClientMonad _m _ f cl = f cl