{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Servant.Polysemy.Client
(
ServantClient
, runClient'
, runClient
, ServantClientStreaming
, runClientStreaming
, runServantClientUrl
, runServantClient
, runServantClientStreamingUrl
, runServantClientStreaming
, ClientError
) where
import Control.DeepSeq (NFData)
import Control.Monad ((>=>))
import Network.HTTP.Client (newManager)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Polysemy
import Polysemy.Cont
import Polysemy.Error
import Servant.Client.Streaming
( BaseUrl
, ClientError
, ClientM
, mkClientEnv
, parseBaseUrl
, runClientM
, withClientM
)
data ServantClient m a where
RunClient' :: NFData o => ClientM o -> ServantClient m (Either ClientError o)
makeSem ''ServantClient
runClient
:: (Members '[ServantClient, Error ClientError] r, NFData o)
=> ClientM o -> Sem r o
runClient :: ClientM o -> Sem r o
runClient = ClientM o -> Sem r (Either ClientError o)
forall (r :: [Effect]) o.
(MemberWithError ServantClient r, NFData o) =>
ClientM o -> Sem r (Either ClientError o)
runClient' (ClientM o -> Sem r (Either ClientError o))
-> (Either ClientError o -> Sem r o) -> ClientM o -> Sem r o
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Either ClientError o -> Sem r o
forall e (r :: [Effect]) a.
Member (Error e) r =>
Either e a -> Sem r a
fromEither
runServantClientUrl
:: Member (Embed IO) r
=> BaseUrl -> Sem (ServantClient ': r) a -> Sem r a
runServantClientUrl :: BaseUrl -> Sem (ServantClient : r) a -> Sem r a
runServantClientUrl BaseUrl
server Sem (ServantClient : r) a
m = do
Manager
manager <- IO Manager -> Sem r Manager
forall (m :: * -> *) (r :: [Effect]) a.
Member (Embed m) r =>
m a -> Sem r a
embed (IO Manager -> Sem r Manager) -> IO Manager -> Sem r Manager
forall a b. (a -> b) -> a -> b
$ ManagerSettings -> IO Manager
newManager ManagerSettings
tlsManagerSettings
let env :: ClientEnv
env = Manager -> BaseUrl -> ClientEnv
mkClientEnv Manager
manager BaseUrl
server
(forall x (rInitial :: [Effect]).
ServantClient (Sem rInitial) x -> Sem r x)
-> Sem (ServantClient : r) a -> Sem r a
forall (e :: Effect) (r :: [Effect]) a.
FirstOrder e "interpret" =>
(forall x (rInitial :: [Effect]). e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret (\case
RunClient' client ->
IO (Either ClientError o) -> Sem r (Either ClientError o)
forall (m :: * -> *) (r :: [Effect]) a.
Member (Embed m) r =>
m a -> Sem r a
embed (IO (Either ClientError o) -> Sem r (Either ClientError o))
-> IO (Either ClientError o) -> Sem r (Either ClientError o)
forall a b. (a -> b) -> a -> b
$ ClientM o -> ClientEnv -> IO (Either ClientError o)
forall a.
NFData a =>
ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM ClientM o
client ClientEnv
env
) Sem (ServantClient : r) a
m
runServantClient
:: Member (Embed IO) r
=> String -> Sem (ServantClient ': r) a -> Sem r a
runServantClient :: String -> Sem (ServantClient : r) a -> Sem r a
runServantClient String
server Sem (ServantClient : r) a
m = do
BaseUrl
server' <- IO BaseUrl -> Sem r BaseUrl
forall (m :: * -> *) (r :: [Effect]) a.
Member (Embed m) r =>
m a -> Sem r a
embed (IO BaseUrl -> Sem r BaseUrl) -> IO BaseUrl -> Sem r BaseUrl
forall a b. (a -> b) -> a -> b
$ String -> IO BaseUrl
forall (m :: * -> *). MonadThrow m => String -> m BaseUrl
parseBaseUrl String
server
BaseUrl -> Sem (ServantClient : r) a -> Sem r a
forall (r :: [Effect]) a.
Member (Embed IO) r =>
BaseUrl -> Sem (ServantClient : r) a -> Sem r a
runServantClientUrl BaseUrl
server' Sem (ServantClient : r) a
m
data ServantClientStreaming m a where
RunClientStreaming :: ClientM o -> ServantClientStreaming m o
makeSem ''ServantClientStreaming
runServantClientStreamingUrl
:: Members
'[ Cont ref
, Embed IO
, Error ClientError
] r
=> BaseUrl -> Sem (ServantClientStreaming ': r) a -> Sem r a
runServantClientStreamingUrl :: BaseUrl -> Sem (ServantClientStreaming : r) a -> Sem r a
runServantClientStreamingUrl BaseUrl
server Sem (ServantClientStreaming : r) a
m = do
Manager
manager <- IO Manager -> Sem r Manager
forall (m :: * -> *) (r :: [Effect]) a.
Member (Embed m) r =>
m a -> Sem r a
embed (IO Manager -> Sem r Manager) -> IO Manager -> Sem r Manager
forall a b. (a -> b) -> a -> b
$ ManagerSettings -> IO Manager
newManager ManagerSettings
tlsManagerSettings
let env :: ClientEnv
env = Manager -> BaseUrl -> ClientEnv
mkClientEnv Manager
manager BaseUrl
server
(forall x (rInitial :: [Effect]).
ServantClientStreaming (Sem rInitial) x -> Sem r x)
-> Sem (ServantClientStreaming : r) a -> Sem r a
forall (e :: Effect) (r :: [Effect]) a.
FirstOrder e "interpret" =>
(forall x (rInitial :: [Effect]). e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret (\case
RunClientStreaming client ->
(ref (Either ClientError x) -> Sem r x)
-> (Either ClientError x -> Sem r x) -> Sem r x
forall (ref :: * -> *) a b (r :: [Effect]).
Member (Cont ref) r =>
(ref a -> Sem r b) -> (a -> Sem r b) -> Sem r b
subst (\ref (Either ClientError x)
continue ->
((forall x. Sem r x -> IO x) -> IO () -> IO x) -> Sem r x
forall (r :: [Effect]) a.
Member (Embed IO) r =>
((forall x. Sem r x -> IO x) -> IO () -> IO a) -> Sem r a
withLowerToIO (((forall x. Sem r x -> IO x) -> IO () -> IO x) -> Sem r x)
-> ((forall x. Sem r x -> IO x) -> IO () -> IO x) -> Sem r x
forall a b. (a -> b) -> a -> b
$ \forall x. Sem r x -> IO x
unliftIO IO ()
_ ->
ClientM x -> ClientEnv -> (Either ClientError x -> IO x) -> IO x
forall a b.
ClientM a -> ClientEnv -> (Either ClientError a -> IO b) -> IO b
withClientM ClientM x
client ClientEnv
env (Sem r x -> IO x
forall x. Sem r x -> IO x
unliftIO (Sem r x -> IO x)
-> (Either ClientError x -> Sem r x)
-> Either ClientError x
-> IO x
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ref (Either ClientError x) -> Either ClientError x -> Sem r x
forall (ref :: * -> *) a b (r :: [Effect]).
Member (Cont ref) r =>
ref a -> a -> Sem r b
jump ref (Either ClientError x)
continue)
) Either ClientError x -> Sem r x
forall e (r :: [Effect]) a.
Member (Error e) r =>
Either e a -> Sem r a
fromEither
) Sem (ServantClientStreaming : r) a
m
runServantClientStreaming
:: Members
'[ Cont ref
, Embed IO
, Error ClientError
] r
=> String -> Sem (ServantClientStreaming ': r) a -> Sem r a
runServantClientStreaming :: String -> Sem (ServantClientStreaming : r) a -> Sem r a
runServantClientStreaming String
server Sem (ServantClientStreaming : r) a
m = do
BaseUrl
server' <- IO BaseUrl -> Sem r BaseUrl
forall (m :: * -> *) (r :: [Effect]) a.
Member (Embed m) r =>
m a -> Sem r a
embed (IO BaseUrl -> Sem r BaseUrl) -> IO BaseUrl -> Sem r BaseUrl
forall a b. (a -> b) -> a -> b
$ String -> IO BaseUrl
forall (m :: * -> *). MonadThrow m => String -> m BaseUrl
parseBaseUrl String
server
BaseUrl -> Sem (ServantClientStreaming : r) a -> Sem r a
forall (ref :: * -> *) (r :: [Effect]) a.
Members '[Cont ref, Embed IO, Error ClientError] r =>
BaseUrl -> Sem (ServantClientStreaming : r) a -> Sem r a
runServantClientStreamingUrl BaseUrl
server' Sem (ServantClientStreaming : r) a
m