{-# LANGUAGE TupleSections #-}
module Invest.Client(
ClientConfig(..)
, simpleClientConfig
, initGrpcClient
, (&), (.~), (^.)
, defMessage
, runGrpc
, (<#>), (#>>), (#>)
, runExceptT
, GrpcIO
, GrpcClient
, liftIO
) where
import Control.Exception (throwIO)
import Control.Lens ((&), (.~), (^.))
import Control.Monad.Except (ExceptT, MonadIO (liftIO), lift,
runExceptT, throwError)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BC (pack)
import Data.Maybe (maybeToList)
import Data.ProtoLens.Message (defMessage)
import Data.Text as T (pack)
import Invest.Client.Errors (SDKError (..))
import Invest.Client.Helpers
import Network.GRPC.Client (uncompressed)
import Network.GRPC.Client.Helpers (GrpcClient,
GrpcClientConfig (_grpcClientConfigCompression, _grpcClientConfigHeaders),
grpcClientConfigSimple,
setupGrpcClient)
import Network.HTTP2.Client (ClientIO, runClientIO)
data ClientConfig = ClientConfig { token :: String, appName :: Maybe String }
simpleClientConfig :: String -> ClientConfig
simpleClientConfig token = ClientConfig { token = token, appName = Nothing }
initGrpcClient :: ClientConfig -> GrpcIO GrpcClient
initGrpcClient cf = lift $ runClientIO (setupGrpcClient . prepareGrpcConfig $ cf) >>= \case
Right client -> pure client
Left err -> throwError . userError . show $ err
prepareGrpcConfig :: ClientConfig -> GrpcClientConfig
prepareGrpcConfig config = (grpcClientConfigSimple "invest-public-api.tinkoff.ru" 443 True) {
_grpcClientConfigHeaders = apiHeaders config,
_grpcClientConfigCompression = uncompressed
}
apiHeaders :: ClientConfig -> [(ByteString, ByteString)]
apiHeaders config =
maybeToList appNameH ++ [tokenH]
where
tokenH = (BC.pack "Authorization", BC.pack ("Bearer " ++ token config))
appNameH = (BC.pack "x-app-name",) . BC.pack <$> appName config